Search code examples
javascriptphpnode.jsencryptionrijndael

How to decrypt a message in node.js that was encrypted with Rijndael-256?


I have a message that is encrypted using PHP before it is stored in MySQL database.

I need to be able to decipher this message using node.js/javascript.

While researching how to do this, I came across the crypto module. I tried to use it, but I am running into the following error

C:\Program Files\nodejs\node_modules\mysql\lib\protocol\Parser.js:82
        throw err;
              ^
TypeError: Not a buffer
    at TypeError (native)
    at new Decipheriv (crypto.js:282:16)
    at Object.Decipheriv (crypto.js:279:12)
    at Query.<anonymous> (C:\Program Files\nodejs\modules\validator.js:76:27)
    at Query._callback (C:\Program Files\nodejs\modules\dbconnect.js:46:14)
    at Query.Sequence.end (C:\Program Files\nodejs\node_modules\mysql\lib\protoc
ol\sequences\Sequence.js:96:24)
    at Query._handleFinalResultPacket (C:\Program Files\nodejs\node_modules\mysq
l\lib\protocol\sequences\Query.js:144:8)
    at Query.EofPacket (C:\Program Files\nodejs\node_modules\mysql\lib\protocol\
sequences\Query.js:128:8)
    at Protocol._parsePacket (C:\Program Files\nodejs\node_modules\mysql\lib\pro
tocol\Protocol.js:274:23)
    at Parser.write (C:\Program Files\nodejs\node_modules\mysql\lib\protocol\Par
ser.js:77:12)

This is how I am trying to decript the message using the crypto module

var crypto = require('crypto');
var encryptedText = new Buffer(rows[0]['password'], 'base64');
var decipher = crypto.createDecipheriv('sha256', 'The encryption password', 32);
var decrypted = decipher.update(encryptedText, 'hex', 'utf8') + decipher.final('utf8');

console.log('My Pass: ' + decrypted);

This is how I encrypt the message using PHP

define('PHP_HASH_ALGORITHIM','sha256');
define('PHP_MCRYPT_CIPHERNAME','rijndael-256');
define('PHP_MCRYPT_MODE','ecb');
define('PHP_MCRYPT_KEY','The encryption password');

function encrypt($input, $textkey = PHP_MCRYPT_KEY) {
    $securekey = hash(PHP_HASH_ALGORITHIM, $textkey, TRUE);
    $iv = mcrypt_create_iv(32);
    return base64_encode(mcrypt_encrypt(PHP_MCRYPT_CIPHERNAME, $securekey, $input, PHP_MCRYPT_MODE, $iv));
}

This is how I would decrypt the message using PHP

function decrypt($input, $textkey = PHP_MCRYPT_KEY) {
    $securekey = hash(PHP_HASH_ALGORITHIM, $textkey, TRUE);
    $iv = mcrypt_create_iv(32);
    return trim(mcrypt_decrypt(PHP_MCRYPT_CIPHERNAME, $securekey, base64_decode($input), PHP_MCRYPT_MODE, $iv));
}

How can I correctly decrypt the message using crypto?


Solution

  • In PHP, you're using Rijndael with a block size of 256 bit ("rijndael-256") and a key size of 256 bit (determined through SHA-256 output). Rijndael also supports the block sizes of 128 and 192 bit. Node.js' crypto module only supports AES which is the same as Rijndael with a fixed block size of 128 bit and variable key size (128, 192 or 256 bit). It means that you can't recreate the same functionality with Node.js' crypto module.

    You need to find a module that supports Rijndael-256. mcrypt and node-rijndael come to mind which both are simple wrappers around libmcrypt which you would need to install additionally.

    It would be probably easier, if you could change the PHP code to use AES (rijndael-128).

    Keep in mind that SHA-256 is a hashing function and not an encryption algorithm. You need to use crypto.createHash(algorithm) instead of crypto.createDecipheriv() to derive the key from a password.


    Security considerations:

    • When you derive a key, you should do that with a random salt and many iterations. Use PBKDF2, bcrypt or scrypt for that. If the password is short (less than 20 characters) then it would be easy to brute-force.

    • Don't use MCrypt. It's abandonware. PHP and Node.js both support OpenSSL encryption which makes it easier to find compatible ciphers. (Still need to select the same mode of operation and padding.)

    • Don't use ECB mode. It's not semantically secure. At least use CBC mode with a random Initialization Vector (IV). The IV doesn't have to be secret, so simply prepend it to the ciphertext.

    • Authenticate your ciphertexts either with an encrypt-then-MAC scheme with a strong MAC like HMAC-SHA256 or use an authenticated mode of operation like GCM or EAX.