Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Error: No callback provided to pbkdf2" when using async await

I want to write an async function for pbkdf2 password hash using crypto module in Nodejs. While the randomBytes function works fine, I get the following erroron running pbkdf2 with await: "Error: No callback provided to pbkdf2".

I know a workaround could be using pbkdf2Sync() but I can't understand why the async version does not work or is it correct to await on a sync function?

Node v 8.10.0

async function hashPassword(password){
	let salt;
	let hash;
	let pass;
	try{
		salt = await Crypto.randomBytes(Config.SALT_BYTES);
		hash = await Crypto.pbkdf2(password, salt, Config.ITERATIONS, Config.HASH_BYTES, 'sha512');
		pass = salt+hash;
		return pass;
	}
	catch(err){
		console.log('ERR: ', err);
	}
}
like image 554
Danial Khansari Avatar asked Sep 03 '25 06:09

Danial Khansari


2 Answers

One solution would be to wrap the method in a promise. Any method that requires a callback can be converted into one that supports async/await in this way.

function pbkdf2Async(password, salt, iterations, keylen, digest) {
    return new Promise( (res, rej) => {
        crypto.pbkdf2(password, salt, iterations, keylen, digest, (err, key) => {
            err ? rej(err) : res(key);
        });
    });
}
like image 168
R-V-S Avatar answered Sep 04 '25 20:09

R-V-S


util.promisify was added in: v8.0.0

Takes a function following the common error-first callback style, i.e. taking an (err, value) => ... callback as the last argument, and returns a version that returns promises.

const {promisify} = require('util');
const {randomBytes, pbkdf2} = require('crypto');
const randomBytesAsync = promisify(randomBytes);
const pbkdf2Async = promisify(pbkdf2);

async function hashPassword(password, options = {}){
  let params = Object.assign({
    saltlen: 16,
    iterations: 10000,
    keylen: 64,
    digest: 'sha512'
  }, options) // merge default and provided options
  
  const {saltLen, iterations, keylen, digest} = params;
  const salt = await randomBytesAsync(saltlen);
  const hash = await pbkdf2Async(password, salt, iterations, keylen, digest);  
  return salt + ':' + hash;
}

Full example with generation password hash and checking password

like image 32
Ivan Zmerzlyi Avatar answered Sep 04 '25 19:09

Ivan Zmerzlyi