How to hash password

We know that it’s very dangerous to hold explicit passwords in a database. That is why it’s the best to get them hash but how to do it?

Hash password

In the first step we need to create salt.

Salt( Via Wikipedia ) – is random data that is used as an additional input to a one-way function that “hashes” a password or passphrase. The primary function of salts is to defend against dictionary attacks or against its hashed equivalent, a pre-computed rainbow table attack. link

The function responsible for generating salt is as follows:

public string GetSalt()
{
    var saltInBytes = new byte[40];
    var rng = RandomNumberGenerator.Create();
    rng.GetBytes(saltInBytes);
    return Convert.ToBase64String(saltInBytes);
}

private static byte[] GetBytes(string value)
{
    var bytes = new byte[value.Length * sizeof(char)];
    Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

And then we can use a ready-made hashing alorithm of the class Rfc2898DeriveBytes in C#.

public string GetHash(string password, string salt)
{
    var hash = new Rfc2898DeriveBytes(password, GetBytes(salt), 1000);
    return Convert.ToBase64String(hash.GetBytes(40));
}

Let’s see that our system will correct hashing our password.

[Fact]
public void Hash_system_should_return_the_correct_hashed_password()
{
    const string password = "secretpw";
    var hashSystem = new HashPw();

    var salt = "CV5QNYON27MkyFrbiZViitcxfdXZHdHvsE7kSAu4UQ5f9GkxmhMszA ==";
    var hashPassword = hashSystem.GetHash(password, salt);

    Assert.Equal("AGd+jMv/HauI86d9nRSa568irLdYgWjrHfVALjQ1g04VJLSUucMnEA==", hashPassword);
}

In this approeach with the same salt and password our system will generates the same hash password. If we give him diffrent salt, then diffrent hash password will be generated.

So in our case two users with the same password will have diffrent hash password.

[Fact]
public void Hash_system_all_time_genereate_the_same_hash_password_if_we_give_him_the_same_salt()
{
    const string password = "secretpw";
    var hashSystem = new HashPw();

    var salt = hashSystem.GetSalt();
    var hashPassword = hashSystem.GetHash(password, salt);
    var secondHashPassword = hashSystem.GetHash(password, salt);

    Assert.Equal(hashPassword, secondHashPassword);
}

[Fact]
public void Hash_password_will_be_diffrent_for_the_same_user_password_with_diffrent_salt()
{
    const string password = "secretpw";
    var hashSystem = new HashPw();

    var salt = hashSystem.GetSalt();
    var hashPassword = hashSystem.GetHash(password, salt);
    var saltForSecondUser = hashSystem.GetSalt();
    var secondHashPassword = hashSystem.GetHash(password, saltForSecondUser);

    Assert.NotEqual(hashPassword, secondHashPassword);
}

And here is the confirmation. 😉

  hashtest

Link to the project.

Additional.

Difference between pseudo number and security number.
secure and pseudo number

6 Comments on “How to hash password”

  1. I have a small remark about Hash_password_will_be_diffrent_for_the_same_user_password_with_diffrent_salt test. It is not derministic. Sometimes you can have generated twice same salt and your test will fail.

    1. The probability is very, but very small. Adding to that, we generate a “secure random” instead of “pseudo random”.

  2. I do not like randomness in unit tests.

    What is returned from RandomNumberGenerator.Create();? it’s like ‘return new Random(42);’ ?

    If seed is not constant then you cannot be sure if salt generated in Hash_password_will_be_diffrent_for_the_same_user_password_with_diffrent_salt() will be always diffrent from each other.

    1. 1. Difference it’s that random generate for us “pseudo random” but randomnumbergenerator generate for us “more secure” random.
      Random vs EncryptRandom
      2. Yes but for me it does not matter that salt will be the same for different passwords. Because class Rfc2898DeriveBytes generate for us diffrent “hash” at the end.

  3. Fajny wpis. Rzuć okiem na literówki (“Slat” w cytacie).
    Zastanawia mnie ta metoda `GetBytes(string)`, bo w sumie jeśli generujesz salt i konwertujesz do Base64 to tak samo powinieneś to odwrócić. Taka metoda jaką zaprezentowałeś ma sens w przypadku gdy string z solą nie jest w Base64, ale wtedy nie wiem, czy nie byłoby problemu ze znakami poza zakresem jednego bajta. Zamiast kopiować tablicę charów, lepiej chyba po prostu użyć `System.Text.Encoding.*.GetBytes(string)`. Co o tym sądzisz?

    1. Jeżeli chodzi o wyjście poza zakres to o bym się nie martwił.
      Dla mnie sprawdza się kopiowanie tablic “ręcznie”. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *