Search code examples
node.jscryptographyopensslpbkdf2cryptojs

Should all implementations of PBKDF2 generate the the same key from identical input?


I'm switching my node.js's application's hashing algorythms from the JS based CryptoJS implementation to the node's own crypto implementation.

Here is my implementation:

var password = "password1";
var salt = generateSalt();
var iterations = 4000;
var keySize = 768/32;
var cryptoJSKey = CryptoJS.PBKDF2(password, salt, { "iterations": iterations , "keySize": keySize });
// base64 encoded key
cryptoJSKey = cryptoJSKey.toString(CryptoJS.enc.Base64);

require("crypto").pbkdf2( password, salt, iterations, keySize, function(err, derivedKey){
    var nodeCryptoKey = new Buffer( derivedKey, "binary" ).toString( "base64" );

    console.log( cryptoJSKey == nodeCryptoKey ); // always false!
});

One thing I noticed is that nodeCryptoKey ends up being 32 characters long and the cryptoJSKey is 192. If I increase the keySize for only node's crypto version to 144 (keySize * 6) the key ends up being 192 characters long as well - though it is still different.

Am I doing something wrong or do the implementations just differ from one another?


Solution

  • Looks like I figured it out.

    In the rolled up PBKDF2.js script in "CryptoJS v3.0.2.zip" (the currently download) CryptoJS.enc.Base64 is undefined; this was probably intended, but not something I noticed.

    I was comparing node's Base64 encoded output to CryptoJS's hex output.

    Another caveat was that the keySizes aren't compatible between CryptoJS and node.js. Node needs keySize * 4 in order to output an identical key. I'm not familiar with what's going on under the hood in either case; but I'll just assume that's intended.

    Node.js's PBKDF2's documentation is pretty scarce; it does, however, say its "key" parameter is named keylen, which is in bytes (or is it bits? I'm not sure).