18

Could you please advise me some easy algorithm for hashing user password by MD5, but with salt for increasing reliability.

Now I have this one:

private static string GenerateHash(string value)
{
    var data = System.Text.Encoding.ASCII.GetBytes(value);
    data = System.Security.Cryptography.MD5.Create().ComputeHash(data);
    return Convert.ToBase64String(data);
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • 5
    Why use a broken hash like MD5? At the minimum use something like SHA-256. – Greg Beech Aug 19 '09 at 15:53
  • 6
    Well, why NOT use MD5? Using a salt reasonably mitigates the vulnerability due to MD5's lack of collision resistance, no? – Eric Lippert Aug 19 '09 at 15:57
  • 1
    @Greg, could you please provide some example of using, with salt if applicable? – abatishchev Aug 19 '09 at 15:58
  • It's not the collision resistance. It's that it's been around long enough that there are optimized implementation that can quickly brute force a 'reversal'. – Joel Coehoorn Aug 19 '09 at 16:06
  • 1
    @Eric - Sure, it mitigates it to an extent, but why start with something insecure when it's just as easy to use something more secure (i.e. same code, just swap out algorithm name)? – Greg Beech Aug 19 '09 at 16:07
  • @Joel: MD5 is too fast is one big reason that brute forcing a reversal (by guessing every possible initial password) is so easy. This is less true with things like SHA-256, though key-strengthening can't hurt :) – Brian Aug 19 '09 at 16:25
  • On a side note, MD5 might fail sometimes as windows can deny usage of "insecure" algorithms. – Chris Chilvers Aug 19 '09 at 16:28

3 Answers3

41

You can use the HMACMD5 class:

var hmacMD5 = new HMACMD5(salt);
var saltedHash = hmacMD5.ComputeHash(password);

Works with SHA-1, SHA256, SHA384, SHA512 and RIPEMD160 as well:

var hmacSHA1 = new HMACSHA1(salt);
var saltedHash = hmacSHA1.ComputeHash(password);

Both salt and password are expected as byte arrays.

If you have strings you'll have to convert them to bytes first:

var salt = System.Text.Encoding.UTF8.GetBytes("my salt");
var password = System.Text.Encoding.UTF8.GetBytes("my password");
dtb
  • 213,145
  • 36
  • 401
  • 431
  • 1
    http://msdn.microsoft.com/en-us/library/system.security.cryptography.hmacsha1.hmacsha1.aspx HMACSHA1 constructor accepts not a salt but a key as single parameter – abatishchev Aug 19 '09 at 16:05
  • 4
    A HMAC is usually used to get the keyed hash of a message. If you replace the key with a salt and the message with your password, you can use the HMAC to get the salted hash of a password. – dtb Aug 19 '09 at 16:10
  • Is there any way of decrypting the salted password ? – Sana Ahmed Aug 16 '16 at 13:35
  • @Sana No, these are one way hashing functions and cannot be reversed. Only attacks like brute force, rainbow tables (which salting makes obsolete), and social engineering are effective for determining an unencrypted password. – Jacob Stamm Jun 03 '21 at 19:24
4

In addition to the HMACSHA1 class mentioned above, if you just need a quick salted hash, then you're already 95% of the way there:

private static string GenerateHash(string value, string salt)
{
    byte[] data = System.Text.Encoding.ASCII.GetBytes(salt + value);
    data = System.Security.Cryptography.MD5.Create().ComputeHash(data);
    return Convert.ToBase64String(data);
}

The real trick is storing the salt in a secure location, such as your machine.config.

Juliet
  • 80,494
  • 45
  • 196
  • 228
  • Could timestamp be a good salt? or discovery of such fact will compromise whole algorithm? – abatishchev Aug 19 '09 at 20:31
  • Time stamp would not work because when you go to validate the hash against new input, the time will be different. – Fantius Aug 19 '09 at 21:28
  • Unless you are storing the time stamp along with the digest, in which case it would work but would not be very secure. – Fantius Aug 19 '09 at 21:31
  • 7
    If the security of your implementation depends on keeping the salt secret then you're in big trouble! – LukeH Aug 20 '09 at 21:03
  • 3
    highly recommend using **System.Text.Encoding.UTF8** instead of ASCII – zanlok Apr 12 '12 at 00:22
  • @Juliet the downvote was an accident, sorry, I tried to undo it but the vote is locked – Vamsi Mar 20 '13 at 05:58
1

Microsoft have done this work for you, but it takes a bit of digging. Install Web Service Extensions 3.0, and have a look at the Microsoft.Web.Services3.Security.Tokens.UsernameToken.ComputePasswordDigest function with Reflector.

I would like to post the source code to that function here, but I'm not sure if it's legal to do that. If anyone can reassure me then I will do so.

Christian Hayter
  • 30,581
  • 6
  • 72
  • 99
  • 3
    I suspect that the legality depends very much on where you are. In some jurisdictions it's illegal for you to even look at the decompiled code yourself, let alone post it for others to look at! – LukeH Aug 19 '09 at 16:15
  • 2
    Though with Visual Studio 2008 it is possible to view the source code for .net when debugging, provided you first agreed to MS' T&Cs for that. – Chris Chilvers Aug 19 '09 at 16:30