1

I need to be able to create an encryption in NodeJS that is the same with PHP openssl_encrypt. For urgent reasons as a workaround, we created a PHP API and our Node server uses that just to do the encryption. We cannot alter the encryption in PHP as it is a legacy system.

The key used is a 15 char string. The iv used is a 16 char string.

PHP Encrypt API

$string = $_GET["string"];
  $key = $_GET["key"];
  $iv = $_GET["iv"];

  $encrypt_method = 'AES-256-CBC';

  $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
  $output = base64_encode($output);

  echo $output;

PHP Decrypt API

$string = $_GET["string"];
  $key = $_GET["key"];
  $iv = $_GET["iv"];

  $encrypt_method = 'AES-256-CBC';

  $string = base64_decode($string);
  $output = openssl_decrypt($string, $encrypt_method, $key, 0, $iv);
  echo $output;

NodeJS Crypto Encrypt

static aesEncrypt = ({ toEncrypt }) => {
    const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, aesIv);
    let encrypted = cipher.update(toEncrypt, 'utf8', 'base64');
    return encrypted + cipher.final('base64');
};

NodeJS Crypto Decrypt

static aesDecrypt = ({ toDecrypt }) => {
    const decipher = crypto.createDecipheriv('aes-256-cbc', aesKey, aesIv);
    let decrypted = decipher.update(toDecrypt, 'base64', 'utf8');
    return decrypted + decipher.final('utf8');
};

I've used crypto and crypto-js but I can't replicate the results. I've found examples in stackoverflow but their usage of php encryption is different and thus gave different results.

  • https://stackoverflow.com/a/35076266/2310830 – RiggsFolly Oct 30 '22 at 16:43
  • The PHP code Base64 encodes / decodes unnecessarily twice. Maybe this is the pitfall why your NodeJS code fails. Post your NodeJS code. – Topaco Oct 30 '22 at 17:06
  • As already suspected: Add an additional Base64 encoding of the ciphertext to the encryption and an additional Base64 decoding of the ciphertext to the decryption. – Topaco Oct 30 '22 at 17:58
  • @Topaco, I've already tried ` return encrypted.toString('base64')` but it doesn't work. It produces an even shorter output. – Alvir Marquez Oct 31 '22 at 03:41
  • `encrypted.toString('base64')` doesn't change anything since encrypted is already a Base64 encoded string. S. my answer for a possible solution. – Topaco Oct 31 '22 at 08:32

1 Answers1

0

The PHP code Base64 encodes/decodes twice. This is unnecessary and only increases the amount of data to be encrypted/decrypted. Actually the PHP code should be fixed. However, since this is apparently a legacy code that may not be changed, the NodeJS code has to be modified.

Add an additional Base64 encoding of the ciphertext to the encryption and an additional Base64 decoding of the ciphertext to the decryption.

For a 2nd Base64 encoding encrypted has to be utf8 (or latin1) encoded into a buffer, which is then finally Base64 encoded into a string (and vice versa for Base64 decoding):

const aesEncrypt = (toEncrypt) => {
    const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, aesIv);
    let encrypted = cipher.update(toEncrypt, 'utf8', 'base64'); // 1st Base64 encoding
    encrypted += cipher.final('base64'); 
    return Buffer.from(encrypted, 'utf8').toString('base64'); // 2nd Base64 encoding
};

const aesDecrypt = (toDecrypt) => {
    toDecrypt = Buffer.from(toDecrypt, 'base64').toString('utf8'); // 1st Base64 decoding
    const decipher = crypto.createDecipheriv('aes-256-cbc', aesKey, aesIv);
    let decrypted = decipher.update(toDecrypt, 'base64', 'utf8'); // 2nd Base64 decoding
    return decrypted + decipher.final('utf8'); 
};
Topaco
  • 40,594
  • 4
  • 35
  • 62