-
-
Save skyrpex/af67025d9ddf5d8de0c314af4dfbae37 to your computer and use it in GitHub Desktop.
Node.js: Create salted hashed password
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto') | |
const { promisify } = require('util') | |
const pbkdf2 = promisify(crypto.pbkdf2) | |
module.exports = { createHashPasswordFn, isPasswordCorrect } | |
/** | |
* @typedef {Object} HashPassword | |
* @property {String} hash | |
* @property {String} salt | |
* @property {Number} iterations - HMAC digest: Iterations | |
* @property {Number} keylength - HMAC digest: Key byte length | |
* @property {String} digest - HMAC digest: algorithm, see crypto.getHashes() | |
*/ | |
/** | |
* Create a hashPassword function | |
* @param {Number} saltlength - Number of random salt bytes | |
* @param {Number} iterations | |
* @param {Number} keylength | |
* @param {String} digest | |
* @return {Function} | |
*/ | |
function createHashPasswordFn(saltlength, iterations, keylength, digest) { | |
/** | |
* Hash a password with a random salt | |
* @param {String} password | |
* @return {Promise<HashPassword>} | |
*/ | |
return async function hashPassword(password) { | |
const salt = crypto.randomBytes(saltlength).toString('base64') | |
const hashBuffer = await pbkdf2(password, salt, iterations, keylength, digest) | |
const hash = hashBuffer.toString('hex') | |
return { hash, salt, iterations, keylength, digest } | |
} | |
} | |
/** | |
* Compare password attempt to a saved salt-hash-password | |
* @param {HashPassword} hashPassword - Saved salt-hash-password | |
* @param {String} passwordAttempt - Plain text password attempt | |
* @return {Promise<Boolean>} | |
*/ | |
async function isPasswordCorrect(hashPassword, passwordAttempt) { | |
const hashBuffer = await pbkdf2( | |
passwordAttempt, | |
hashPassword.salt, | |
hashPassword.iterations, | |
hashPassword.keylength, | |
hashPassword.digest | |
) | |
const hashAttempt = hashBuffer.toString('hex') | |
return hashPassword.hash == hashAttempt | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { createHashPasswordFn, isPasswordCorrect } = require('./salt-hash-password') | |
;(async function() { | |
// Sane defaults for May 2018 | |
const hashPassword = createHashPasswordFn(128, 1e5, 64, 'sha512') | |
// Result hash is different each time | |
const pw1 = await hashPassword('s3cret_1') | |
const pw2 = await hashPassword('s3cret_1') | |
pw1.hash === pw2.hash | |
//=> false | |
// Succesful comparison when given the right password and salt-hash settings | |
const pw3 = await hashPassword('s3cret_2') | |
const result = await isPasswordCorrect(pw3, 's3cret_2') | |
//=> true | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment