3

I'm trying to port this working php code to Node.js but I get Error: Invalid IV length 32

Here is the PHP code:

//--- PHP example code (works): ---

$aes_iv = 'MjY2YjljMmM0MjVjNzVlMGMyZGI2NjAwN2U5ZGMzZDQ%3D';

$payload = base64_decode($payload);
$aes_iv = base64_decode($aes_iv);

// secret key. 64 character hex string:
$shared_key = '14370ced836 ...'; 
// convert from hex to binary string:
$shared_key = pack('H*', $shared_key); 

// AES decrypt payload
$payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $shared_key, $payload, MCRYPT_MODE_CBC, $aes_iv);


// AES adds null characters to the end of short strings, 
// so we should strip them out
$payload = rtrim($tp_payload, "\0"); 

Here is the Node.js code that doesn't work. See "Error: Invalid IV length 32"

//--- Node.js equivalent ??? ---

var aes_iv = 'MjY2YjljMmM0MjVjNzVlMGMyZGI2NjAwN2U5ZGMzZDQ%3D';

var payload_s = new Buffer(payload, 'base64').toString();
var aes_iv_s = new Buffer(aes_iv, 'base64').toString();

// secret key. 64 character hex string:
var shared_key = '14370ced836 ...'; 
// convert from hex to binary string:
var shared_key_b = new Buffer(shared_key, 'hex').toString('binary');

// Error: Invalid IV length 32
var decipher = crypto.createDecipheriv('aes-256-cbc', shared_key_b, aes_iv_s);
var decoded  = decipher.update(payload_s);

decoded += decipher.final();
console.log(decoded);
Banditvibe
  • 337
  • 3
  • 14

3 Answers3

3

MCRYPT_RIJNDAEL_256 refers to the rijndael encryption algorithm with a non-standard block size of 256 bits, rather than a key size of 256 bits. PHP uses libmcrypt for its encryption, while Node.js uses openssl, and while libmcrypt implements AES (block size of 128 bits), it also implements rijndael with configurable block size.

AES is specifically defined with a block size of 128 bits, and that is the only version of rijndael openssl supports. As such, I wrote a minimal libmcrypt binding for node called node-rijndael, which should serve your purposes. See also my answer to a similar question here.

var Rijndael = require('node-rijndael');

// shared_key
var key = '14370ced836...';

// aes_iv
var iv = new Buffer('MjY2YjljMmM0MjVjNzVlMGMyZGI2NjAwN2U5ZGMzZDQ=', 'base64');

var payload = new Buffer(/*payload*/);

var rijndael = new Rijndael(key, {
  mode: Rijndael.MCRYPT_MODE_CBC,
  encoding: 'hex', // shared_key encoding
  iv: iv
});

// defaults to utf-8 output encoding
payload = rijndael.decrypt(payload);
payload = payload.replace(/\0+$/, '');
Community
  • 1
  • 1
skeggse
  • 6,103
  • 11
  • 57
  • 81
0

Try something like this for node.js:

var aes_iv_b = new Buffer(aes_iv, 'base64'),
    shared_key_b = new Buffer(shared_key, 'hex'),
    decipher = crypto.createDecipheriv('aes-256-cbc', shared_key_b, aes_iv_b),
    decoded = Buffer.concat([
      decipher.update(payload, 'base64'),
      decipher.final()
    ]);
// if the output is utf8/ascii you might be able to improve performance by using
// something like this instead:
//  decoded = decipher.update(payload, 'base64', 'utf8') // or 'ascii'
//            + decipher.final('utf8'); // or 'ascii'

console.log(decoded);
mscdex
  • 104,356
  • 15
  • 192
  • 153
0

If you are able to change the PHP code to use openssl with aes-256-cbc instead of libmcrypt, then you could use the standard crypto library as I've used in this other answer

Hope it helps. Regards, Ignacio

Community
  • 1
  • 1
inieto
  • 680
  • 12
  • 17