1. 28

The TL;DR seems to be “use libsodium/libNaCl”. I’d love to see some discussion and first hand experiences on that, since I’m no crypto expert


  2. 10

    As somebody that’s read a bunch of password-hashing threads on HN, here’s my understanding:

    PBKDF2 is acceptable, but bcrypt is slightly better designed, so prefer bcrypt if it’s available. scrypt is better still, Argon2 might be better again but perhaps wait a while to see how it goes.

    The article says “Scrypt requires about 1000 times the memory as bcrypt for the same security against GPU attacks” which makes it sound like bcrypt is secure against GPU attacks while scrypt has to eat a lot of memory to catch up. As I understand it, bcrypt lets you crank up the computation cost of cracking a password, but in this modern age when GPUs contain thousands of independent computation units, computation isn’t the scarce resource it once was. On the other hand, scrypt lets you crank up the computation cost and the memory cost, and memory is still scarce even on GPUs and custom-made password-cracking chips (like bitcoin miners), so scrypt lets you trade off space and time to match your use-case.

    One thing that these articles rarely mention: Let’s say your website is configured to use a password hasher configured to spend 250ms hashing. A user registers, you hash their password, and store it in your database. Eighteen months later, attackers can now get computers twice as fast, so it only takes them 125ms to hash the user’s password. Your password hashing is half as strong as it was, even though you haven’t changed anything. The answer: Whenever anybody logs in successfully, you (by definition) have a plain-text copy of the correct password, so rehash it with the current security settings. That way, whenever anybody logs in, their password storage is automatically upgraded.

    1. 5

      Eh, scrypt is way over-hyped, bcrypt is better:

      • in practice, bcrypt isn’t very vulnerable to GPU attacks or ASICs
      • bcrypt has been around a lot longer without being meaningfully broken
      • bcrypt has many more reputable libraries in different languages, probably also due to age
      • bcrypt has one hardness parameter (scrypt has a few tunables that are often obscured by the implementation, and aren’t really documented anywhere)
      • bcrypt standardizes a storage format—every library I’ve used has been compatible
      • the hardness parameter is embedded, so checking a password against a hash will Just Work, making bumping your hardness parameter trivial

      Also, bcrypt is much better than PBKDF2. You have to crank up PBKDF2 to zillions of iterations to even get close. PBKDF2 and scrypt are both more work to manage. In my opinion, crypto should be as simple and foolproof as possible.

      I wouldn’t say it’s bad or wrong to use scrypt, but you have to be more careful and think more about that decision. People should have a certain amount of knowledge to use scrypt, and be able to vet the implementation they use, at least trivially so. For Joe Shmoe web programmer who just wants to authenticate users, I always recommend bcrypt, since it’s so hard to screw up.

      TL;DR: use bcrypt, it Just Works.

      1. 1

        Whenever anybody logs in successfully, you (by definition) have a plain-text copy of the correct password, so rehash it with the current security settings

        I have never done authentication before, but I thought part of the trick was you did some Diffie-hellman thing with the JS so you only sent the hashed version of the data so the password never went plaintext anywere. Is that not true? I guess that screws over everyone that disable JS…

        1. 15

          This is not the generally accepted best practice, no. (for one, what happens when you don’t have JavaScript?)

          You send the plaintext password over a secure channel (like TLS), which is fine when you’ve authenticated that the remote server is the one you care about. If it isn’t, then even sending the hashed password wouldn’t be a significant win, since that would essentially become the new credential.

          1. 3

            Generally, if you send a salted, hashed version of the password over the wire (say, with HTTP’s Digest Authentication, or some JS-based moral equivalent), you need a plaintext copy of the password on the server to compare it to, which is worse than sending the user’s password over an HTTPS connection.

            1. 2

              Not so at all. Hash the password on the client, hash the hash again to store it.

              1. 2

                If you sniff the hashed password as it travels over the wire, you can use it to log in as that user in future, so you’re still sending an authentication token in the clear, even if it doesn’t happen to be exactly what the user typed in.

                1. 2

                  Yes, but it’s not worse, just different.

                  1. 2

                    It protects the user who reuses their password everywhere from getting it sniffed.

              2. 2

                As @kivikakk suggested, this isn’t generally done, though I have seen banks and other high profile entities attempt it. There’s the fundamental problem that you can’t really trust your web browser, though.

              3. 1

                Whenever anybody logs in successfully, you (by definition) have a plain-text copy of the correct password, so rehash it with the current security settings

                Changing the auth mechanism every 2-3 years is not a menial task, and can let users unable to login if you hit a bug. Would you actually recommend this or is it just a theoretical measure?

                1. 5

                  Changing the auth mechanism entirely would be a big change, yes.

                  The idea is that in your application’s config file you just have a single “work factor” setting, and you use it when hashing new users' passwords and re-hashing existing users. Since there’s absolutely no code change involved, it should be a very menial task to update.

                  1. 4

                    Also, grandparent poster, note that bcrypt hashes include the work factor (“cost”, in bcrypt parlance) in the hash so that changing that global setting doesn’t break comparing against the already hashed passwords