Thursday, March 3, 2011

What is the easiest way to create and compare a salted password in .NET?

In an ongoing effort to improve my code I am looking for the best way to create and compare a salted password in .NET.

Is there a better, or more secure, way of doing this?

My current code is as follows:

    public static string CreateSaltedPassword(string salt, string password)
    {
        SHA1CryptoServiceProvider SHA1 = null;

        SHA1 = new SHA1CryptoServiceProvider();

        // Convert the string into an array of bytes
        byte[] byteValue = System.Text.Encoding.UTF8.GetBytes(salt + password);

        // Compute the hash value
        byte[] byteHash = SHA1.ComputeHash(byteValue);

        // Dispose the unmanaged cryptographic object 
        SHA1.Clear();

        return Convert.ToBase64String(byteHash);
    }

    public static bool ComparePasswords(string salt, string password, string storedPassword)
    {
        string passwordHash = string.Empty;

        // Create the hashed password
        passwordHash = PasswordProvider.CreateSaltedPassword(
            salt, password);

        // Compare the passwords
        return (string.Compare(storedPassword, passwordHash) == 0);
    }
From stackoverflow
  • Jeff Atwood's code project article:

    This class is heavily documented, string oriented, and most of all, simple! It's ideal for learning more about encryption.

  • You should do a few thousand iterations through the SHA1 hash:

    public static string CreateSaltedPassword(string salt, string password, int iter)
    {
      SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();
      byte[] byteValue = System.Text.Encoding.UTF8.GetBytes(salt + password);
      do {
        byteValue = SHA1.ComputeHash(byteValue);
      } while (--iter > 0);
      SHA1.Clear();
      return Convert.ToBase64String(byteValue);
    }
    

    Do some testing to see how long it takes on your target machine: 1000 to 10000 iterations shouldn't be noticeable to users when you are checking their input, but it will change an attacker's time requirement from hours to years—long enough that the password will have expired before the attacker recovers it.

    The salt source and size is not shown; the salt does not need to be secret, it just needs to be unpredictable for a given password. 8 bytes from a cryptographic RNG is a convenient and secure salt. User names are more convenient, but may be a little less secure.

    This set up gives reasonable security for most applications today. The next step up in security would be bcrypt. Where I suggested multiple iterations of the hash function above, bcrypt does more methodically with a very slow key generation process.

    You may be interested in my answers to these similar questions:

  • Use the Rfc2898DeriveBytes class from System.Security.Cryptography.

    It's built-in to the .NET framework since version 2.0 and it implements PBKDF2-HMACSHA1, which gives solid password salting and a slowing-down of the hash (which is critical for password hashes).

0 comments:

Post a Comment