Is BCrypt a good hashing algorithm to use in C#? Where can I find it?

58,108

Solution 1

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.

Solution 2

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.

Share:
58,108
Lemon
Author by

Lemon

Software Developer, Geek, HSP, SDA, ..., open, honest, careful, perfectionist, ... Currently into indoor rowing and rock climbing, just to mention something non-computer-related... Not the best at bragging about myself... so... not sure what more to write... 🤔

Updated on July 08, 2022

Comments

  • Lemon
    Lemon almost 2 years

    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?

  • Jacco
    Jacco about 13 years
    maybe add to your salt paragraph that a salt must be randomly choosen
  • George Stocker
    George Stocker about 13 years
    @Jacco Good call, added. Although that's not that important. You could simply use the timestamp of the login for the salt. The difference it makes is that the attacker then needs to recompute the rainbow table for each salt. That's what makes it difficult, not that it's randomly chosen. Making it random would add another layer of obsfucation, but that's useless once the attacker is able to see your database (which is the problem that causes all of our heartache in the first place).
  • Jacco
    Jacco about 13 years
    Not really, the salt does not have to be secret, the just unique for each instance. Since unique (as in world-wide) is not possible, random is the next best thing. Also, timestamp is not a good salt as there is not enough entropy.
  • Piskvor left the building
    Piskvor left the building almost 13 years
    To quote the linked comment: "[we] moved to PBKDF2 as it is built into the .NET framework, whereas BCrypt would require us to verify an implementation". Note that the comment doesn't say the algorithm is better, just that SE Dev Team considers the built-in PBKDF2 implementation more trusted than an external library (which is, ultimately, a judgement call).
  • Chris Marisic
    Chris Marisic almost 13 years
    @Piskvor I updated my answer. This isn't about what the SO team considers secure but a judgement call between inherently proven secure or hopefully secure. The latter when it comes to cryptography is unacceptable.
  • jammycakes
    jammycakes almost 13 years
    I'd take issue with your statement "If they can successfully use XSS or SQL injection, good password security doesn't matter." On the contrary, if they can successfully XSS or SQL inject your site, good password security is even more important. The key here is "defence in depth" -- you should tighten security as far as is practical at every layer of your application.
  • Keith
    Keith almost 12 years
    I'd add to this that the purpose of BCrypt/SCrypt above and beyond key-stretching (which PBKDF2 does fine) is to also force the usage of a significant amount of memory, which in turn reduces the amount of attempts that the same hardware can make in parallel. While this is great for really secure passwords it could also have performance issues in a shared environment where users log in concurrently. There's a whole layer of performance testing required for a BCrypt implementation over PBKDF2.
  • CMircea
    CMircea almost 11 years
    @Keith, BCrypt requires very little memory. Only SCrypt requires significant amounts.
  • martinstoeckli
    martinstoeckli almost 11 years
    Just to make it more clear, verification can either mean the algorithm (BCrypt) is verified, or its implementation (.NET code) is verified. The implementation can be tested easily, just compare the result with other implementations, if the result is the same, and therefore correct, then no backdoor can be hidden inside. The cryptographic security comes from the algorithm, not from the implementation, so as long as a library returns the correct hash-value you can safely use it. One point to take care of is, when the library also creates a unique salt itself.
  • Chris Marisic
    Chris Marisic over 10 years
    @martinstoeckli the issue is about verification of the implementation AND algorithm. Just because you can input x get y out in 2 implementations doens't mean that impl2 isn't leaking information that totally compromises security. An unverified implementation could literally do WebRequest.Send(salt, key, text); return verifiedImplementation(salt, key, text)
  • Dharmendar Kumar 'DK'
    Dharmendar Kumar 'DK' over 10 years
    I wonder how SO migrated all the bcrypt hashed passwords to the new hashes? Wouldnt they need the raw passwords to hash it using the new algorithm?
  • George Stocker
    George Stocker about 10 years
    @DK One way I've done it in the past is when people log in, ask them to reset their password, store the new password in the new hashing algorithm.
  • teashark
    teashark almost 10 years
    @DK I don't even think you have to ask them to reset their passwords. On next log in (where they supply their plaintext password) you can do it I believe.
  • Chris Marisic
    Chris Marisic almost 10 years
    @Piskvor added information citing the recent heartbleed hack. Verification is not "a judgement call" it is either secure or insecure, by definition.
  • George Stocker
    George Stocker over 9 years
    @jammycakes Absolutely; my point was lost: You can't just say, 'Hey, we hash and salt our passwords, "we're ok"!'
  • BatteryBackupUnit
    BatteryBackupUnit over 8 years
    @ChrisMarisic so you really believe that one can perform a verification and then be a 100% sure that's it is secure?
  • Chris Marisic
    Chris Marisic over 8 years
    @BatteryBackupUnit that's not verification ensures. Verification ensures that there is no mathematical / cryptographical fault in the implementation of the algorithm to its specification. Many verified implementations are worthless now that the entire algorithm was invalidated early SHA-# algorithms and MD5 off the top of my head. This is exactly the heart-bleed issue, it's not that SSL is insecure (although several flavors are) it was an error in the implementation that defeated the entire security in a spectacularly awful way exposing direct memory reads to internet connected servers.
  • Polynomial
    Polynomial over 7 years
    This is poor advice and I am surprised it has so many upvotes. Verifying a BCrypt implementation in a managed language is much, much more trivial than verifying something like an entire SSL implementation in C. Heartbleed is completely irrelevant; you'd be better off mentioning something like PHP type coercing problems with hash equality checks. Plus while largely suitable in a practical sense, PBKDF2 is a KDF, not a password hashing algorithm, whereas BCrypt is better suited. Regardless, it would make much more sense to use Argon2 these days anyway, for which there is a well-tested C# library
  • KeithS
    KeithS about 7 years
    One very important point to make about BCrypt. It's not just slow, it's configurably, exponentially slow. It was designed specifically to keep up with Moore's law. SHA/AES are actually designed to be fast while remaining secure, because the plaintexts are thought to have high entropy. BCrypt's forte is password hashing because it can use algorithmic complexity as a substitute for low input entropy.
  • phil soady
    phil soady about 7 years
    suggest you read this thread before deciding what is a good hashing algorithm to use. in c# security.stackexchange.com/questions/35250/…
  • TrueWill
    TrueWill almost 7 years
  • Corrodias
    Corrodias over 5 years
    What evidence exists that Rfc2898DeriveBytes has been cryptographically verified on all supported platforms? As I understand it, all of the FIPS-certified algorithms' names end with "CryptoServiceProvider" or "Cng", which this does not. But then, it's not a hashing function but a pseudorandom generator that uses a hashing function, so perhaps it doesn't need to, but then we're back to the question of, how can we tell whether it's verified?
  • Chris Marisic
    Chris Marisic over 5 years
    @Corrodias the publication from NIST is proof. It's included in the second sentence.
  • Corrodias
    Corrodias over 5 years
    @ChrisMarisic The link is broken, but I found the document. It unfortunately only talks about the algorithms; it says nothing about C# or the .NET Framework's implementations of those algorithms, which was my concern. The claim being implied by Kevin Montrose - and you - that I'm trying to validate is that the .NET implementations of these have been verified.
  • Chris Marisic
    Chris Marisic over 5 years
    @Corrodias this seems to be the best proof support.microsoft.com/en-us/help/811833/…
  • Corrodias
    Corrodias over 5 years
    @ChrisMarisic Mm, yes. I wish MS would explicitly say whether their Rfc2898DeriveBytes is certified. It only explicitly mentions that "The names of these classes end in "CryptoServiceProvider" or "Cng."" (which implies that it is not certified), but I suppose it does at least provide a means by which you can check for sure, that is, set the OS option to allow only FIPS-certified algorithms and then try to run a program that uses PBKDF2 and the hasher of your choice.
  • Ryan Haney
    Ryan Haney over 4 years
    "Even with all this, you've got to be using good security practices." Don't forget OS, web server and ISP vulnerabilities. We're all basically screwed.