What’s wrong with nodejs crypto decipher?

The encrypted data starts with a 8 byte “magic” indicating that there is a salt (the ASCII encoding of "Salted__"). Then the next 8 bytes is the salt. Now the bad news: Node.js does not seem to use the salt for the EVP_BytesToKey method:

int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL,
  (unsigned char*) key_buf, key_buf_len, 1, key, iv);

That NULL is the salt.

This has been verified using a Java test application (using the right salt) – the result string was returned.

Please leave out the salt using the OpenSSL -nosalt switch and try again.

[EXAMPLE]

OpenSSL CLI:

openssl enc -aes-256-cbc -nosalt -a -k password
owlstead
Mh5yxIyZH+fSMTkSgkLa5w==

NodeJS crypto:

var crypto=require('crypto')
var cipher=crypto.createDecipher('aes-256-cbc', "password")
var enc = cipher.update("Mh5yxIyZH+fSMTkSgkLa5w==", 'base64', 'utf8')
enc += cipher.final('utf8')

[LATE EDIT] Note that using secret key derivation with a salt and large work factor may be paramount to security. You’d better use a very unique, high entropy password otherwise your encrypted data may be at risk.


[REALLY LATE EDIT] OpenSSL 1.1.0c changed the digest algorithm used in some internal components. Formerly, MD5 was used, and 1.1.0 switched to SHA256. Be careful the change is not affecting you in both EVP_BytesToKey and commands like openssl enc.

Leave a Comment