2

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?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Junior
  • 11,602
  • 27
  • 106
  • 212
  • @BurninLeo where would I find the crypto.js file? – Junior Sep 21 '15 at 18:33
  • When I change the iv value from 32 to this `var iv = new Buffer(32, 'binary');` I get this error `Error: Unknown cipher` I am not sure if I should pass the number 32 there or not – Junior Sep 21 '15 at 18:38
  • Sorry, I mis-read the error message. Accoring to https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv, "key and iv must be 'binary' encoded strings or buffers." - i.e., in my opinion, `32` is not valid at all. – BurninLeo Sep 22 '15 at 07:54

1 Answers1

6

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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • @artjimB thank you so much for this great answer. I want to try the node-rijmdael but as you said I need to install libmcrypt first. I don't see a `libmcrypt` library for npm. How can I install it? – Junior Sep 21 '15 at 21:00
  • It's a native library for linux possibly even windows, but I doubt it. Maybe there are pure JavaScript implementations of Rijndael out there, but I don't know any. – Artjom B. Sep 21 '15 at 21:18
  • It shouldn't matter if there's a `libmcrypt` for Node or not. – Scott Arciszewski Sep 21 '15 at 22:51
  • @ScottArciszewski in order to install the libraries I must install `libmcrypt` and I can't figure out on how to use it? I am running Node.js on windows. – Junior Sep 22 '15 at 15:06
  • @MikeA You could just write a minimal PHP script that does this and call that php script from node.js through child_process. – Artjom B. Sep 22 '15 at 15:28
  • @ArtjomB. can you please give me an example of how to call the php script using a child_process? – Junior Sep 22 '15 at 16:08
  • @MikeA [Execute a command line binary with Node.js](http://stackoverflow.com/questions/20643470/execute-a-command-line-binary-with-node-js) You can pass the data either as temporary files or as console output (encoded or binary) – Artjom B. Sep 22 '15 at 16:09
  • Why do you need libmcrypt? If it's for AES, you can use any implementation of AES not just libmcrypt's. – Scott Arciszewski Sep 22 '15 at 20:00