7

Does anyone have a reference implementation (ideally 3rd party certified, or government approved) way one-way hash a password for C# and or Java?

Ideally,I'd like to see something that includes a "salt and pepper" technique as mentioned here as well as any other modern security technique for validation that might be applicable.

The content I want to protect is information the user can remember, such as a password, or the answer to a challenge question.

If you don't have a complete code sample, a general description of which algorithm you would choose, and example methods of salting and peppering would be helpful.

makerofthings7
  • 50,488
  • 54
  • 253
  • 542
  • The term "password storage" is wrong for what you seem to be looking for. You want to store something that lets you verify that the user can produce the right password or secret. But it is not enough to produce the password itself for use elsewhere (which is a good thing). Assuming that is true, can you fix it here and other places you've used it? – nealmcb Feb 13 '11 at 01:38
  • @nealmcb - Done, let me know of other spots that are not worded right and I'll clarify the language. – makerofthings7 Feb 13 '11 at 03:07
  • In your edit, do you mean to say "US government approved"? – nealmcb Feb 16 '11 at 20:24
  • @nealmcb FIPS is just an example of an approval and verification. It would be nice to see what other approvals exists, and draw a consensus if any. – makerofthings7 Feb 16 '11 at 21:58
  • Although I have accepted an answer I'm still interested in other trusted methods to store and encrypt a password, and any corresponding validation that may exist. – makerofthings7 Feb 16 '11 at 22:03

3 Answers3

5

Given your new "government approved" requirement, my guess is that one good solution would be PBKDF2 from RFC 2898. It is implemented for .NET in Rfc2898DeriveBytes Class (System.Security.Cryptography). You presumably want to substitute SHA-256 for SHA-1 in there.

I also just ran across the Fairly Secure Hashed Password: fshp which is like PBKDF1 but with SHA-256 by default. It supports a variable number of iterations, defaulting to 4096. It uses 64 bit salts. They have implementations there for .NET, Python, Ruby, Perl, PHP5, Java and JavaScript.

As described and discussed at .net impl of bcrypt - Stack Overflow, it seems that for .NET/CLR another good option (though not NIST-approved) is BCrypt.net:

and for Java a good option is

I guess neither seems to have the "pepper" concept, or the space complexity of scrypt.

nealmcb
  • 20,693
  • 6
  • 71
  • 117
  • Thanks for adding the PBKDF2 class. I wasn't clear that it existed in .NET or that this RFC-Named class was newer/better than PasswordDeriveBytes. Thanks a ton! – makerofthings7 Feb 16 '11 at 22:02
2

The basics

The basic approach is Hash(secret | salt), which is stored along with the salt. Obviously it's important to use a modern hash algorithm like one of the SHA2 variants (though currently SHA1 is not totally broken like MD5 is). Note that if you are storing challenge questions this way, you probably want to Trim() and ToLower() the secret before hashing it. This may reduce the complexity somewhat, but security questions aren't intended to have high entropy like a password anyway.

What about brute-force attacks like Rainbow tables?

Concerns about brute-force attacks can be mitigated in two ways:

  1. Require a minimum amount of entropy in the secret (length, complexity, etc.).
  2. Increase the amount of computation required to perform the hash.

The method used in bcrypt is a good improvement on standard hashing because it increases the amount of time to calculate the hash by many orders of magnitude. Basically, it just iteratively hashes the secret many times: Hash(Hash(...Hash(secret | salt)...))

Because the amount of time is still relatively small (hundreds of milliseconds), it does not add an intolerable delay to the legitimate user. But it can ruin automated brute-force attacks.

That's not good enough

If the additional difficulty of bcrypt is insufficient, try scrypt. It works like bcrypt but needs to save each iterative hash in memory for a final merge at the end. This adds the same time complexity as bcrypt but also increases space complexity, making it more difficult to implement in hardware, especially in parallel.

Implementation

Honestly, I'm not aware of a C# library to implement this, let alone one "certified" by some official body, but it wouldn't be too difficult. Assuming you write thread-safe code, and the password verification takes place on a trusted system like a server, implementation concerns like side-channel attacks are minimized.

Further reading: This answer to Is BCrypt a good encryption algorithm to use in C#? Where can I find it?

Justin Morgan
  • 436
  • 2
  • 6
  • Thanks! I heard somewhere that `ToUpperInvariant()` is more reliable in cross-culture comparisons of strings instead of `ToLower()`. What do you think? – makerofthings7 Feb 12 '11 at 20:39
  • Any case elimination function will work in the general case. I'll be the first to admit that I'm no expert in i18n, so I'd love to hear more about why `ToUpperUnvariant()` is better. In this case it probably doesn't matter much, because you're comparing two strings typed by the same person. Presumably, they typed it the same way both times. – Justin Morgan Feb 12 '11 at 22:08
  • 1
    Here is a link regarding `ToUpper()` http://blogs.msdn.com/b/deeptanshuv/archive/2004/09/04/225720.aspx and another http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html – makerofthings7 Feb 13 '11 at 08:34
  • I learn something every day. FWIW, it seems like `ToLowerInvariant()` is equally valid. – Justin Morgan Feb 13 '11 at 12:44
  • 1
    Just something worth noting. I often see references to md5 being totally broken. It has collisions. This is not the same thing as being totally borked. While I would use sha1 or better given the opportunity, I would like to see an md5 collision that allows malware in an iso for example. Just thoughts. – RobotHumans Feb 13 '11 at 20:04
  • MD5 is quite broken. Here are some examples, including benign and malicious programs with the same MD5 hash, and two different programs with the same Microsoft Authenticode signature: http://www.mscs.dal.ca/~selinger/md5collision/ It's not a huge leap to .iso files. If you want to prevent inadvertent changes like transmission errors, MD5 is just fine, but that's about it. – Justin Morgan Feb 13 '11 at 22:03
  • @justin: Nevertheless, @aking1012 is right in that the collisions you cite can only be produced by someone who can manipulate both the "good" and the "bad" thing-to-be-hashed. Someone who can do that in the password context already has some pretty powerful access to the password storage process and may well be able to just make a copy of the original password. There are still no preimage attacks published on MD5, so you can't take the hash of an existing password and produce another password with the same hash. Nevertheless MD5 is indeed a needlessly risky choice, to say the least. – nealmcb Feb 15 '11 at 02:43
  • Thanks for the links. After further thought and research I think the crypto implementation should be vetted by a 3rd party. Do you know of any FIPS approved BCrypt or SCript implementation? – makerofthings7 Feb 16 '11 at 20:04
  • 1
    To my knowledge, FIPS has not approved any method for password storage. FIPS 800-3 defines secure hashing, but basically just says "use SHA1 or SHA2". As far as the government is concerned, bcrypt and scrypt are just academic. – Justin Morgan Feb 17 '11 at 03:12
  • *"I'm not aware of a C# library to implement this [...] but it wouldn't be too difficult"* - noooo :). The first advice from all security authorities (like OWASP) is **"Do not implement your own!"**... Use the .NET Framework [Security](https://docs.microsoft.com/en-us/dotnet/api/system.security?view=netframework-4.7.2) or [Cryptography](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography?view=netframework-4.7.2) namespaces. – Ioanna Aug 29 '18 at 09:04
1

.Net answer:
According to this post all -Cng and -CryptoServiceProvider postfixed implementations from the .Net Cryptography Namespace should be FIPS-certified, as opposed to the -Managed versions.

Drawbacks:

Advantages:

  • They are FIPS-certified
  • The hashing algorithms use bcrypt
Ioanna
  • 166
  • 1
  • 10