0

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.

Community
  • 1
  • 1
The Unknown Dev
  • 3,039
  • 4
  • 27
  • 39

1 Answers1

3

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:

  1. Do not encrypt passwords, use a password hashing algorithm. There's a huge difference.
  2. If you're going to encrypt, use authenticated encryption.
  3. Don't use mcrypt.
  4. Don't deploy home-grown crypto protocols into production or encourage other developers to do the same.

Recommended steps:

  1. Decrypt your data with PHP, then store passwords properly.
  2. If you need encryption for any other purpose, use a high-level cryptography library, like libsodium.
Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
  • Thanks, I don't know much about cryptography and the PHP code was written years ago by someone else, so it's unfortunately not my call to change. As far as the `iv` concatenation in the Node version, I saw it on an example on the module's github page, so I figured that was correct, but removing it all together in the Node version worked out, and makes decryption a lot cleaner. – The Unknown Dev May 18 '16 at 15:30
  • I very strongly recommend talking to whomever makes the call and ask them to consider changing the way the encryption is done to make it secure. (If they don't know how, I do consult.) – Scott Arciszewski May 18 '16 at 15:41