Hi, I'm Tony Arcieri. You may remember me from such software projects as Celluloid, Reia, and Cool.io...

Monday, March 19, 2012

Don't use bcrypt

(Edit: Some numbers for you people who like numbers)

If you're already using bcrypt, relax, you're fine, probably. However, if you're looking for a key derivation function (or in bcrypt's case, password encryption function) for a new project, bcrypt is probably not the best one you can pick. In fact, there are two algorithms which are each better in a different way than bcrypt, and also widely available across many platforms.

I write this post because I've noticed a sort of "JUST USE BCRYPT" cargo cult (thanks Coda Hale!) This is absolutely the wrong attitude to have about cryptography. Even though people who know much more about cryptography than I do have done an amazing job packaging these ciphers into easy-to-use libraries, use of cryptography is not something you undertake lightly. Please know what you're doing when you're using it, or else it isn't going to help you.

The first cipher I'd suggest you consider besides bcrypt is PBKDF2. It's ubiquitous and time-tested with an academic pedigree from RSA Labs, you know, the guys who invented much of the cryptographic ecosystem we use today. Like bcrypt, PBKDF2 has an adjustable work factor. Unlike bcrypt, PBKDF2 has been the subject of intense research and still remains the best conservative choice.

There has been considerably less research into the soundness of bcrypt as a key derivation function as compared to PBKDF2, and simply for that reason alone bcrypt is much more of an unknown as to what future attacks may be discovered against it. bcrypt has a higher theoretical-safety-to-compute-time factor than PBKDF2, but that won't help you if an attack is discovered which mitigates bcrypt's computational complexity. Such attacks have been found in the past against ciphers like 3DES. Where 3DES uses a 168-bit key, various attacks have reduced that key size's effectiveness to 80-bits.

PBKDF2 is used by WPA, popular password safes like 1Password and LastPass, and full-disk encryption tools like TrueCrypt and FileVault. While I often poke fun at Lamer News as a Sinatra antipattern, I have to applaud antirez on his choice of PBKDF2 when he got bombarded with a "just use bcrypt!" attack (although bro, antirez, there's a PBKDF2 gem you can use, you don't have to vendor it)

The second cipher to consider is scrypt. Not only does scrypt give you more theoretical safety than bcrypt per unit compute time, but it also allows you to configure the amount of space in memory needed to compute the result. Where algorithms like PBKDF2 and bcrypt work in-place in memory, scrypt is a "memory-hard" algorithm, and thus makes a brute-force attacker pay penalties both in CPU and in memory. While scrypt's cryptographic soundness, like bcrypt's, is poorly researched, from a pure algorithmic perspective it's superior on all fronts.

The next time you need to pick a key derivation function, please, don't use bcrypt.

@CaStarCo: A simple cryptpass = salt + SHA256(salt + cleartextpassword) is exactly as easy to brute force crack as cryptpass = SHA256(cleartextpassword) for a single password. Now the unsalted is more vulnerable to attacking multiple passwords in a database at once as everyone using the same password will be cracked simultaneously, while the salted, if the salt is good, will only crack the one.

The benefit of PBKDF2, bcrypt, and scrypt is the added cost of multiple iterations that ramp up the offline brute-force attack cost, making them far more secure than even salted hashes.

First of all bcrypt is not a cipher, it's a key derivation function. That might seem nitpicky, but their use cases and attack scenarios differ wildly.With a cipher, you usually have many plaintext, ciphertext pairs and want to find the key encrypting the plaintext to the ciphertext (so that you canthen decrypt ciphertexts for which you don't have plaintexts). With a key derivation function you usually have a low entropy input and want to create an output that is computationally difficult to distinguish from high entropy output. Such a low entropy input can be a password whose key space is usually very small. Thus a KDF in our context has to be slow to compute, and only with the reference implementation, but with any implementation. "Breaking" such a KDF means finding a short cut that allows significantly faster computation than with the reference algorithm.

