views:

511

answers:

8

I need to store a hash of a single password in a .Net WinForms application.

What's the most secure way to do this?

In particular:

  • Salt, HMAC, or both?
  • How much salt?
  • How many iterations?
  • What encoding? (The password is plain ASCII)

I assume that the algorithm should be either SHA512 or HMACSHA512.

+3  A: 

RNGCryptoServiceProvider to generate a random salt, then SHA512 the password with the salt, and finally store both the password hash and the corresponding salt if you want to later verify that some text equals the stored password.

Darin Dimitrov
You don't think I should use HMAC, or use iterate the hash?
SLaks
In my opinion SHA-512 with random salt is strong enough. There's a nice article here http://www.aspheute.com/english/20040105.asp, just use SHA-512 instead of SHA-1.
Darin Dimitrov
HMAC introduces problems you don't need (Keys).
Noon Silk
bcrypt is a significantly better approach to this
Sam Saffron
+1  A: 

Hash and Salt. If you only hash you could be attacked by a rainbow attack (reverse has lookup) and a salt makes this much more difficult (random salt would be best.) For your encoding you will probably want to either Base64 or Hex encode your resulting byte array. If you just try to store the byte array as Unicode you could run the risk of some data being lost because not all patterns are valid characters. This also allows for an easier way to compare hashes (just compare the base64 or hex string when you want to validate instead of comparing the byte array)

An increased number of rounds doesn't do much beyond slowing down would be attackers. But is also makes is much more difficult to reuse the hashes in the future if you lose or need to recreate your hash algorithm. You might check out a standard password hash such as crypt on unix systems. This allows for you to change out the hash algorithm and can even support versioning.

But again, a simple hash + salt is good enough for most applications.

Matthew Whited
+3  A: 

For a server-side implementation with a large number of passwords, you should definitely use a tunable iterated approach like bcrypt. This well-known article on the topic is still (mostly) relevant:

http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html

For a single password in a stand-alone application, where the storage location is probably already secured by the system's own authentication system, I think it's much less important. A single strong hash is likely good enough, and adding salt is easy enough that there's no reason not to do so.

Tim Sylvester
+3  A: 

I can recommend BCrypt.net. Very easy to use and you can tune how long it will take to do the hashing, which is awesome!

// Pass a logRounds parameter to GenerateSalt to explicitly specify the
// amount of resources required to check the password. The work factor
// increases exponentially, so each increment is twice as much work. If
// omitted, a default of 10 is used.
string hashed = BCrypt.HashPassword(password, BCrypt.GenerateSalt(12));

// Check the password.
bool matches = BCrypt.CheckPassword(candidate, hashed);
Svish
A: 

Strictly looking at more secure:

Salt, HMAC, or both?

Both would be more secure. Since the key to the HMAC could be considered a salt, doing both would be a little redundant, but still more secure because it would take more work to crack.

How much salt?

Every bit of salt would double the combinations that would need to be maintained in a rainbow-table to easily crack the password. But since there is only one password, and only one salt, more may not be needed. The HMAC uses the block size of the underlying hash for its key size, 1024 bits for SHA512. The block size should be good enough for the salt, but doubling or tripling it would make cracking the password with a rainbow-table much, much harder.

How many iterations?

The more the better. Sure, more iterations means it will take longer to determine if the correct password was entered, but computers are fast and users will not mind waiting for a few seconds while verifying the password. Doing more iterations would mean that someone cracking the password would have to do more iterations too.

What encoding? (The password is plain ASCII)

Might as well encrypt (with AES) the over-iterated, over-salted, HMAC'ed, super-secure password along with its salt just to make it harder. Make the password for the encrypted password hash and key, be some combination of strings that should appear in the executable such as "RNGCryptoServiceProvider" or "System.Security.Cryptography". And while encoding we might as well convert it hex, or base64, or better yet base-36 or some other less expected conversion.

Note: This was mostly written in jest, but should still contain some truth.

gwell
A: 

I think you should stick with open standards. Among the current hash schemes, the "{ssha}" used by OpenLDAP is very secure and widely used. You can find the description here,

http://www.openldap.org/faq/data/cache/347.html

Most LDAP libraries implement this scheme.

ZZ Coder
+4  A: 

Salt your hash with secure random salt of at least 128bits or longer, to avoid a rainbow attack and use BCrypt.

To quote: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html

The problem is that MD5 is fast. So are its modern competitors, like SHA1 and SHA256. Speed is a design goal of a modern secure hash, because hashes are a building block of almost every cryptosystem, and usually get demand-executed on a per-packet or per-message basis.

Speed is exactly what you don’t want in a password hash function.

Fast password validation functions are a problem, cause they can be attacked using brute force. For BCrypt to become much faster it would require a break through in cryptography, something that is less likely to happen. Sure as CPU are getting faster so is BCrypt you have control over its slowness.

Sam Saffron
Speed very important part of message digest functions. NIST rules out slow message digests in their elimination process for choosing the next standard.
Rook
Sometimes I wonder if people read my answers before downvoting them
Sam Saffron
A: 

You could follow a published standard, like pkcs#5. see http://en.wikipedia.org/wiki/PKCS for a short description, or http://tools.ietf.org/html/rfc2898 for the RFC.

atk