Reputation: 10989
What's the best way to implement password hashing and verification in node.js using only the built-in crypto
module.
Basically what is needed:
function passwordHash(password) {} // => passwordHash
function passwordVerify(password, passwordHash) {} // => boolean
People usually are using bcrypt
or other third-party libs for this purpose. I wonder isn't built-in crypto
module huge enough already to cover at least all basic needs?
There's scrypt()
, which appears to be the right guy for this purpose, but there's no verified counterpart and nobody seems to care.
Upvotes: 11
Views: 16197
Reputation: 1
how to compare password using the "crypto" package(https://www.npmjs.com/package/crypto-js)
The thing is, i have a REACT app that use node as a backend to authenticate. so in the node part, i use bcrypt to compare password . Now the challange now is to use crypto to compare password. does someone can help? here is attached my script that use bcrypt package to compare password enter image description here
Upvotes: 0
Reputation: 140
It is quite an interesting thread, and different solutions are provided. After my findings, I propose a solution based on the Easy profiling for Node.js Applications
See the sample code below.
// add new user
app.get('/newUser', (req, res) => {
let username = req.query.username || '';
const password = req.query.password || '';
username = username.replace(/[!@#$%^&*]/g, '');
if (!username || !password || users[username]) {
return res.sendStatus(400);
}
const salt = crypto.randomBytes(128).toString('base64');
const hash = crypto.pbkdf2Sync(password, salt, 10000, 512, 'sha512');
users[username] = { salt, hash };
res.sendStatus(200);
});
// validating user authentication attempts
app.get('/auth', (req, res) => {
let username = req.query.username || '';
const password = req.query.password || '';
username = username.replace(/[!@#$%^&*]/g, '');
if (!username || !password || !users[username]) {
return res.sendStatus(400);
}
const { salt, hash } = users[username];
const encryptHash = crypto.pbkdf2Sync(password, salt, 10000, 512, 'sha512');
if (crypto.timingSafeEqual(hash, encryptHash)) {
res.sendStatus(200);
} else {
res.sendStatus(401);
}
});
Please note that these are NOT recommended handlers for authenticating users in your Node.js applications and are used purely for illustration purposes. You should not be trying to design your own cryptographic authentication mechanisms in general. It is much better to use existing, proven authentication solutions.
Upvotes: 5
Reputation: 49182
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
import { promisify } from "util";
// scrypt is callback based so with promisify we can await it
const scryptAsync = promisify(scrypt);
Hashing process has two methods. First method, you hash the password, second method, you need to compare the new sign-in password with the stored password. I use typescript to write everything in detail
export class Password {
static async hashPassword(password: string) {
const salt = randomBytes(16).toString("hex");
const buf = (await scryptAsync(password, salt, 64)) as Buffer;
return `${buf.toString("hex")}.${salt}`;
}
static async comparePassword(
storedPassword: string,
suppliedPassword: string
): Promise<boolean> {
// split() returns array
const [hashedPassword, salt] = storedPassword.split(".");
// we need to pass buffer values to timingSafeEqual
const hashedPasswordBuf = Buffer.from(hashedPassword, "hex");
// we hash the new sign-in password
const suppliedPasswordBuf = (await scryptAsync(suppliedPassword, salt, 64)) as Buffer;
// compare the new supplied password with the stored hashed password
return timingSafeEqual(hashedPasswordBuf, suppliedPasswordBuf);
}
}
Test it:
Password.hashPassword("123dafdas")
.then((res) => Password.comparePassword(res, "123edafdas"))
.then((res) => console.log(res));
Upvotes: 27
Reputation: 1739
const password = "my_password";
// Creating a unique salt for a particular user
const salt = crypto.randomBytes(16).toString('hex');
// Hash the salt and password with 1000 iterations, 64 length and sha512 digest
const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex');
Store both salt
and hash
for the user in DB.
const re_entered_password = "my_password";
// To verify the same - salt (stored in DB) with same other parameters used while creating hash (1000 iterations, 64 length and sha512 digest)
const newHash = crypto.pbkdf2Sync(re_entered_password, salt, 1000, 64, 'sha512').toString('hex');
// check if hash (stored in DB) and newly generated hash (newHash) are the same
hash === newHash;
Upvotes: -1