Next, why do you assume that bcrypt has had less cryptoanalytical scrutiny than PBKDF2. Both are about the same age. In fact one of the reasons bcrypt is often mentioned as a good choice is because it has aggregated a lot of trust over the last 13 years. Also there are a lot of bad examples in the use of PBKDF2, which mostly stem from too low iterations count. TrueCrypt, which you mention as one of the examples why PBKDF2 is trustworthy, is an especially bad at choosing reasonable parameters: They only use an iteration count of 1000 for most hashes (see http://www.truecrypt.org/docs/?s=header-key-derivation). The PBKDF2 values in the table you copied from http://www.tarsnap.com/scrypt/scrypt.pdf were calculated with an iteration count of 86000 (first entry - "100ms") and 4,300,000 (second entry - "5.0s")! WPA, an other example you mention, is also notoriously bad at using good iteration counts. That's the reason dictionary attacks on WPA-PSK have become so popular. I agree with Blair Strang here, that one of the main advantages of bcrypt is that there is much better documentation available and implementations have better default values.

A side note on the 3DES attacks. Technically, yes, you can use a 3DES keying option whose key size is 168. But nobody ever argued, that the actual strength of the cipher was 168 bit. In fact one of the first things you read about Triple DES is that its actual strength is in really at most 112 bit, because of a meet-in-the-middle attack that's inherent in its design. And the "attack" you mention that reduces it to 80 bit does not even apply to normal use cases of 3DES (take a look at the paper that's linked in the Wikipedia article) and it definitely has no application concerning KDFs. Actually 3DES is an example of an old algorithm, that is still one of the strongest available. The main reason everyone switched to AES was that it was by far faster.

If you want to be on the safe side with password hashing I, you can diversify your choice: Let p be your password and SaltI be 128 bit random values. Derive p_1 = HMAC(Salt1+"PBKDF2") with key sha256(p), p_2 = HMAC(Salt2+"bcrypt") with key sha1(p) and p_3 = HMAC(Salt3+ "scrypt") with key sha1(p). Derive key k1, k2 and k3 by using the key derivation function PBKDF2, bcrypt and scrypt respectively, each of them using 1/30 seconds CPU time with input p_1, p_2 and p_3 respectively. Compute the key (or database reference entry) as sha256(k1+k2+k3). Here "+" designates the concatenation of byte arrays. This way you get the best of all worlds: A proven bcrypt, an experimental but very promising scrypt and a traditional PBKDF2. The important aspect, is that you tweak the parameters of each KDF such that they take long to compute (that's why I proposed 1/30s CPU time). Then your KDF is as strong as the strongest of the three.

@Tibor Sekelj Wrong, read it again. You have to be able to crack all 3 algorithms to get the password.

The drawback to the approach of using 3 algorithms though, is that you can only use 1/3 of the work factor for each, so if by magic 2 of the 3 are totally compromised, the third algorithm is much faster to crack. Which in theory should still be really hard, but just pointing it out.

I think some of this concerns look a bit silly. All KDF was designed to solve something that unsolvable at first.

All algo is just an attempt to postpone the problem. None is future proof.

All KDF concern about computational resources so they add some kind of workload parameter to tune the alogos.

This approach sound just like an arm wrestling. (Let see who is the strongest one.)

In reality all computers are not grow in CPU speed or memory capacity altogether. What really matter is resources gap between low end servers and high end super computers. The gap is wider as the time pass. In near future renting a cloud computing power can be cheap but we still use the same old school servers. (The hash compare verification is not suitable for offline system at first.)

So I think we should just pick one promising algorithm, pick one magic number as workload parameter and the salt.

Never change them and admit that we are lost. (In computational power racing with open algorithm standard. I don't think one can win by brilliant algorithm solutions.)

The good thing is offline bruteforcing is the worst case scenario when a server leaks password hash. It isn't leak if other security systems are functional correctly. And attacker probably just got only hash collision version of password.

If users is not reusing the same password for everything. I think that should be suffice but if not the user is vulnerable to services owner of everything they use at the beginning.

KDF is just a tools that limit some more criteria to attackers.For example you can specify that only NSA and Jeff Bezos or someone along the line can crack the password not others.And of course common criteria of attackers is the one that can also obtain password hash value.

P.S. The KDF in one user scenario is another story (eg. generating symmetric cipher key to encrypt an offline file.) you can make it as slow as a few seconds.

I was very pleased to find this web-site. I wanted to thanks for your time for this wonderful read!! I definitely enjoying every little bit of it and I have you bookmarked to check out new stuff you blog post. Back Office Support Services