132
votes

I have read that when hashing a password, many programmers recommend using the BCrypt algorithm.

I am programming in C# and is wondering if anyone knows of a good implementation for BCrypt? I found this page, but I don't really know if it is bogus or not.

What should I be aware of when choosing a password hashing scheme? Is BCrypt a 'good' implementation?

2

2 Answers

153
votes

First, some terms that are important:

Hashing - The act of taking a string and producing a sequence of characters that cannot be reverted to the original string.

Symmetric Encryption - (Usually just referred to as 'encryption') - The act of taking a string and producing a sequence of characters that can be decrypted to the original string through the use of the same encryption key that encrypted it.

Rainbow Table - a lookup table that contains all variations of characters hashed in a specific hashing algorithm.

Salt - a known random string appended to the original string before it is hashed.

For the .NET Framework, Bcrypt does not yet have a verified reference implementation. This is important because there's no way to know if there are serious flaws in an existing implementation. You can get an implementation of BCrypt for .NET here. I don't know enough about cryptography to say whether it's a good or bad implementation. Cryptography is a very deep field. Do not attempt to build your own encryption algorithm. Seriously.

If you are going to implement your own password security (sigh), then you need to do several things:

  1. Use a relatively secure hash algorithm.
  2. Salt each password before it's hashed.
  3. Use a unique and long salt for each password, and store the salt with the password.
  4. Require strong passwords.

Unfortunately, even if you do all this, a determined hacker still could potentially figure out the passwords, it would just take him a really long time. That's your chief enemy: Time.

The bcrypt algorithm works because it takes five orders of magnitude longer to hash a password than MD5; (and still much longer than AES or SHA-512). It forces the hacker to spend a lot more time to create a rainbow table to lookup your passwords, making it far less likely that your passwords will be in jeopardy of being hacked.

If you're salting and hashing your passwords, and each salt is different, then a potential hacker would have to create a rainbow table for each variation of salt, just to have a rainbow table for one salted+hashed password. That means if you have 1 million users, a hacker has to generate 1 million rainbow tables. If you're using the same salt for every user, then the hacker only has to generate 1 rainbow table to successfully hack your system.

If you're not salting your passwords, then all an attacker has to do is to pull up an existing Rainbow table for every implementation out there (AES, SHA-512, MD5) and just see if one matches the hash. This has already been done, an attacker does not need to calculate these Rainbow tables themselves.

Even with all this, you've got to be using good security practices. If they can successfully use another attack vector (XSS, SQL Injection, CSRF, et. al.) on your site, good password security doesn't matter. That sounds like a controversial statement, but think about it: If I can get all your user information through a SQL injection attack, or I can get your users to give me their cookies through XSS, then it doesn't matter how good your password security is.

Other resources:

  1. Jeff Atwood: .NET Encryption Simplified (great for an overview of hashing)
  2. Jeff Atwood: I just logged in as you
  3. Jeff Atwood: You're probably storing passwords incorrectly
  4. Jeff Atwood: Speed Hashing

Note: Please recommend other good resources. I've must have read a dozen articles by dozens of authors, but few write as plainly on the subject as Jeff does. Please edit in articles as you find them.

75
votes

You must not use BCrypt in .NET. You must use PBKDF2 as is with the built in .NET framework implementation. It is the only freely available cryptographically verified implementation in .NET along with being the algorithm recommended by NIST.

StackId previously used BCrypt and moved to PBKDF2 for this very reason:

For those curious, we’re hashing passwords with PBKDF2. Relavent code is here ( http://code.google.com/p/stackid/source/browse/OpenIdProvider/Current.cs#1135 ), through a few layers of indirection. In an earlier iteration, we were using BCrypt; but moved to PBKDF2 as it is built into the .NET framework, whereas BCrypt would require us to verify an implementation (no small undertaking).

Kevin Montrose, May 27 2011

(Updated link on GitHub)

Edit: The meaning of verified in cryptographic terms seems to not be readily understood, a verified implementation means it's been cryptographically proven to be implemented without error. The cost of this can easily reach $20,000 or higher. I recall this when I was doing research on OpenSSL and read where they stated they haven't completed the entire verification process but if you need fully verified that they can point you down the right path for it and mentioned costs associated. Certain government requirements include mandates for verified encryption algorithms.

The bcrypt implementations in .NET have not been verified. Using an unverified encryption implementation you can't be absolutely certain that there is not either intentional malicious faults in it such as allowing a backdoor into what is encrypted or unintentional implementation faults that result in cryptographically insecure data.

2014 edit: For anyone that questioned the imperativeness of using verified cryptopgraphical algorithims look at the devastation that was wrought by the heartbleed hack exploited in OpenSSL. That is the cost of using an unverified implementation. It's secure.... until you find out that any person can just read the entire memory contents of your server.

The author of the change which introduced Heartbleed, Robin Seggelmann, stated that he "missed validating a variable containing a length" and denied any intention to submit a flawed implementation. Following Heartbleed's disclosure, Seggelmann suggested focusing on the second aspect, stating that OpenSSL is not reviewed by enough people.

This is the definition of an unverified implementation. Even the smallest defect can result in crippling the entire security.

2015 edit: Removed recommendation based language and replaced with absolutes. Embedded original Kevin Montrose comment for posterity.