How To Safely Store A Password
codahale.com
codahale.com
To be more technical, bcrypt, like PBKDF2 and other schemes of that nature, add a significant amount of additional computation by iteratively applying a primitive, but still maintain a relatively small circuit size (in comparison to the primitive itself, which is usually designed to fit onto smart cards and the like). Creating and using algorithms which are "memory-hard" or require larger circuits reduces the number of circuits one can place on some area of silicon and drives up the cost of an attack. In other words, mounting an attack on bcrypt or PBKDF2 is still cheaper and potentially much faster than we'd like it to be (which is the reason those algorithms are "tunable"--you scale the number of iterations up as computers become faster). This, along with some example memory-hard functions was the topic of Percival's paper, "Stronger Key Derivation via Sequential Memory-Hard Functions," which correctly cites Bernstein as the source of emphasis on practicality in measuring an attack not by computational complexity, but the cost of launching the attack. See http://www.bsdcan.org/2009/schedule/attachments/87_scrypt.pd... if you're interested in reading further.
I'd love to recommend its use over bcrypt, as memory constraints are much more expensive than computational constraints, but recommending something most developers don't have access to would result in more weak hashing schemes in production.
It isn't. Bcrypt exists to protect application developers.
A user with a crappy password is getting his account busted one way or another. You're right to point that out. Cryptography won't solve that problem.
The problem crypto solves is this: a crappy web app that loses its user table is royally screwed if its devs settled for "salted hashes". At the whim of their attackers, hundreds or thousands of their user's passwords are going to hit Rapidshare. That's what the devs will be famous for.
Bcrypt keeps that from happening. You'll get famous behind losing 1000 passwords. You won't get famous behind losing 20.
Losing such a collection of salted hashes does not render one "royally screwed." Those hashes (or HMACs) are still cryptographically secure, which means it's computationally infeasible to find a first preimage provided the password doesn't suck. You seem to think (or are at least implying) that bcrypt is impervious to standard iterative bruteforce attacks, but that's just not the case. Much like PBKDF2, and other iterative hashing techniques, bcrypt is more resistant, but still "vulnerable" to such an "attack." bcrypt's main advantage over other iterative techniques, in my opinion, is the 4KiB of s-boxes used by Blowfish.
The biggest differences between Mindvox losing it's password file in 1995 and a webapp losing its user table in 2010 are:
* Web apps are getting fielded with straight SHA1 hashes, which is inferior even to FreeBSD's original MD5 hash scheme.
* Brute force attacks have gotten much faster.
The main advantage to bcrypt over, say, AES, is that the key setup is really slow. Mazieres spotted a weakness in Blowfish and turned it into a benefit.
Is there some real argument you have with me? I agree: if you lose your user table, you have real problems apart from losing password hashes --- though we could bicker about which of those problems is worse. Where are you disagreeing with me?
The argument I have is this: The passwords that are going to be hitting Rapidshare in your scenario are the crappy or short ones, whether you use bcrypt, scrypt, PBKDF2, salted hashes or HMAC. Encourage them to use bcrypt or some other iterative technique for the security benefits, but don't exaggerate and tell them that they're "effed" if they have salted hashes. They're still a long way away from storing passwords in plaintext.
Pick a number of passwords to lose from a table. Hash them with any of the SHA-3 contestants and a "salt": you will lose more. Hash them with bcrypt, you will lose less.
Again I'm left asking you: what's your point? What are you trying to prove? That you know that there's a SHA-3 contest? You haven't refuted anything this article says; in fact, you keep accidentally managing to validate it.
The weaknesses in SHA-1 make it a poor cryptographic hash, which make it a poor pseudorandom function, which has a significant potential to make it a poor password hash.
My point, for the second time, is that you're not "effed" if you use salted hashes.
I'm not trying to "prove" anything. I'm stating my opinion on the matter. This isn't a pissing contest, rather, a forum for discussion.
NIST expects SHA–3 to have a security strength that is at least as good as the hash algorithms currently specified in FIPS 180–2, and that this security strength will be achieved with significantly improved efficiency.
http://csrc.nist.gov/groups/ST/hash/documents/FR_Notice_Nov0...
Are you suggesting that because a comprise is bad, nothing should be done to reduce the magnitude of the impact? This argument does not hold up in general, and it is especially weak when arguing about using encryption algorithms with freely available, high quality implementations. The developer effort required to use bcrypt is minimal.
Also, you seem to be making the incorrect assumption that only poorly written web applications get their databases compromised. Web applications with excellent security get their databases stolen for a variety of other reasons. Even if the programmers do everything right, a careless employee might get his/her password sniffed or stolen by a key logger. If a company uses external hosting, its database could get stolen because of a mistake by the hosting providers.
In summary, the risk of your database being stolen is always present, regardless of the diligence of the the programmers who implemented the web application. The fact that a compromise is bad is not justification for ignoring simple security measures that take minimal effort to implement.
The effort required to implement bcrypt in new systems is indeed small, and such a method is the suggested way to do, but depending on the amount of users, the effort required to port an existing database over to bcrypt (e.g., Facebook) could be immense, and the result disastrous if not done with great care.
Ptacek said, and I quote, "... a crappy web app ..." so why do you only cite me as making the "incorrect assumption that only poorly written web apps have their databases compromised?"
Again, I agree that is the case in new systems, but I disagree that one is "effed," as the article puts it, if they have a large database of salted hashes.
A system which uses an adaptive hash function like bcrypt is ~6 orders of magnitude less effed in the event of a compromised database than a system which uses a standard hash algorithm and a salt, ceteris paribus.
I would hope you agree that those ~6 orders of magnitude could well be the difference between "not noticeably effed" and "profoundly effed."
Which, uh, is an objectively verifiable fact.
[1] http://www.imperva.com/docs/WP_Consumer_Password_Worst_Pract...
Start typing in the pw box, if it's not strong enough, they'll let you know.
Also, try "123456" or "password"
Yes, many users pick crappy passwords. That's a social problem, one that is difficult to address with technology[1].
Storing passwords on the server is unrelated to whether or not the user picked a good password. If an attacker gets ahold of a copy of your database, they will have a much easier time of turning SHA1 hashes of passwords into actual passwords than of turning bcrypt-encrypted passwords into actual passwords (the latter being orders of magnitude more difficult, maybe to the point of being impractical as a target vector).
[1] You can always do things like require certain types of password complexity: minimum length, choice of characters from different character classes and cases, etc. But then you end up just moving the problem elsewhere: instead of using the crappy password they remember, the user has to write down their complex password, or maybe even store it in a text file on their hard drive.
The bruteforce attack described in the article primarily affects short and dictionary-based passwords. If the password is of sufficient length and complexity (the keyspace is large enough), then bruteforcing becomes computationally infeasible. What the article proposes is, essentially, to use a more computationally expensive algorithm for the benefit of protecting shorter, weaker, passwords. I disagree, and think that increasing the computational cost of the algorithm itself should be used to enhance the security of passwords, rather than having their security depend entirely on that increased cost.
Good passwords stored as a salted hash, or preferably, as an HMAC, are in no way insecure. I feel that implying otherwise is a disservice.
There clearly are passwords that are impractical to crack. To get one, just "head /dev/random | openssl sha1".
Nobody uses passwords like that. They're irrelevant. Instead, the smart ones use passwords that contain a combination of words, numbers, and punctuation. John the Ripper has been cracking those passwords for over a decade.
"Salted hashes" are insecure. They'd have been rejected by the FreeBSD team in 1997. If you choose to make a religion out of not using bcrypt, do what the RFC says and use PBKDF.
We certainly don't want people in the software engineering industry to come up with new ideas, implement them, and see how they work in real life. That could lead to advancement in the field, and that would be bad, because I might have to learn something new. Shudder.
This brief article I found from 30 seconds in google shows my example at the bottom ('96 characters'): http://www.lockdown.co.uk/?pg=combi
I acknowledge that bcrypt seems like a simple safeguard against password attacks, but I don't doubt a hacker's ingenuity in developing a method to make attacks against it reasonable - especially if it becomes widely adopted. And I think once you've lost your password database you're already completely fucked, in one way or another.
Password hashes are part of a way to mitigate a particular situation: deciphering a login credential when the password database has been exposed. Shadow files are locked down to root-only because you should never trust people with your password hashes. If somebody has the hash, it's just a matter of time. I don't assume time is on my side.
If bcrypt() somehow makes it near-impossible to brute force password hashes in a "reasonable amount of time", we'd no longer need our shadow files to be root-only. We could give our bcrypt hashes out to the world and say, "Ha! TRY to crack this!" But you don't do that. Because you know deep down in your heart, once that hash is out in the open, the game is over. It's possible someone will crack it so you cannot trust it.
And if someone got access to your locked-down password database, someone is deep enough in your system to have at least read-only access to your password database. Whether or not they can decode the password they probably have other ways of getting whatever it is they really want, which is rarely just an account credential.
I will, however, agree that bcrypt appears to buy you much more time in the event that your password database is exposed. I am skeptical of how much more time that would be under the right circumstances, though, and the potential consequences of CPU exhaustion in the event of some kind of small DoS on the authentication layer.
Also: can you please comment on the original point of my post, which was using a complex password in addition to a fast salted hash? When compared to bcrypt and its purpose/results, is this still an inadequate technical solution, and why?
(edited to make 3rd paragraph not retarded and add request for clarification)
Here's a bcrypt hash. Crack it, and I'll donate $200 to the charity of your choice. It's not random, and the cost factor on the hash is not high.
$2a$14$Dk9dLUH6khBEU3tIHGkNX.6rm6kccRwDUq.bopQ68INbDumal3BiGthat's just mean
As far as CPU exhaustion, there are some huge sites which use bcrypt (like, in the top 10)[1]. It is not a problem, provided you choose your work factor carefully.
As far as complex passwords, use them. Try to get your users to use them. But it's an orthogonal concern: your attacker will still be able to work their way through the gigantic keyspace of your monster passwords at 1,000,000x the rate of what they could do if you'd have used bcrypt.
[1] Just looked this up. Not the top 10, but the top 15 for sure.
Moral of the story: use long and multiple passwords.
Unless, of course, you salt them (which would turn it into 4.8 months to break all the common passwords in a table, building a rainbow table with the salt taken in mind - the only situation in which you're spending 4.8 months per user is if they're each salted differently, for example with the username)- but the article doesn't suggest salting bcrypt, so I'm ignoring that.
>> BCrypt::Password.create("hi,mom", :cost => 10)
=> "$2a$10$L/c.1uoZSh3oaU1fLrnYK.yyU4PiJXsIAzN22qnbU41liyLn5/of 2"
>> BCrypt::Password.create("hi,mom", :cost => 10)
=> "$2a$10$3F0BVk5t8/aoS.3ddaB3l.fxg5qvafQ9NybxcpXLzMeAt.nVWn.NO"
>> BCrypt::Password.create("hi,mom", :cost => 10)
=> "$2a$10$VEVmGHy4F4XQMJ3eOZJAUeb.MedU0W10pTPCuf53eHdKJPiSE8sMK"
Despite the pages and pages and pages and pages of conversation about how to select and format "salts", adding random nonces to hashes is not one of the world's great CS problems.Or did you make a mistake and the cost factors are supposed to different ?
The documentation for py-bcrypt ( http://www.mindrot.org/projects/py-bcrypt/) doesn't explain what happens, but shows use is very very easy.
EDIT: current guess is that searching for the salt that was used might be part of what makes it hard.
http://people.redhat.com/drepper/sha-crypt.html Ulrich Drepper's implementation of a work factor in SHA password hashing. He addresses a popular article on bcrypt() and how using SHA allows one to follow NIST guidelines and still have the advantage of a time-consuming algorithm.
me@myhost ~/ :) time perl -le'print crypt("some-password","\$6\$rounds=900000\$myrandomsalt")'
$6$rounds=900000$myrandomsalt$O4u/Z5FRNBi3fw6YhAM1V1hC1LAawq9Ri65Kx77GchzOWieXeRs6w83bYqotyqBcz.WE29NygNli93dBDAbpt/
real 0m3.996s
user 0m3.990s
sys 0m0.005s
If someone could comment on this in comparison to bcrypt I would appreciate it. Why should we use bcrypt if this exists in modern crypt() implementations?For example salt + iterative hash works extremely well too, that's what is done in the OpenPGP format (http://www.ietf.org/rfc/rfc4880.txt - 3.7.1.3 Iterated and Salted S2K).
Is there any way to do the above while storing bcrypt passwords on the server? Does using bcrypt in these scenarios force you to use https and pass full text passwords to the server?
The idea is a developer will just do:
passwd_str = bcrypt_string_from_password(passwd);
db_store_password(userid, passwd_str);
and just be done with it, rather than having to decide between ROT13 (kidding), hashing, salted hashing, HMAC, etc. A couple years ago I thought applying SHA1 to a password before storing it in the DB was perfectly fine. Later I discovered that it was better to use a salt. More recently I've discovered that both of those approaches are flawed. Fortunately I've never written a large-scale application that deals with storing passwords, but I'm sure there are many application developers like me who would write much safer password storage routines if they didn't have to be the one to select an algorithm.Now, I'm not saying bcrypt is the answer (I know nothing about it beyond what I've read on HN), but that's the general problem with your hypothetical proposal.
He might also have got the idea from one of tptacek's suggestions not long ago.
The difference between doing the iterations and bcrypt is.. well.. not massive in a practical sense. You could do either (if your already MD5'ing passwords once [hmmmm], for example, then it is a quicker solution)
But in practical terms, "stretched" SHA1 is fine. I won't bitch at anyone for using it.
PBKDF2 is just as good a choice as bcrypt
bcrypt has a slight advantage over PBKDF2 in that it requires a larger ASIC area. It's only a constant factor better than PBKDF2, but making an attack 5x more expensive is still somewhat useful.
Your proposal also treats a 2-way cryptographic function as a 1-way cryptographic function. That is, optimistically, a questionable thing to do.
Client-side hashing would be great, if there was a way to do it that didn't involve Javascript.
For that matter, Microsoft, Apple, RedHat, Debian, and Ubuntu all make the same or (usually) even weaker assumptions in their respective packaging and/or updating systems.
Second, plenty of apps that are far bigger than yours have scaled bcrypt without event. 37signals is a public example. Other larger apps are using it without talking about it.
Third, in the spectacularly unlikely event that password hashing became a scalability obstacle, it's pure compute and scales horizontally without a problem. Note: I've never heard of someone having to do this.
Finally, the whole point of bcrypt is that it's tuneable. You dial it up to your pain threshold, and in the process cripple brute force attackers.
Proper design of such a system is the subject of the post. If you're a developer who doesn't want to think about the design of such systems, that's fantastic! Just use bcrypt.
Why is reversible encryption a terrible idea for passwords?
You've now gone from "Even if we get attacked, we've chosen a provably difficult / secure storage method. The damage should be negligible." to "If we get attacked - I hope like hell they don't get <single piece of secret info>."
An attack is an attack. If they can get in and steal your password database, what's to say that they can't get access to the key that decrypts your reversible database?
In other words, the information needed to extract the true raw-text password is actually included in the encrypted string.
With a hash, only a representation of the raw-text is being stored. Even if you knew exactly what was done to create that representation, you're still a long way off from understanding the raw-text.
If you treat both the key and the salt as being "known to the developer only" and either of these becomes compromised, you still don't have they raw-text of a hash, but you've got everything you need for the encrypted.
Is that it? bcrypt is good only because it is slow? In that case, why don't we use whatever we like (MD5, SHA1, SHA256, SHA512, SHA-3, etc) and add a sleep(500); just before the call? It is guaranteed to keep up with Moore's law as well!
In general, a password algorithm, whatever its cost, should execute with near optimal efficiency in any setting in which it sees legitimate use, while offering little opportunity for speedup in other contexts.
PBKDF1 and PBKDF2 both rely upon general-purpose hash functions, which are much faster in dedicated computing environments such as FPGA or GPU clusters. The Eksblowfish algorithm at the heart of bcrypt is extremely resistent to optimization.
This is crucial for password storage, since if a CUDA implementation is 3-4 orders of magnitude faster than the implementation your application uses, you've just chipped off a huge chunk of the advantage offered by your hash function.