1

I assume that the best way to handle passwords for a website is I create a hash of the password and save that hash in my database. Then when someone tries to login, I do a hash of the password they entered and compare.

Is this correct?

And, is there sample code anywhere showing how to do this in C#?

And should I add some standard text to each password so the text being hashed is always at least 20 chars long?

Update: The other links don't have code so here's what I implemented for this question. I don't include the username because that can change, so just salt:password. the : works because uuencode does not include a :.

public static class EncryptionUtilities
{
    private const int SALT_SIZE = 8;
    private const int NUM_ITERATIONS = 1000;

    private static readonly RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

    /// <summary>
    /// Creates a signature for a password.
    /// </summary>
    /// <param name="password">The password to hash.</param>
    /// <returns>the "salt:hash" for the password.</returns>
    public static string CreatePasswordSalt(string password)
    {
        byte[] buf = new byte[SALT_SIZE];
        rng.GetBytes(buf);
        string salt = Convert.ToBase64String(buf);

        Rfc2898DeriveBytes deriver2898 = new Rfc2898DeriveBytes(password.Trim(), buf, NUM_ITERATIONS);
        string hash = Convert.ToBase64String(deriver2898.GetBytes(16));
        return salt + ':' + hash;
    }

    /// <summary>
    /// Validate if a password will generate the passed in salt:hash.
    /// </summary>
    /// <param name="password">The password to validate.</param>
    /// <param name="saltHash">The "salt:hash" this password should generate.</param>
    /// <returns>true if we have a match.</returns>
    public static bool IsPasswordValid(string password, string saltHash)
    {
        string[] parts = saltHash.Split(new[] {':'}, StringSplitOptions.RemoveEmptyEntries);
        if (parts.Length != 2)
            return false;
        byte[] buf = Convert.FromBase64String(parts[0]);
        Rfc2898DeriveBytes deriver2898 = new Rfc2898DeriveBytes(password.Trim(), buf, NUM_ITERATIONS);
        string computedHash = Convert.ToBase64String(deriver2898.GetBytes(16));
        return parts[1].Equals(computedHash);
    }
}

ps - I considered adding "The World Wonders" to the text hashed because it's the most famous salt of all time. However, I figured it didn't add anything and encryption is not the place to bring in historical strings.

David Thielen
  • 383
  • 1
  • 4
  • 13
  • I agree with the advice in Angel's link. Salted PBKDF2 as implemented in the `Rfc2898DeriveBytes` class is pretty much industry standard. – Polynomial Sep 21 '14 at 21:45
  • The code to implement and manage this is built into ASP.NET and called [ASP.NET Identity](http://www.asp.net/identity). – Xander Sep 21 '14 at 22:05
  • If you want a code review, this isn't in scope here, but you can get that on [codereview.se], assuming that you believe your code to be correct. – Gilles 'SO- stop being evil' Sep 22 '14 at 23:48
  • @Gilles I'm not asking for a code review, I'm just trying to provide code for anyone who might need this in the future. And this should remove the tagging this as duplicate as the "already answered" link does not provide code. – David Thielen Sep 23 '14 at 02:51

1 Answers1

1

Yes, you should add a text to each password so that the text being hashed is always at least X long, this is called a salt, and it should be unique to each user.

A database entry might look like this:

username : password : salt

bob : qiyh4XPJGsOZ2MEAyLkfWqeQ : zyIIMSYjiPm0L7a6

the salt should be randomly generated when the account is created, and then you would concatenate the salt with the user's password input, run it through a 1-way hashing algorithm (multiple times to slow it down), and then save the output in the password field, and duplicate the procedure upon login, then compare the two strings (make sure to do full comparison, don't stop once you notice the strings no longer match, in order to prevent a timing attack)

for an actual implementation I would check Ángel's link

user2813274
  • 2,051
  • 2
  • 13
  • 18
  • This sounds not standard, bcrypt is easy enough to implement just do it 100,000 times and every year increase it by 50,000 and generate the password hashes again – Ramhound Sep 22 '14 at 20:25
  • I wanted to avoid any particular technologies or algorithms - those should be chosen to suit the individual needs and security requirements. – user2813274 Sep 22 '14 at 21:47
  • There are really only two correct ways to implement password hashing. Trying to suggest anything else, I would go as far as saying, doing so would be unethical. – Ramhound Sep 22 '14 at 21:49