I am trying to recreate an encryption function that we have in our old PHP application into a new Node JS application, using Node's mycrypt
module.
My goal is the make sure that given the same original string and salt, the PHP script below produces the same encrypted value as the Node script.
PHP
<?php
$string = 'This is my password';
$salt = 'sodiumChloride12';
$encrypted = base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$salt,
$string,
MCRYPT_MODE_ECB,
mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND)
)
);
echo "Encrypted: $encrypted\n";
It produces:
Encrypted: iOKEAxaE4vIeWXBem01gHr2wdof7ZO2dld3BuR9l3Nw=
JavaScript
var mcrypt = require('mcrypt');
var MCrypt = mcrypt.MCrypt;
// Set algorithm and mode
var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');
// Set up salt and IV
var salt = 'sodiumChloride12';
var iv = rijndaelEcb.generateIv();
rijndaelEcb.open(salt, iv);
/** ENCRYPTION **/
var cipher = rijndaelEcb.encrypt('This is my password');
var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');
console.log('Encrypted: ' + cipherConcat);
/** DECRYPTION **/
// Convert back from base64
var ivAndCipherText = new Buffer(cipherConcat, 'base64');
// Undo concat of IV
var ivSize = rijndaelEcb.getIvSize();
iv = new Buffer(ivSize);
var cipherText = new Buffer(ivAndCipherText.length - ivSize);
ivAndCipherText.copy(iv, 0, 0, ivSize);
ivAndCipherText.copy(cipherText, 0, ivSize);
var plaintext = rijndaelEcb.decrypt(cipherText).toString();
console.log('Decrypted: ' + plaintext);
The Node version produces:
Encrypted: 834aJoVRxla/fGNACUAVFYjihAMWhOLyHllwXptNYB69sHaH+2TtnZXdwbkfZdzc
Decrypted: This is my password
Based on the fact that it decrypted the original phrase, I know the calls are working as expected, but the encrypted output is not the same as in the PHP script. Decryption logic was from this answer, but I'm more concerned with making the encryption work the same way.
Am I doing something different with the IV in Node than in PHP?
I looked at this question, but it uses the crypto
module instead of the mcrypt
module I am using.
Am I doing something different with the IV in Node than in PHP?
Hmm. What does the code say?
MCRYPT_MODE_ECB,
var rijndaelEcb = new MCrypt('rijndael-128', 'ecb');
You're using ECB mode, which doesn't use an IV. You're actually wasting CPU cycles generating one. Even if you were using CBC mode, MCRYPT_RAND
is a bad constant to use here.
var cipherConcat = Buffer.concat([iv, cipher]).toString('base64');
You're concatenating an unused IV to your ciphertext, and complaining about an invalid result? The PHP code just returns cipher
(in Node.js equivalent terms), not a concatenation of iv
and cipher
.
More importantly, there are some serious cryptography flaws here that need to be addressed, starting with ECB mode as mentioned above:
Recommended steps: