How To Safely Store A Password
codahale.com
codahale.com
h = HASH.new()
HASH.update(password)
HASH.update(salt)
for x in xrange(X):
HASH.update(HASH.digest())
return HASH.digest()
this approach "strengths" the hash by forcing you to calculate it over and over again. You should set X to be the number of rounds you want to conduct. Ie. how slow you want you server to respond to an individual request. It is always a trade-off between server slowness for individual requests and "security" of the hash function. The goal is to make dictionary attacks take longer than is feasible for you attackers to conduct.[Note: you should absolutely have a different salt for each password with this approach.]
Here's a version that's much easier to read than the spec:
https://github.com/emerose/pbkdf2-ruby/blob/master/lib/pbkdf...
I should stop saying PBKDF2 and just go back to saying PBKDF.
I'd be happy to find out I'm wrong.
HASH.update(salt)
On each iteration as well? Then again, if things were this simple, someone would have already said "just do this", it would have been peer-reviewed and would have become widely used. Anyone know why this hasn't caught on yet in web frameworks like Django/Rails?When working with cryptography, "why not also add" is really dangerous, because some times you get less secure systems after doing so. And other times you get no benefits from doing so.
Assume you have a perfect cryptographic hash function H(X). No matter how many of N bits of X you change (0 < N <= len(X)), on average 50% of the bits of H(X) will change. So, let's consider the case of just H(salt || H(salt || password)) versus H(salt || H(password)).
Let A = H(salt||password), and let B = H(password). A and B are now, for all practical purposes, two different random integers. Each of which has the same entropy. This is because adding the salt should make no impact on the quality of these random numbers. It should now be fairly easy to see that there is no difference between H(salt||A) and H(salt||B), other than the fact that they produce different outputs.
This is all based on the assumption that the hash function is a perfect one -- however this assumption is reasonable for strong hash functions.
EDIT: also what Thomas said. It is in the standard that 1000 should be the minimum value. I would use higher based on the level of protection you want to give your users. Note that different hash functions have different costs so this will also impact the choice of X.
I'm thinking you could take your entropy analysis of the user's password and set it so that "weaker" passwords use a higher work factor. This analysis could be easily done before hashing every time the password is input, so an attacker wouldn't be able to single out weak passwords from the hash file.
Theoretically, you should be able to tailor the numbers so that cracking a weak password isn't any faster than cracking a strong one, right? Plus it will encourage your users to use a stronger password in the first place, since it'd make login slightly faster.
Any obvious problems with this plan?
I feel like it might still help you to avoid wasting time exhaustingly hashing already strong passwords. I mean, how high does that uniform work factor have to be?
The guy whose password is "password" or "qwerty12" is gonna get cracked no matter what, sure. But what about people whose passwords are a couple of dictionary words? If the work factor means each hash takes a second or two, even a slightly complex dictionary attack becomes fruitless (for most crackers...)
So the user can still log in, but it takes a second or two, and there's that little message, "To ensure the safety of your password, your login has been slowed down. If you use a more secure password, like <generate password>, you will login much faster!"
And the young lady using "6ab$TRa?" isn't being punished for the fact that most users use crappy passwords, nor is your server.
But as computing power increases, that minimum strength is being pushed out. bcrypt lets us hold the line by keeping pace with computing power— couldn't it also give us the ability to push back?
How many users are using the 100,000 most common passwords? 1,000,000? As it stands today, anyone using one of those is instantly compromised the moment the hash file is accessed. With a truly variable work factor, you could theoretically ensure the safety of any password, regardless of strength.
It obviously gets silly toward the far end (make "password" take three months to hash?) And maybe it gets silly a lot sooner than I'm thinking. But surely it could be pushed back a little, yes? Make one of those 1,000,000 passwords intractable, and you're protecting thousands of users from attack.
False.
Collision attacks don't apply to many situations but are much easier to execute, for example a MD5 pre-image attack requires approximately 2^128 steps but a collision attack requires only about 2^64 steps. This is why MD5 is totally unsuitable for collision resistance, and in fact has already been successfully exploited to fabricate a real-world CA certificate, but still puts up mild resistance to password cracking. Not that I'm recommending you use it or anything -- do what the nice gentleman says and just use bcrypt already!
Please disregard my comment above.
How? If hashing one password takes one second, and you have a dump of a thousand users, it will take you a million seconds to try just 1,000 common passwords on that list.
Are you thinking of unsalted hashes, perhaps?
So really I think you were demonstrating my point :)
Have the work factor also be a function of the password itself... this would cause even more difficulty brute-forcing the password, as it means intermediate steps would also have to be tested - breaking one weak password doesn't give you any information about other passwords.
BCrypt is already based on the premise that there are passwords which are easy to compute, and tries to avoid that differentiation. Why would you introduce it back in?
Of course it's a good point that the challenge then becomes determining what that set of passwords is. And not having run the numbers, I can't be sure how much room for improvement there is.
E.g. an attacker can go "Oh! this password will take FIVE SECONDS to test, so I know it must be a simple password." or "Hey, check this out; this password can be tested in 0.1 seconds. It must be pretty complex."
In general, I'd guess that these kinds of information leaks are pretty bad because if an attacker can see how hard a password is to test, he now knows something about the password.
It may be better if, given a single unchanging hash, if it takes a variable amount of time to test a given password against this hash, though that might have its own can of worms.
The work factor is an input to the digest function, both when creating and when validating the password. Normally it should be stored alongside the digest itself so you can increase the work factor over time without disrupting existing passwords. So you are correct. It might theoretically be possible to correctly balance the work factor to counter variation in password info entropy so that all passwords take about the same time to crack, and this would be very cool and impress members of the opposite sex, but it would not improve security at all.
Making a probabilistic password checker is also a superficially interesting idea. Maybe my mind is too small to explore it completely, but it seems that at best it would be no better than just increasing the work factor.
How could someone use this? Well, I could decide to only target the rows with a low work factor. Since your entropy estimate is high for these rows, I can know that it's more likely they'll be 8 characters or longer and use a wider range of characters. I can likely ignore all candidate passwords that are shorter or that do not include non-alpha characters.
How useful is this? Let's assume 2 choices of work factor. Also let's assume strong passwords of length 8 have 96^8 ~= 53 bits of entropy and eak passwords of length 8 or less have 27^8 ~= 38 bits of entropy.
You just let me cut the search space for strong passwords of length 8 to to ~15 bits, and in a double whammy, I get to use bcrypt with a low work factor when brute forcing against these rows.
I'm not a cryptographer, and so it's entirely likely I've made some mistake here. But as a general rule, I think it is an _extremely_ bad idea to use cryptography in any way that exposes additional information about individual rows in a database.
Cryptography is not a place for innovative thinking. Even cryptographers need their cleverness to undergo exhaustive review.
> … Let's assume 2 choices of work factor. Also let's assume strong passwords of length 8 have 96^8 ~= 53 bits of entropy and eak passwords of length 8 or less have 27^8 ~= 38 bits of entropy.
> You just let me cut the search space for strong passwords of length 8 to to ~15 bits…
You can’t subtract bits of entropy like that.
Here’s something I hope will convince you this reasoning is faulty.
Imagine a universe of 3-digit passwords, and there are two kinds of passwords: Strong ones use a mix of digits 0–7, and weak ones only use the digits '0' or '1'.
You could see the strong passwords could be any of 8^3 = 512 different combinations (~9 bits of entropy), except the 2^3 = 8 combinations (3 bits of entropy) that would only contain ones and/or zeros. So while a worst-case for brute-forcing a known-weak password is trying 8 strings, the worst-case for brute-forcing a known-strong password is trying 504 strings. This is still the same order of magnitude, and still approx. 9 bits of entropy! You removed such an incredibly small sliver of passwords, that an attacker really isn’t any better off than before.
Another way to think of this is, just because the user didn’t use only lowercase letters, doesn’t mean that none of the characters are!
Back to your example, with a strong password search space of 96^8. Now if you know a password is strong, that means it isn’t one of the 27^8 possible weak passwords. By how much does this reduce our search space?
7,213,895,789,838,336 possible strings of length 8
- 0,000,282,429,536,481 possible 'weak' 8-char passwords
= 7,213,613,360,301,855 possible 'strong' 8-char passwords
We’ve reduced our search space by only .0039%.
That said, rolling your own crypto — which the grandparent post isn’t really quite doing — is something you should run away from, fast, unless you really are a cryptographer!
Why are you storing the whole salt in your database? Isn't it much more common to keep half of it in a configuration file? I know Django has a SECRET_KEY parameter for this sort of thing, and hopefully other frameworks do also.
For that matter, why is authentication being handled by the web server? If you've got data worth stealing (billing, emails, medical), you can afford to spring the extra few hundred for a proper authentication server.
Gawker's password handling (7-bit salt, in the database, digested with crypt) seems like the worst possible implementation of secure password storage.
The 128-bit salt used by bcrypt makes the table intractably hugely large. You cannot precompute it.
Of course, you know the salt (because it's stored right there in /etc/shadow), so you can still run through dictionary words and try them all. But bcrypt is designed to take arbitrarily long amounts of real time to do this.
So in the case of bcrypt, it's not really an issue that the salt is stored right there alongside the hashes password.
Bcrypt is not better because it has a better salt. It's better because one iteration of bcrypt takes a long time, and millions of iterations take an intractably long time.
Obviously, the variable-cost key scheduler is the central notion to the thing, but not having a large salt completely nerfs it.
bcrypt uses a 128-bit salt, and it uses it for good reason. See the paper, sections 6.2.1 and 6.2.2.
Putting the 128-bit salt on there prevents a precomputed dictionary attack, a constant time operation.
But SHA1 itself is a constant time operation, so having a salt only slows down an attacker in a wall time sense, but not the more important time-complexity sense.
We all agree the salt is not particularly important for the constant time hash. (It's only practically important when the hash takes a lot of wall time relative to the wall time of a precomputed dictionary lookup, and constant time hashes gradually lose this edge due to Moore's Law.)
The point you see me making is that bcrypt is not a constant time operation (due to the variable-cost key schedule--2^cost, actually), and allowing people to use a constant time precomputed dictionary lookup by not having a large salt would make it as bad as no-salt SHA1.
So we all agree that the large salt is vitally important for the non-constant time bcrypt.
Not that either of these points are relevant to my initial assertion that giving the salt to an attacker is not something people worry about. The salt is there to prevent a precomputed dictionary attack, and a large salt does this no matter how well-known it is.
Every time this topic comes up, 15 people chime in with various schemes in which some of the "salt" is derived from the hostname and some of it is stored in an encrypted vault and some of it is inferred from the color of the user's eyes. This is why Coda is making fun of "Himalayan pink salt".
To understand how irrelevant these details are, consider AES encryption. In addition to hiding an AES key, you can also hide portions of the AES CBC IV (a public value). You could use a random number of rounds. You could mix in tweaks with the round key. All of these things are possible, but (a) nobody analyzes AES based on those random hacks, because they don't fundamentally alter the properties of AES, and (b) nobody does those things, because they are silly.
Gawker could use the best conceivable practices in cryptography to obscure passwords; they could be using Colin Percival's scrypt function (which nobody uses yet) to be (in some way) provably resilient to hardware-assisted cracking. You could still level this criticism at them, for "not doing something to further obscure the encryption they used".
This is not a new argument; what I am re-explaining here is Kerckhoffs' principle.
I don't understand why you'd add extra content to the password unless you keep it secret. The whole point of a salt/nonce is to prevent attackers from attacking the digest, right? You need some per-user data, to defend against rainbow tables, and some per-site data, to protect weak passwords.
My fundamental objection to schemes like bcrypt/scrypt is that they impose a heavy performance penalty on authentication to avoid a relatively rare case; besides, any theoretical entity capable of reversing a typical salted-password implementation is also capable of reversing bcrypt/scrypt.
You're exactly the guy I'm talking about. "Oh, I use AES, but I don't just use AES; I store the secret IV for AES in a cookie so even my server can't decrypt it unless the client comes back with the IV so it's like two guys in the silo with the missile keys". Seriously, I just found that piece of code yesterday. Did you write it? Stop writing that stuff.
I know there's lots of ways to screw up security, but most of them derive from lazy people taking shortcuts. They run the httpd, database, and authentication all off the same server so a vulnerability in one compromises all. They store secrets in the database because figuring out secure storage would take half an hour of research.
Replacing a poorly-implemented SHA1-based system with a poorly-implemented bcrypt-based one won't help security.
If the entire knowledge you have of cryptography comes from _Applied Cryptography_ --- wait; let me extend that: if you even feel the need to cite _Applied Cryptography_ --- you should be careful debating crypto constructions. You're not going to end up happy.
Anyone can create an input that hashes to a given value. The relevant factor is how long it takes to create that input. I hope you can see the difference between that process taking 3 seconds vs 40 years.
A part from the obvious flaw of including part of the password in plain text, how secure is this method compared to the following method were the salt is not a secret and were the concatenated hash + salt is hashed?: saltedhash(password)=hash(hash(password).salt)
The real error was misreading the man page and using the first two characters as the salt, which is then published as the first two characters of the hash. It's sort of an easy error to make, because to decrypt, you do use the first two characters of the hash. Understandable for a beginner working on a school project, but pretty ludicrous for a large company holding control over most of the domains on the internet at the time.
You're authenticating over the internet. What is 1/10th of a second to authenticate the first time you want to log in relative to everything else? It's like complaining you have to put the key into your car before starting a five hundred mile road trip. Yes, it takes a few seconds. But worth it? Most definitely.
Maybe the correct thing to do is to make the key derivation executed on the client side, but then this would erode the experience of mobile phone users.
And if it really kills you to make it take a full second, then make it take 1/10th of a second: there, now your hashing is faster than the time it takes to dynamically generate a page.
People really need to learn that security doesn't come free, and some times you just need to bite down and say "You know what? I never plan on getting broken into, but just in case I do I'll take the tenth of a second extra computation in exchange for doing the right thing."
SELECT username FROM users WHERE password=HASH('secret');
I've seen systems where that statement will give a list of all usernames with the password "secret". SELECT username FROM users WHERE password = HASH(salt||'secret');
This is academic because you already know the password ('secret').Salts make rainbow tables (essentially precomputed hash values of (say) all english words) hard and infesiable.
How is that really any better? You should assume that if an attack can get to your database, they can get to your web servers and take all of that as well. Such a scheme certainly wouldn't have saved Gawker.
There's no reason why compromising the database would allow attackers into the web server, unless you've configured SSH to allow signing in from arbitrary remote systems.
http://www.theregister.co.uk/2010/11/23/network_card_rootkit...
(Why yes, I _did_ have that problem weighing on my mind while I investigated several machines that had a weekends worth of exposure to the recent Exim remote root exploit...)
I think you give people way too much credit. Maybe config files aren't "typically" world-readable but they ARE typically httpd-readable.
It's a mistake to assume, that because you might follow best-practices, the rest of the people out there do. You said yourself in a comment on this same post that many people make mistakes because they're too lazy to take that "half an hour of research." Let's make the assumption that that is typical.
> There's no reason why compromising the database would allow attackers into the web server, unless you've configured SSH to allow signing in from arbitrary remote systems.
Oh, you mean the default behavior? See above.
The point is, if someone has gotten enough access that they can actually get a raw copy of the database, it's just as likely they can get a raw copy of the config files, or /etc/shadow, or whatever else is on the host system.
Thanks to codahale for writing this, r11t the HN user who originally posted this early this year, and the discussion by everyone on that HN thread which convinced me of the correctness of the bcrypt approach.
I've already shipped one project which I'm sure at least part of the reason we successfully pitched was our demonstrated indepth understanding of password security requirements.
(I also realised in retrospect that a project I'd designed and specced before reading that article/discussion was going to be wrong in it's password handling, I'm disappointed we never got to build that product, but I'm kinda glad I'm not sitting here thinking "Fuck, what am I gonna do if $project's database ever gets compromised? It'll be just as bad as Gawker...")
import hashlib
hashed = password
for i in range(50000):
hashed = hashlib.sha1(salt + hashed)
Provided we also store the number of iterations (along with the salt), and provided I didn't do anything stupid above, we could simply add more iterations after these 5 years and update hash and number of iterations field. Would it be a viable solution? import bcrypt
hashed = bcrypt.hashpw(password, bcrypt.gensalt(log_rounds=13))
Increasing log_rounds by one increases the work factor exponentially (2 * * log_rounds). import timeit
t = timeit.Timer(stmt="""\
def test(pwd, n_iter):
for i in range(n_iter):
pwd = hashlib.sha1(pwd).hexdigest()
test('hello', 50000)
""", setup='import hashlib')
print t.timeit(100) / 100
>>> 0.126629960537If you wanted to "upgrade" the passwords to the higher cost key schedule, you'd just continue the key schedule where it left off--but this would require knowing the original password! So that's not really an option.
Of course we're 'overthinking' it again, but is the above solution viable?
new_hash = (bcrypt new_work_factor) . old_hash -- new hashing function
new_hashed_passwords = map bcrypt old_hashed_passwords -- convert the old hashed passwords to new
Of course, this will fail horribly if (bcrypt new_work_factor) is somehow an inverse (or partial inverse) of old_hash. It could also fail horribly if (bcrypt new_work_factor) maps it's input into a low "rank" (sorry, I'm a mathematician, not a crypto expert) region of old_hash's domain.My gut instinct would be to do just that but I wonder if there's a better way. You'd probably also want to track the encryption of each user so you know when you can make the final switch.
Another alternative is to just send "update your password" emails to everyone framing it as an improvement to your site's security.
I guarantee everyone with a decent spamfilter will miss those e-mails - that looks exactly like a standard phishing attempt.
Simply use the existing MD5/SHA1 hash as input to bcrypt and update all password hashes in your database in one go. Then, whenever the user logs in you first apply the old hash function followed by bcrypt before comparing with what you have in the DB.
But then Eli Biham used the term extensively in his HAIFA framework and I lost the argument. I'll still make fun of the word (salt! smoked salt! peanut salt! hah!), but I can't say no crypto people use it. I wish they wouldn't, though.
The source code to the hashing algorithm means nothing. It is already open source!
The reason that the salt is there is to prevent against rainbow tables.
The salting did NOT become useless. If they had not salted passwords, then many many more passwords would have been broken because instead of having to brute force each and every one, you'd just look it up in a massively large hash table.
On the first day, people stored passwords in plain text. If someone got access to your database, they had all the passwords.
On the second day, people decided to hash the passwords so that people couldn't unencrypt them. Then the attackers created rainbow tables that correlated each hash with its associated password since the password would always hash to the same value (so you have "109BCA" in your database, but they have a table that has that hash and that "12345" hashes to that value).
On the third day, people decided to salt the hashes to render the rainbow tables ineffective. Now, each password would hash to a different value so they couldn't just look up the password for a given hash. However, as computing power increased it became easy to just brute-force the password. You have the hash and you have the salt so you can just try every password with the hash until you get a match.
hashed_password = "ACBDEF1234567890"
salt = "12345"
possible_passwords = ["password1", "ilikesheep", "micro$oft"]
possible_passwords.each do |pass|
if Digest::SHA1.hexdigest("#{pass}#{salt}") == hashed_password
real_password = pass
end
end
The problem is that code like that has gotten really cheap to run and it's incredibly parallel (you can have loads of machines each take a piece of the workload - oh, and hopefully no one will make a joke that you'd never write that in Ruby; I just felt that would be easy pseudo-code to demonstrate). You can just try combinations of passwords at random, but there are lists of more common passwords that you can try first making it go even faster. Hashing algorithms are meant to be fast because they're meant to be usable on a large piece of data. As such, it also becomes fast to brute force check all sorts of combinations.On the fourth day, people started using things like bcrypt because bcrypt was made to be slow. The fact that bcrypt is slow means that if someone wants to brute force it, it will be very slow going for them. If one can check 10,000 SHA1 hashes in a second, but only 10 bcrypt hashes in a second, it will take 1,000x longer to crack the bcrypt stored password (those are just made-up numbers as an example).
Salting is better than not salting because they have to brute force the password. However, as computing power increases it isn't so much better because brute forcing is becoming easy. One needs to use a slow algorithm to make sure that cracking it will also be slow (prohibitively slow). Bcrypt also allows you to specify how much work you want it to have to do. This way, as computing power increases, you can increase the amount of computing power needed to compute the bcrypt. By contrast, hashes are meant to go fast and so every day they're getting less secure.
Not exactly. I could have a rainbow table for every possible password eight characters or fewer, and find it in a rainbow table in log(table_size) but to brute force it might take several days. GPUs make it so you can generate bigger rainbow tables faster too.
These are unsalted, md4 hashed, unicode strings.
They are fast and easy to crack if you ever do get your hands on them. The point is that many big companies don't do passwords right, so why expect Gawker to do so?
Edit: md4 is not a typo. They use md4 not md5... OK.
If you start out now with some given cost factor, that is unfeasibly breakable with modern hardware, that factor will remain stored somewhere, presumably in the database. Once computing hardware speeds up to the point that your factor is now practical to break, you can increase the cost factor for new passwords, but older ones remain susceptible to cracking. The only option would be to re-encode them periodically with the new factor to keep them secure.
Can anyone clarify if I've understood this correctly, or if I'm missing something fundamental about bcrypt? I've looked over the usenix paper, but I can't see anything obvious to confirm one way or the other.
* it has to be dog slow (to make brute forcing hard)
* it should be complicated enough to avoid collisions (this really applies to most hash functions)
* it should be suitably salted, to avoid rainbow tables
-> bcrypt is designed like this, if in doubt, use it
If you need yours users account to be safe just force them to use a strong enough password
hashed(password + salt) = epic win
Sorry mate but your method sounds easily exploitable ... heck using reCaptcha would be less punishing for the user than your approach.
EDIT: Oh, you mean it was similar to other submissions. Fair enough.
dg76fb23S for Facebook, dg76fb23S for hacker news
Been working great for years :)
And if someone ever sees these in plaintext, it's trivially extrapolate-able to other sites. Dunno.
So you use the same password for everything.
This key could be generated in real time and would not be displayed anywhere on the form and will be transferred in stealth mode to the server.
With no passwords to enter or transmit, there will be nothing to hack.... If the key generated in origin is itself a strong key decrypting information stored on the server will require first hacking the key which if not stored on the server in the first place will make life hell for hackers as they will require access to the individual devices as well.
Cheers, gurudatt
There's a long history of ``clever new ways'' to use existing crypto algorithms turning out to have serious flaws -- a good example is early attempts to improve the strength of (56-bit key) DES by encrypting three times with three keys. This turns out to introduce enough non-randomness to make the result much weaker than one might expect; standard 3DES works by encrypting with the first key, decrypting with the second, and encrypting with the third, which results in very different properties of the output cyphertext.
I'm not saying BCrypt has the same sort of issues, but I'd like to see some cryptanalysis of this before trusting my users' data with it. Notably, there seems to be no links to such analysis on the BCrypt home page -- not even an argument from the author as to why this code should be cryptographically sound.
Bcrypt is backed by Blowfish, designed by Bruce Schneier. Go look it/him up. It's secure.
MD5/SHA1/etc are not weak because they are cryptographically weak (though some are), it is weak because they are fast. SHA3, when it is picked, will still be a very bad choice because it too will be fast.
So, why Bcrypt? Well, it uses Blowfish. Blowfish has a very slow key scheduling algorithm which basically involves a lot of hashing to get the round subkeys. Bcrypt makes this even slower. So what? Well, with Bcrypt you could set it up to take .3 seconds to verify a password. Try bruteforcing on that.
Again, an example of this is the 3DES encrypt/decrypt/encrypt process vs. a more naive encrypt/encrypt/encrypt process. One is substantially stronger than the other. One is a secure way to use DES, and one is not.
Schneier all but disavowed _Applied Cryptography_ in _Practical Cryptography_.
Schneier's reputation as a cryptanalyst is, as even he might concede at this point, somewhat outstripping his actual career.
Bcrypt is part of the academic literature; the people who wrote it are both renowned.
You can make your same critique about any other crypto construction; maybe the OCB block cipher mode is unsafe! After all, Bruce Schneier didn't write it!
bcrypt is not an encryption algorithm. It doesn't "protect" your users' data, so there's no reason to trust or not trust it with their data.
If you don't believe me, consider this hash function
H(A) = (A>>1)&0xFFFFFFFF
There. Hash function. It sends any input to a 32 bit value. Would you use it for your password though? No. I certainly would not.
Granted, that is an incredibly weak example, but it's one that's easy to see why it's weak, and thus why a hash function does protect a user's data.
Well, yes, I trust the Blowfish cipher (and GP probably does too). The question is how we can be sure it isn't being somehow misapplied, i.e. whether the way bcrypt uses it opens some other hole. That's what I (and probably GP) would like to see an expert weigh in on.
(1) http://news.ycombinator.com/item?id=601408
(2) http://www.chromium.org/chromium-os/chromiumos-design-docs/p...
Edit: I defer to tptacek.
(b) There are operational reasons not to use scrypt, one of them being that there is no reference implementation with broad language bindings.
(c) The specific improvement scrypt makes over bcrypt is not yet relevant; nobody has ever hardware-optimized a bcrypt cracker, and the project that successfully does so and publishes their results will have made a contribution to cryptography literature.
(d) Even when bcrypt starts to face down hardware crackers, it doesn't "lose"; you simply have to increase work factors to compensate.
(e) You don't even have to use bcrypt; you can use PBKDF2, which simply iterates SHA1 a tuneable number of times. Bcrypt is better than PBKDF2, but every adaptive hash, PBKDF2 included, is in a different and better league than "salted hashes".
Sure they have. A hardware-optimized bcrypt cracker is called a GPU. I can buy a 480-core GPU on Newegg for $350, but it doesn't come with any more RAM than a low-end PC does.
First of all, none of this security even comes into play until after your password file is stolen, but your and jim's comments imply you believe that using bcrypt would somehow make an existing site less secure.
Given the same list of indexes, I can then "find" the salt of a stored password hash and run a given plain text password through that algorithm.
But, as has been stated, that effort is completely null if the SHA512 algorithm is fast and brute-forcing it only takes a handful of rented GPU instances...
[EDIT] Now that I think about it, if the Gawker attack were to happen to me, then the attackers would also have the source code and can get the salt dispersion list... So this is, in hindsight, kind of pointless.
This is essentially what bcrypt does for you anyway (in a really crude sense).
So yeah, SHA-512 gives you a much larger keyspace, which is awesome, but isn't demonstrably slower than MD5, SHA-1, etc. Which was one of its design goals (and also one of the goals of all entrants in the ongoing SHA-3 competition).
An HTML version appears to be here: http://www.usenix.org/event/usenix99/provos/provos_html/node... Some of the links, particularly the main page, appear to be broken.
This doesn't mean BCrypt is unsound. It does mean that I would want to see such analysis before using it.