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.

14 comments:

Singpolyma said...

I think the point of "just use bcrypt" is "don't use (even salted) sha1/sha2"

Blair Strang said...

Hi,

The reason I usually recommend bCrypt is actually due to the human factors involved; essentially, bindings are available for every language, the API is consistent and fairly foolproof.

Usually we don't need "optimally secure" hash functions, we just need "good enough to be indistinguishable from best practice" and bCrypt fits the bill here fine.

Lukas Ĺ alkauskas said...

Implementation in Python here: https://github.com/dotpot/Crypton

CaStarCo said...

@Singpolyma Why not salted sha1/sha2? Thanks in advance.

Astounding said...

@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.

yawn said...

@CaStarCo

google hashcat - it will crack your password in 2 seconds or so, with or without salt :-)

Twister said...

How would you respond to this post?

http://www.labnol.org/internet/unique-password-for-every-site/21288/

I am just a follower of the above blog, I just want to know your opinion.

perseids said...

I'm sorry, but you're wrong in almost all your points.

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.

lee x said...
This comment has been removed by the author.
lee x said...

why does the 40 char text requre less money then 10 char text to brake in the same time ?

(could not edit)
i guess they got the 10 char and 40 char box mixed up

Adrie Donker said...

There's a nasty mistake in the documentation on github. It states you should: include 'scrypt'. This should be: include SCrypt. Took me half an hour to find out.

mmn said...

I really don't understand the argument for bcrypt. There's no problem in setting the rounds in ordinary crypt() for SHA-512 etc, right?

crypt('abc123', '$6$rounds=1234$mysaltysalt$');

That will do 1234 rounds of SHA-512. Now what's the point of bcrypt, which can only handle Blowfish hashes?!

dan thornbury said...

Use bcrypt, don't use bcrypt. To hell with it; I'm sticking with unsalted md5!

Tibor Sekelj said...

Wrong, your password is always only as strong as the weakest one if the three

What is no where mentioned is how does bcrypt with compare with pbkdf2 using sha512

Isn't bcrypt per se less secure as it uses a shorter bit length?

In terms of "cost" you can ramp up pbkdf2 iterations. Wouldn't that be enough?