DataConnect
DataConnect

Reputation: 129

PHP encrypt and decrypt in node JS

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?

Upvotes: 1

Views: 293

Answers (1)

Topaco
Topaco

Reputation: 49141

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.

Upvotes: 2

Related Questions