Search code examples
javascriptphpnode.jsaesmcrypt

Recreating MCRYPT_RIJNDAEL_128 in node.js


Trying to recreate the following php encryption code in node.js:

$size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($size, MCRYPT_RAND);
$msg = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, 'MY_KEY_LONG_STRING', 'PLAINTEXT', MCRYPT_MODE_ECB, $iv));

Tried this:

var text = 'PLAINTEXT';
var len = text.length;
for (var i = 0; i < 16 - len % 16; i++) {  // pad to multiple of block size 
    text += '\0';
}
var key = 'MY_KEY_LONG_STRING';
key = key.substr(0, 16); // trim to expected key size for aes128

var cipher = crypto.createCipher('aes-128-ecb', key);
cipher.setAutoPadding(false); // did our own padding, to match mcrypt_encrypt
var encrypted = cipher.update(text, 'utf8', 'base64');
encrypted += cipher.final('base64');

Getting different result from the php one...

Also tried creating cipher with IV (which shouldn't even be used in aes-128-ecb):

var cipher = crypto.createCipheriv('aes-128-ecb', key, '');

Also, different result from php. Any ideas how to make this behave exactly like the php version?


Solution

  • Playing two rather ill constructed libraries against each other can be fun. Rather than doing all the work, I'll help you along with ideas as requested:

    • rather than removing key bytes, PHP expands them using zero padding to the next available key size - that would be 192 bits or 24 bytes in your situation; to do this you need to specify aes-192-ecb as algorithm (you need to keep using MCRYPT_RIJNDAEL_128 but substitute, that 128 in PHP is the block size not the key size)
    • the padding is not correct, PHP pads 0..15 zero bytes instead of 1..16 bytes
    • you cannot use the 2 argument createCipher as the second argument is the password; node.js performs key derivation if you use that one, so you need to use the three argument createCipher instead and supply any 16 byte IV

    The IV code in PHP only taxes the random number generator needlessly, the IV is not used.


    Code to do the padding

    var padSize = 16 - ((len + 16 - 1) % 16 + 1);
    for (var i = 0; i < padSize; i++) {  // pad 0 .. 15 until to multiple of block size 
        text += '\0';
    }
    

    Or you could use your own padding method (in the question) unless len % 16 == 0.