Search code examples
javascriptnode.jscryptographycryptojspbkdf2

Nodejs crypto.pbkdf2 result is different from CryptoJS.PBKDF2


I'm working with PBKDF2 on frontend (CryptoJS) and backend (Node.js), both the derived key must be equal so, I use the same salt, same algo, same number of iteration, same password, but the derived key is different.

This is the Browser/cryptoJS code, in comment the sample salt and key. (hex)

<script type="text/javascript" src="pbkdf2.js"></script>
<script type="text/javascript" src="sha512.js"></script>
<script>
var salt = CryptoJS.lib.WordArray.random(128 / 8);
var key512Bits = CryptoJS.PBKDF2('anacleto', salt, { hasher:CryptoJS.algo.SHA512, keySize: 512 / 32, iterations: 1 });
console.log(salt.toString(CryptoJS.enc.Hex));
// 1427f23fd32f8f9902768e7ab7c7ffad
console.log(key512Bits.toString(CryptoJS.enc.Hex));
// de3259de39fcc55531b91b4ffb2a6c29005c674cc95b3ec5bdf18412b6087d05921f3a0e4148fc34c88a04e980481d397a4c2b143edc0cb1bb5d7434ca3b4c25
</script>

And this is the nodeJS code

var crypto = require('crypto');
var salt_hex = '1427f23fd32f8f9902768e7ab7c7ffad';
var key_hex = 'de3259de39fcc55531b91b4ffb2a6c29005c674cc95b3ec5bdf18412b6087d05921f3a0e4148fc34c88a04e980481d397a4c2b143edc0cb1bb5d7434ca3b4c25';
var salt = new Buffer(salt_hex, 'hex');
crypto.pbkdf2('anacleto', salt.toString('utf8'), 1, 512/8, 'sha512', function (err, key) {
  if (err)
    throw err;
  var x = key.toString('hex');
  var y = key_hex;
  console.assert(x === y, '\n' + x + '\n !== \n' + y);
});

And the console comes up with this assertion error:

AssertionError: 
efcca398dc0eb07aec6dcf2239dae83b79c2f82212b2cc0a21270fe251c73c7ab69f0133e75bf3ca6159242826ff3f26c64075f72cf86c67ba1199af29f6d576 
!== 
de3259de39fcc55531b91b4ffb2a6c29005c674cc95b3ec5bdf18412b6087d05921f3a0e4148fc34c88a04e980481d397a4c2b143edc0cb1bb5d7434ca3b4c25

As you can see the key from node.js starts with "efcca" and the CryptoJS one start with "de325".

Where is the error? Maybe it's a different library implementation?? Shouldn't be the same derived key?


Solution

  • When you do

    var salt = CryptoJS.lib.WordArray.random(128 / 8);
    

    You get random bytes. When you encode the salt to a UTF-8 string in node.js it will result in a different encoding than what node.js's crypto.pbkdf2 expects.

    Change

    crypto.pbkdf2('anacleto', salt.toString('utf8'), 1, 512/8,
    

    to

    crypto.pbkdf2('anacleto', salt, 1, 512/8,
    

    or

    crypto.pbkdf2('anacleto', salt.toString('binary'), 1, 512/8,