Home > Software engineering >  PHP encrypt and decrypt in node JS
PHP encrypt and decrypt in node JS

Time:10-02

I have a encryption in PHP and a decryption in node JS. I know there are many topics about this. But all of them state that it doesn't work. In my case it does. Well sort of.

PHP

define('CRYPT_KEY', 'bwAZA48aaYd34PGhBWSutIIFaCu4oAe/Ps24/Rx bw0=');

class Encryption {
  public function encrypt($data) {
    $output = false;
    $methode = "AES-256-CBC";
    $key = base64_decode(CRYPT_KEY);

    $ivSize  = openssl_cipher_iv_length($methode);
    $ivData  = openssl_random_pseudo_bytes($ivSize);
    $encData = openssl_encrypt($data, $methode, $key, OPENSSL_RAW_DATA, $ivData);
    $output = base64_encode($ivData . $encData);

    return $output;
  }

  public function decrypt($data) {
    $output = false;
    $methode = "AES-256-CBC";
    $key = base64_decode(CRYPT_KEY);

    $ivSize  = openssl_cipher_iv_length($methode);
    $data = base64_decode($data);
    $ivData   = substr($data, 0, $ivSize);
    $encData = substr($data, $ivSize);
    $output = openssl_decrypt($encData, $methode, $key, OPENSSL_RAW_DATA, $ivData);

    return $output;
  }
}

echo $encryption->encrypt('Hello world'); 
// output: 8ZtGcgDeSCN8f jrZ/W2tWL40DIncjmCwanFiNrEhyE=

node JS

const key = Buffer.from('bwAZA48aaYd34PGhBWSutIIFaCu4oAe/Ps24/Rx bw0=', 'base64');
const iv = Buffer.from(crypto.randomBytes(16), 'base64');


function decrypt(data) {
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  const decripted = decipher.update(data, 'base64', 'utf8')   decipher.final('utf8');
  
  return decripted;
}

console.log('Output: ', decrypt('8ZtGcgDeSCN8f jrZ/W2tWL40DIncjmCwanFiNrEhyE='));

the first part of the output is scrambled

result: ▬�2���◄p��r♣�'Hello world

Does someone know why this happens. Im I doing something wrong?

CodePudding user response:

The reason for the problem is that in the PHP code IV and actual cipher text are concatenated, but in the NodeJS code the corresponding separation is missing. Instead, a new, random IV is used incorrectly.
However, for decryption to work, it must use the same IV as encryption. The IV must therefore be determined from the concatenated data.

The separation of IV and ciphertext can be done as follows:

const data = Buffer.from('tIF2bpl7Ro8lZbslAgBqJNqwIqn4pNWZrGkUaWcJQzo=', 'base64');
const iv = data.subarray(0, 16);
const ciphertext = data.subarray(16);

Since the ciphertext is now passed to decrypt() as buffer and not Base64 encoded, the decryption in decrypt() has to be changed accordingly:

const decripted = decipher.update(data, '', 'utf8')   decipher.final('utf8');

Please note that the posted NodeJS example does not work. It returns an EVP_DecryptFinal_ex:bad decrypt error, indicating that key and ciphertext are not related.

  • Related