2

I am currently using the new ASP.NET Identity framework.

I must implement a way of checking if a password the user wishes to change their password to has been used in the past. I have a table containing retired hashes and their corresponding salts.

What I am unable to figure out is how to generate a hash using a specific salt so I can compare the new password to the retired passwords. I've seen UserManager.PasswordHasher.HashPassword(password) but I don't see an overload to specify the salt.

How does one go about hashing a password with Identity and specify a salt?

masterwok
  • 4,868
  • 4
  • 34
  • 41
  • You may want to look at [this question](http://stackoverflow.com/questions/20621950/asp-net-identity-default-password-hasher-how-does-it-work-and-is-it-secure), the hash is the first few bytes of the base64 encoded string, so when you go to call `VerifyHashedPassword` it should be re-useing the old hash. How are getting the salts sperated from the string currently? Can you include the code for it? – Scott Chamberlain Feb 13 '14 at 21:55
  • There is a great answer on how the default implementation works here http://stackoverflow.com/questions/20621950/asp-net-identity-default-password-hasher-how-does-it-work-and-is-it-secure I recently created a solution to generate the hased passwords in pure SQL which can be found here http://stackoverflow.com/questions/5033886/generate-asp-net-membership-password-hash-in-pure-t-sql/33420086 – Dave Cornall Oct 29 '15 at 17:11

3 Answers3

5

Just verify the password the same way you would verify currently. All you need to do is store the same information you would store for the current password in the old passwords and check that none of them verify

bool UserReusedPassword(string username, string password)
{
    foreach(string oldHash in GetOldHashesForUser(username)
    {
        if(UserManager.PasswordHasher.VerifyHashedPassword(oldHash, password) != PasswordVerificationResult.Failed)
        {
            return true;
        }
    }

    return false;
}

using UserManager.PasswordHasher the salt is stored as the first few bytes of the hashed string, so you should not need to "manually enter the salt" VerifyHashedPassword will automatically read it in and set it for the verification process.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
4

You can't use a specific salt. However you should use a different salt for each password. So your HashPassword method is responsible of the generation of the salt. Here's an example (mainly inspired from the Mircosoft default implementation):

public string HashPassword(string password) 
{ 
    if (password == null) throw new ArgumentNullException("password"); 

    int saltSize = 16;
    int iterations = 4000;

    byte[] salt; 
    byte[] bytes; 

    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, saltSize, iterations)) 
    { 
        salt = rfc2898DeriveBytes.Salt; 
        bytes = rfc2898DeriveBytes.GetBytes(32); 
    } 

    byte[] inArray = new byte[saltSize + 32];       
    Buffer.BlockCopy((Array)salt, 0, (Array)inArray, 0, saltSize); 
    Buffer.BlockCopy((Array)bytes, 0, (Array)inArray, saltSize, 32); 
    return Convert.ToBase64String(inArray); 
} 

As you can see the salt is embedded in the result of the HashPassword method so when you need to validate the password, you can extract the salt and the hash and make the verification.

meziantou
  • 20,589
  • 7
  • 64
  • 83
  • 1
    Thanks you for the answer. However I don't think it's what I'm looking for. I'm letting UserManagerExtensions.ChangePassword handle the generation of salts and hashes which then updates the users pass/salt in the database. When a user changes their password it saves the current hash and salt in a table containing retired user passwords. It then checks to ensure the new password isn't contained in the past table by using the salt contained in the retired password table. This is where I need to figure out how to generate hashes using specific salts. – masterwok Feb 13 '14 at 17:37
  • The example above also produces different hashes than what I am seeing in my database. My hash format: AFFJxo3xpKyixRj47VECKhDNwJfL6pjp2XQB6G4thqukflvbZAXp5og7ffqEvyexOw== – masterwok Feb 13 '14 at 17:38
  • Hash format the above example generates: u6qFzSpQ3PzVxj11w8UIBGiTkeCw943cUfI2io29TLdUZQw4Lzo33dwNFglnzs5I – masterwok Feb 13 '14 at 17:46
  • Asp Identity does not provide a way to generate a hash with a specific salt (look at the IPasswordHasher interface) so you won't be able to do what you want by using the provided interface. Note that my example is not exactly the same as the microsoft implementation (number of iteration is not the same, plus I copy bytes into the first element of the array instead of the second, and maybe some other differences). – meziantou Feb 13 '14 at 17:58
0

You can look at the migration sample from SQL membership to Identity here. SQL membership used password salt for encryption and the article outlines hooking in a custom password hasher to reuse those passwords.

Suhas Joshi
  • 1,042
  • 9
  • 11