Digest string NOT WORKING crypto.pbkdf2Sync

Viewed 365

I am trying to update the authentication system of an old application that used to run on node 4.5, but I am getting this error every time I try to login.

TypeError [ERR_INVALID_ARG_TYPE]: The "digest" argument must be one of type string or null. Received type undefined
    at check (internal/crypto/pbkdf2.js:56:13)

Here is what I tried to solve the issue
The old version of the code is:

crypto.pbkdf2Sync(password, new Buffer(this.salt, 'base64'), 10000, 64).toString('base64');

And I am trying to update to this:

pbkdf2Sync(password, new Buffer(this.salt, 'base64'), 10000, 64,'sha512').toString('base64');

This doesn't work however as the previously stored hashed passwords don't match the hashes created by the update I implemented.

Any suggestions on what I can do?

2 Answers

I'd suggest passing "sha1" as the digest parameter, since this is the digest that is used if the digest parameter was not included - from the docs:

A selected HMAC digest algorithm specified by digest is applied to derive a key of the requested byte length (keylen) from the password, salt and iterations. If the digest algorithm is not specified, a default of 'sha1' is used.

So if we explicitly pass "sha1" as the digest, we should get the required result:

crypto.pbkdf2Sync(password, Buffer.from(this.salt, 'base64'), 10000, 64, "sha1").toString('base64');

The code below is running on an online compiler using Node 12.16.1 without any error. It was part of another project so some extra information is given there.

output:

Generate a 32 byte long AES key with PBKDF2
aesKeySha256 length:  32  data:  e1ea3e4b0376c0f9bf93b94fe71719a099317297b79108aacd88c8a355d7a3d4
aesKeySha1   length:  32  data:  d6bc1ae2aea28f5098826b555d7a0fe073e5bc7d8136d232e01d422ba2dd761e
aesKeySha1   Base64:  1rwa4q6ij1CYgmtVXXoP4HPlvH2BNtIy4B1CK6Lddh4=

Security warning the following code uses a fixed salt - for production use a random generated salt for each run:

console.log("Generate a 32 byte long AES key with PBKDF2");
var crypto = require('crypto');

var password = "secret password";
var PBKDF2_ITERATIONS = 15000; // number of iterations, higher is better but slower

// ### security warning - never use a fixed salt in production, this is for compare reasons only
var salt = generateFixedSalt32Byte();
// please use below generateSalt32Byte()
//var salt = generateSalt32Byte();

var aesKeySha256 = generateAes256KeyPbkdf2Sha256(password, PBKDF2_ITERATIONS, salt);  
console.log('aesKeySha256 length: ',
  aesKeySha256.length, ' data: ', bytesToHex(aesKeySha256));
var aesKeySha1 = generateAes256KeyPbkdf2Sha1(password, PBKDF2_ITERATIONS, salt);  
console.log('aesKeySha1   length: ',
  aesKeySha1.length, ' data: ', bytesToHex(aesKeySha1));

var aesKeySha1Base64 = generateAes256KeyPbkdf2Sha1Base64(password, PBKDF2_ITERATIONS, salt);  
console.log('aesKeySha1   Base64: ', aesKeySha1Base64);

function generateAes256KeyPbkdf2Sha256(password, iterations, salt) {
  return crypto.pbkdf2Sync(password, salt, iterations, 32, 'sha256');
}

function generateAes256KeyPbkdf2Sha1(password, iterations, salt) {
  return crypto.pbkdf2Sync(password, salt, iterations, 32, 'sha1');
}

function generateAes256KeyPbkdf2Sha1Base64(password, iterations, salt) {
  return crypto.pbkdf2Sync(password, salt, iterations, 32, 'sha1').toString('base64');
}

function generateSalt32Byte() {
  return crypto.randomBytes(32);
}

function generateFixedSalt32Byte() {
  return Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex');
}

function bytesToHex(input) {
  return input.toString('hex');
}
Related