views:

879

answers:

3

I was just going through one of DavidHayden's articles on Hashing User Passwords.

Really I can't get what he is trying to achieve.

Here is his code:

private static string CreateSalt(int size)
{
    //Generate a cryptographic random number.
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] buff = new byte[size];
    rng.GetBytes(buff);

    // Return a Base64 string representation of the random number.
    return Convert.ToBase64String(buff);
}

private static string CreatePasswordHash(string pwd, string salt)
{
    string saltAndPwd = String.Concat(pwd, salt);
    string hashedPwd =
        FormsAuthentication.HashPasswordForStoringInConfigFile(
        saltAndPwd, "sha1");
    return hashedPwd;
}

Is there any other C# method for hashing passwords and adding salt to it?

+3  A: 

He is taking a password, adding a salt and then getting the hash to store in a file. What don't you get?

Is there any other c# method for Hashing passwords and adding salt to it?

You understand that salt is added to password before hash, right? This is so if someone got access to all of the hashed passwords they could not reverse them unless they also had salt, thus making them more secure.

tm1rbrt
@tm1rbrt ya right... ok now i get it...
Pandiya Chendur
Also you generally use the same salt for all hashes on the same database
tm1rbrt
Oh you most certainly do *not* use the same salt for all hashes. Each hash should have an individual salt, to make precomputed hash generation computationally heavy. By using the same salt you weaken the entire system. This is very very bad advice.
blowdart
@tm1rbrt whats the point in using the same salt? I cant understand..
Pandiya Chendur
@blowdart what can be done for that?
Pandiya Chendur
+4  A: 

Salt is used to add an extra level of complexity to the hash, to make it harder to brute-force crack.

From an article on Sitepoint:

A hacker can still perform what's called a dictionary attack. Malicious parties may make a dictionary attack by taking, for instance, 100,000 passwords that they know people use frequently (e.g. city names, sports teams, etc.), hash them, and then compare each entry in the dictionary against each row in the database table. If the hackers find a match, bingo! They have your password. To solve this problem, however, we need only salt the hash.

To salt a hash, we simply come up with a random-looking string of text, concatenate it with the password supplied by the user, then hash both the randomly generated string and password together as one value. We then save both the hash and the salt as separate fields within the Users table.

In this scenario, not only would a hacker need to guess the password, they'd have to guess the salt as well. Adding salt to the clear text improves security: now, if a hacker tries a dictionary attack, he must hash his 100,000 entries with the salt of every user row. Although it's still possible, the chances of hacking success diminish radically.

There is no method automatically doing this in .NET, so you'll have go with the solution above.

Seb Nilsson
@seb thanks now i get what davidhayden was trying to acheive..
Pandiya Chendur
+11  A: 

Actually this is kind of strange, with the string conversions - which the membership provider does to put them into config files. Hashes and salts are binary blobs, you don't need to convert them to strings unless you want to put them into text files.

In my book, Beginning ASP.NET Security, (oh finally, an excuse to pimp the book) I do the following

static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
  HashAlgorithm algorithm = new SHA256Managed();

  byte[] plainTextWithSaltBytes = 
    new byte[plainText.Length + salt.Length];

  for (int i = 0; i < plainText.Length; i++)
  {
    plainTextWithSaltBytes[i] = plainText[i];
  }
  for (int i = 0; i < salt.Length; i++)
  {
    plainTextWithSaltBytes[plainText.Length + i] = salt[i];
  }

  byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);            
}

The salt generation is as the example in the question. You can convert text to byte arrays using Encoding.UTF8.GetBytes(string). If you must convert a hash to its string representation you can use Convert.ToBase64String and Convert.FromBase64String to convert it back.

You should note that you cannot use the equality operator on byte arrays, it checks references and so you should simply loop through both arrays checking each byte thus

public static bool CompareByteArrays(byte[] array1, byte[] array2)
{
  if (array1.Length != array2.Length)
  {
    return false;
  }

  for (int i = 0; i < array1.Length; i++)
  {
    if (array1[i] != array2[i])
    {
      return false;
    }
  }

  return true;
}

Always use a new salt per password. Salts do not have to be kept secret and can be stored alongside the hash itself.

blowdart
+1 for your book pimping! ;-)
PhilPursglove
Thanks for this advice - really helped get me started. I also came across this link < http://www.dijksterhuis.org/creating-salted-hash-values-in-c/ > which I found was good practical advice and mirrors much of what was said in this post
Remnant
nifty LINQ statement refactor for CompareByteArrays`return array1.Length == array2.Length `
hunter