vignesh vignesh - 1 month ago 15
Node.js Question

NodeJS pbkdf2Sync password hasing portability from v0.12.7 to v6.9.1

I have been working on porting an application written from node v0.12.7 to node v6.9.1.

We are using MEAN stack with all of them upgraded to their latest versions.

We have been able to upgrade everything except for one problem. We used pbkdf2Sync method (comes inbuilt with express) for hashing passwords like so:

/**
* Hook a pre save method to hash the password
*/
UserSchema.pre('save', function(next) {
if (this.password && this.password.length > 6) {
this.salt = new Buffer(crypto.randomBytes(16).toString('base64'), 'base64');
this.password = this.hashPassword(this.password);
}

next();
});

/**
* Create instance method for hashing a password
*/
UserSchema.methods.hashPassword = function(password) {
if (this.salt && password) {
return crypto.pbkdf2Sync(password, this.salt, 10000, 64).toString('base64');
} else {
return password;
}
};


In the latest versions, they have changed the encoding to utf8 and also changed the pbkdf2Sync to include a mandatory digest. I am not sure what else they have changed.

The problem:

The passwords hashed and stored in the mongo database using earlier version of node does not match with the password generated by hashPassword function after version upgrade.

I have tried:

1) Specifying encoding string

2) Using buffers

3) Adding digest option as parameter

And I dont get the same hashed password with any of these.

I tried changing the hashPassword function with many combinations. One of the tries I made was this, but does not work.

UserSchema.methods.hashPassword = function (password) {
if (this.salt && password) {
return crypto.pbkdf2Sync(password, new Buffer(this.salt, 'base64').toString('binary'), 10000, 64, 'SHA1').toString('base64');
} else {
return password;
}
};


A test case:

Password to hash: ramco@123

Salt: d\u001e'��\u0001\u0004\u0012)aq�**G\u000f

Result I am supposed to get: kG6uCjSk87I7PrXMko+nS8Mz/78LMilXDMJZI0mzBgi75mBpi8hIkh3+B8CqpuYZdvvs5HWjcNthhhnUA89sCw==

But I get some other string from the hashPassword function.

I referred:

The NodeJS commit made in git:
https://github.com/nodejs/node/commit/b010c8716498dca398e61c388859fea92296feb3

The express commit made in git:
https://github.com/meanjs/mean/commit/61f1a22c91ac15f06143ace6e540b334fa9e3bd6

Crypto documentation:
https://nodejs.org/api/crypto.html

How to store crypto pbkdf2 in mongoDB?

And lot of other sites and forums but did not help me. Kindly help me if you can.

Thanks in advance.

Answer

Looks like older versions of Node used SHA-1 as digest. Also, you should pass in the salt as a binary buffer (I'm using the supplied salt string from your example, if you have stored the salt as Base64-encoded binary you can probably leave the base64 encoding that you're using as-is and only explicitly set the correct digest).

The following yields the expected result:

const crypto = require('crypto');

let password = 'ramco@123';
let salt     = `d\u001e'��\u0001\u0004\u0012)aq�**G\u000f`;

let x = crypto.pbkdf2Sync(password, new Buffer(salt, 'binary'), 10000, 64, 'sha1').toString('base64');

console.log(x);
Comments