Playing 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 another result from php one ...

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

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

      

Also, another result from php. Any ideas how to do this behave exactly the same as the php version?

+3


source to share


3 answers


Playing two rather poorly designed libraries against each other can be fun. Instead of doing all the work, I will help you along with ideas as requested:

  • Instead of removing key bytes, PHP expands them using the zero's padding of the next available key size - this would be 192 bits, or 24 bytes in your situation; for this you need to specify aes-192-ecb

    as an algorithm (you need to keep using MCRYPT_RIJNDAEL_128

    but replace that 128 in PHP is the block size, not the key size)
  • padding is incorrect, PHP shims 0..15 null bytes instead of 1..16 bytes
  • you cannot use the 2nd argument createCipher

    , because the second argument is the password; node.js does key derivation if you use it, so you need to use three arguments createCipher

    instead and supply any 16 byte IV

The IV code in PHP imposes an unnecessary random number generator, IV is not used.




Code to fill

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 can use your own fill method if len % 16 == 0

.

+3


source


Here is my code for solving the problem of migrating from PHP to NodeJS. I have a strong 32 byte key, so I have to use aes-256-ecb

.

PHP Code I want to 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

      

The NodeJS mcrypt package also 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

      

+1


source


I tried another option but it didn't work, but it worked for me.

function encrypt(text) {
  text = '' + text;
  var crypto = require('crypto');
  var len = text.length;
  var padSize = 16 - (((len + 16 - 1) % 16) + 1);
  var data = String.fromCharCode(padSize);
  var text = text + data.repeat(padSize);

  var cipher = crypto.createCipheriv('aes-128-ecb','secretKey', '');
  cipher.setAutoPadding(false);
  var encrypted = cipher.update(text, 'utf8', 'base64');
  encrypted += cipher.final('base64');
  return encrypted;
}

      

Similer in PHP

function aes128Encrypt($str,$key){
$block = mcrypt_get_block_size('rijndael_128', 'ecb');
$pad = $block - (strlen($str) % $block);
$str .= str_repeat(chr($pad), $pad);
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $str, MCRYPT_MODE_ECB));
}

      

0


source







All Articles