Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 490
Pasha Bitz Avatar asked Dec 31 '14 00:12

Pasha Bitz


2 Answers

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.

like image 152
Maarten Bodewes Avatar answered Sep 18 '22 22:09

Maarten Bodewes


Here is my code to solve problem with migration from PHP to NodeJS. I have strict 32 bytes key so I have to use aes-256-ecb.

PHP code I want rewrite:

$text = "Some super mega text I want to encode";
$skey = "rcbTw667C7zxghZ5U3gwhQlp22t8c5Rq";

function encode($text,$skey) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $skey, $text, MCRYPT_MODE_ECB, $iv);
    return base64_encode($crypttext);
}

echo encode($text,$skey);

Output:

dU1eOy+YwkYvm/KCTB8aqR1UsisyrHrvBu+E/H3G/s0aagMDKlNFekGXNQyFMFJD

NodeJS:

var crypto = require('crypto');

var text = "Some super mega text I want encode";
var skey = "rcbTw667C7zxghZ5U3gwhQlp22t8c5Rq";

function encode(text, skey) {
    var len = text.length;
    var padSize = 16 - ((len + 16 - 1) % 16 + 1);
    for (var i = 0; i < padSize; i++) { 
        text += '\0';
    }
    var cipher = crypto.createCipheriv('aes-256-ecb', skey, '');
    cipher.setAutoPadding(false);
    var encrypted = cipher.update(text, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
}

console.log(encode(text, skey));

Output:

dU1eOy+YwkYvm/KCTB8aqR1UsisyrHrvBu+E/H3G/s0aagMDKlNFekGXNQyFMFJD

Also NodeJS mcrypt package works:

npm install mcrypt

Code:

var text = "Some super mega text I want encode";
var skey = "rcbTw667C7zxghZ5U3gwhQlp22t8c5Rq";

function encode(text, skey) {
    var MCrypt = require('mcrypt').MCrypt;
    var rijEcb = new MCrypt('rijndael-128', 'ecb');
    rijEcb.open(skey);
    var ciphertext = rijEcb.encrypt(text);
    return ciphertext.toString('base64');
}

console.log(encode(text, skey));

Output:

dU1eOy+YwkYvm/KCTB8aqR1UsisyrHrvBu+E/H3G/s0aagMDKlNFekGXNQyFMFJD
like image 26
vlapo21 Avatar answered Sep 18 '22 22:09

vlapo21