I'm looking for a straightforward, secure, solution for storing a user's password using Node. I'm a cryptography novice, but have been trying to piece a solution together from researching online. I'm looking for validation that what I came up with is a solid solution for a web app with basic (not a bank, hospital, etc) security needs. Here it is:
var crypto = require('crypto');
var SALT_LENGTH = 64;
var KEY_LENGTH = 64;
var ITERATIONS = 1000;
function createHashedPassword(plainTextPassword, cb) {
crypto.randomBytes(SALT_LENGTH, function (err, salt) {
console.time('password-hash');
crypto.pbkdf2(plainTextPassword, salt, ITERATIONS, KEY_LENGTH, function (err, derivedKey) {
console.timeEnd('password-hash');
return cb(null, {derivedKey: derivedKey, salt: salt, iterations: ITERATIONS});
});
});
};
...and here are the choices I made that brought me to this point:
What hashing algorithm to use?
Based on this widely referenced article, it looks like the leading contenders are PBKDF2, bcrypt, and scrypt. I chose PBKDF2 because it has built in support in Node.
What salt size to use?
This stack overflow answer seemed to be the most straightforward answer I could find. I'm still not very clear on why 64 bytes is the right salt size though. When I google around, I get other stack exchange answers like this, but I'm not sure it applies to the Node algorithm? Totally confused here, an explanation aimed at a novice using this Node function would be awesome.
What key length to use?
Once again, I largely based my choice off the same answer as above, but I'm just as foggy on the basics of 'why'. The answer says that 'it's a waste to generate keys smaller than your input, so use at least 64 bytes'. Huh? Once again, a practical explanation would be helpful.
How many iterations to use?
For this question, I based my choice off this stack exchange answer. I don't understand much of it, but I did get that the algorithm is supposed to take approximately 8ms. So, as you can see I put timers on the function, and I adjusted my iterations to get it in that ballpark on my machine.
Thanks!
To protect passwords, experts suggest using a strong and slow hashing algorithm like Argon2 or Bcrypt, combined with salt (or even better, with salt and pepper). (Basically, avoid faster algorithms for this usage.) To verify file signatures and certificates, SHA-256 is among your best hashing algorithm choices.
The technology in the Bcrypt algorithm and process limits attacks and makes it harder for attackers to compromise passwords. Bcrypt was not designed for encrypting large amounts of data. It is best implemented for passwords, however SHA-256 is better for large amounts of data because it is less costly and faster.
The NPM package credential handles all of these
You can see the author's write up on it in the book Programming Javascript Applications
I would strongly recommend using BCrypt. There are lots of advantages to the algorithm, and most implementations handle all of these questions for you.
As described in this answer:
Bcrypt has the best kind of repute that can be achieved for a cryptographic algorithm: it has been around for quite some time, used quite widely, "attracted attention", and yet remains unbroken to date.
I've written up a detailed article about how to implement BCrypt in node/express as well as other frameworks here: http://davismj.me/blog/bcrypt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With