Password hashing different salt with same username

399 views Asked by At

We introduced password encryption to our site. The salt is calculated as shown below:

Rfc2898DeriveBytes hasher = new Rfc2898DeriveBytes(Username.ToLowerInvariant(),
           System.Text.Encoding.Default.GetBytes("Wn.,G38uI{~6y8G-FA4);UD~7u75%6"), 10000);
string salt = Convert.ToBase64String(hasher.GetBytes(25));

For most usernames the salt is always the same. But for some usernames it changes at every call. Can someone tell me what we are doing wrong?

1

There are 1 answers

0
Anti-weakpasswords On BEST ANSWER

Assuming you're using RFC2898DeriveBytes to hash the password itself as well, then @CodesInChaos is correct, what you're doing wrong is:


byte[] salt1 = new byte[8];
using (RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider())
  {
  // Fill the array with a random value.
  rngCsp.GetBytes(salt1);
  }

  • The salt should then be stored in the clear in your database alongside the password hash and iteration count (so you can change it), and probably a version code too (so you can change it again, i.e. your current calculated salt method is version 1, and the random salt is version 2).

    • Spending 20,000 iterations of PBKDF2 on the salt, rather than spending it on the actual password hash!
  • 10,000 iterations for the first 20 bytes, since RFC2898DeriveBytes is PBKDF2-HMAC-SHA-1, and SHA-1 has a native 20 byte output
  • 10,000 more iteration for the next 20 bytes, which is then truncated to only the 5 you need to get to a 25 byte output.
  • This is a weakness, as the defender has to spend the time on the salt on every login, whether it's spent on the salt, or the password hashing. The attacker has to spent that time once for each username, and then they are going to store the results and try _illions (where _ is very large) of password guesses.
    • Thus, the attacker has a greater than normal marginal advantage because they can precalculate the salt, while you have to calculate it on the fly.

If you aren't using RFC2898DeriveBytes, another PBKDF2 implementation, BCrypt, or SCrypt to do the actual password hashing, then that's what you're doing wrong.

Trimming the username some, but not all of the time is entirely incidential; just make sure not to trim passwords before they're hashed.