Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.3k
Description
In a few words: The new scrypt API in v10.5 is dangerously designed and will cause people to make security mistakes. A new API is needed for the 98% problem (i.e. password hashing). Additionally, the documentation for the old API should make it abundantly clear that it's not meant for non-expert users, and to instead use whatever the new API is called.
Copying my comment (with slight corrections) from #20816
This is how PHP does password hashing:
// All in one go:$hash = password_hash($userProvidedPassword, PASSWORD_DEFAULT); // Later:if (password_verify($userProvidedPassword, $hash)){// Everything works out. Optionally, do this too:if (password_needs_rehash($userProvidedPassword, PASSWORD_DEFAULT)){// Someone upgraded PHP and there's a new default algorithm. We should rehash the password. } }This is almost an optimal UX for PHP developers for password storage: Salts are explicitly generated by the kernel's CSPRNG, encoded, and included in the password hash.
A step further would be making PASSWORD_DEFAULT--, well, the default.
You should only need one input for generating a new password hash: The password.
You should only need two inputs for verification: The challenge and the attempt (or the hash and password, respectively).
All other parameters should be optional.
Note: Key derivation is a separate concern, where you don't want the salt stored alongside the password hash, but that's a smaller corner of the cryptography usability market than password hashing.
Let's look at how another library handles both corner cases:
Key Derivation
#definePASSWORD "Correct Horse Battery Staple" #defineKEY_LEN crypto_box_SEEDBYTES unsigned charsalt[crypto_pwhash_SALTBYTES]; unsigned charkey[KEY_LEN]; randombytes_buf(salt, sizeofsalt); if (crypto_pwhash (key, sizeofkey, PASSWORD, strlen(PASSWORD), salt, crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT) !=0){/* out of memory */ }Password Hashing
#definePASSWORD "Correct Horse Battery Staple" charhashed_password[crypto_pwhash_STRBYTES]; if (crypto_pwhash_str (hashed_password, PASSWORD, strlen(PASSWORD), crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE) !=0){/* out of memory */ } if (crypto_pwhash_str_verify (hashed_password, PASSWORD, strlen(PASSWORD)) !=0){/* wrong password */ }Usable cryptography API design is a nontrivial undertaking, and getting it wrong will mean years (or even decades) of clean-up.
I would propose, at minimum, an alternative API that has a similar user experience to PHP's password_hash() that transparently wraps scrypt as part of the Node.js core, and then recommend that API for users who want to store password hashes (which is roughly 98% of the use case when someone reaches for bcrypt, scrypt, or Argon2).
Or you could always just incorporate the design of @joepie91's scrypt-for-humans into the Node.js core. Designing cryptography APIs for humans is a good idea.