Strong Password Hashing with Node.js Standard Library
Cracking your users' hashed and salted password is pretty damn easy these days. To make it a bit harder for the bad guys, you should use something like PBDFK2, which hashes the password thousands of times before giving you back the result. This is called key-stretching and it helps simply by making your passwords more computationally expensive to crack.
Here's a neat little function you can use to hash (and then verify) your passwords in Node.js, using its crypto module.
crypto = require 'crypto'
hasher = (opts, callback) ->
# Generate a random 8-character base64 password if none provided
if not opts.plaintext
return crypto.randomBytes 6, (err, buf) ->
callback err if err
opts.plaintext = buf.toString 'base64'
hasher opts, callback
# Generate random 512-bit salt if no salt provided
if not opts.salt
return crypto.randomBytes 64, (err, buf) ->
callback err if err
opts.salt = buf
hasher opts, callback
# Node.js PBKDF2 forces sha1
opts.hash = 'sha1'
opts.iterations = opts.iterations ? 10000
crypto.pbkdf2 opts.plaintext, opts.salt, opts.iterations, 64, (err, key) ->
callback err if err
opts.key = new Buffer(key)
callback null, opts
opts is an object with a number of optional components:
- plaintext: The password to be hashed. If it is not provided, an 8 character base64 password will be randomly generated.
- iterations: How many times should the hash function be applied. Defaults to 10000. Strong enough?
- salt: A string or Buffer with the salt. If not provided, a 512-bit salt will be randomly generated.
Your callback should accept an object similar to the above, but with an additional component: key - the resulting 512-bit hash in the form of a Buffer.
Hashing a password
hasher {plaintext: 'secret'}, (err, result) ->
# Save as hex strings
user.salt = result.salt.toString 'hex'
user.key = result.key.toString 'hex'
user.save()
Verifying a password
# Hex string to Binary
salt = new Buffer user.salt, 'hex'
hasher {plaintext: 'secret', salt: salt}, (err, result) ->
if user.key == result.key.toString 'hex'
console.log 'Success!'
Generating a password
hasher {}, (err, result) ->
# Save as hex strings
user.salt = result.salt.toString 'hex'
user.key = result.key.toString 'hex'
user.save ->
postmark.send
From: "you@example.com"
To: user.email
Subject: "Thank you for signing up with Example.com"
TextBody: "Your temporary password is #{result.plaintext}"
Let's end on a troubling note, courtesy of scrypt and this StackOverflow answer.
Hash, rinse, repeat!