Looks like for the typical case (~200ms calculating the hash) bcrypt beats argon2. I guess that’s what I understand from those discussions, I’m not an expert by any means. It is related with cache hardness: https://twitter.com/Sc00bzT/status/1149963675069026304
In particular, in terms of ASIC attacks, bcrypt and other non-memory-hard KDFs have extremely efficient implementations. Silicon is cheap, computation is cheap, memory access is extremely expensive- both in terms of time and power usage.
And that Twitter link (https://twitter.com/TerahashCorp/status/1155129705034653698) leads here: https://www.password-hashing.net/ ... but, on that website, I could not find an explanation about why to use argon2 over bcrypt.
Here is an scrypt just in JS[1]. It will also run in the browser, if you need to hash client side for some reason. On node, it will use the built in crypto api which IIRC is a wrapper around openSSL so perf should be native. I'm not a big fan of the API, you have to concern yourself with buffers and normalization. Maybe that is important for non-latin alphabets? I don't actually know, I'm too anglo-centric.
Then there is good ol bcrypt[2]. Certainly the most mature, it has been around a while. Like [0], it also uses a native module with node-gyp.
All three support async/await so you can avoid blocking the event loop during expensive hashing operations. I should note I haven't really used any of them. I was just curious so I did some googling.
Based on your criteria, I think [0] fits the bill best. Very hard to forget the salt, as it is generated by default and stored with the hash.
I'm always really curious about other people's code, so I hope you don't mind me asking: I typically use a library/framework that handles details like password hashing. That said, sometimes i like to avoid libs and really understand every aspect. Can I inquire about your stack? Are you using express or koa or anything like that?
[0] https://github.com/ranisalt/node-argon2
I think it's fine enough if I stick with bcrypt, and that's what I'm planning to do, but I saw this was on the front page, so I opportunistically made the comment hoping that someone with experience in this area (e.g. tptacek) might see the question and jump in :)
[0] https://latacora.micro.blog/2018/04/03/cryptographic-right-a...
const scryptParams = { logN: 15, r: 8, p: 1 };
async function hashPassword(password: string): Promise<string> {
const password_hash: Buffer = await scrypt.kdf(password, scryptParams);
return password_hash.toString("base64");
}
async function verifyPassword(hash, password): Promise<boolean> {
return await scrypt.verify(Buffer.from(hash, "base64"), password);
}I know that Litecoin used scrypt to harden it against GPU/ASIC mining, but GPU/ASIC miners ended up coming out anyways. With this in mind, is scrypt actually a better option than bcrypt?
More recent designs such as scrypt and Argon2 force high memory usage as well as computation time, incurring little cost on the users but making ASIC and GPU attacks significantly less cost-effective.
Of course, any of these will still give better protection than plain cryptographic hashes.