I created a simple MVC4 app and registered a user. The usrname and password are stored in a table called: AspNetUsers. This table does not have a salt field.
The way I understood is that when a user logs in; they enter a username and password. The salt is then concatenated with the password entered and compared to the password in the database. Is that not correct? i.e.
Hash(PasswordEntered) + Salt = Password in database = authenticated
Hash(PasswordEntered) + Salt <> Password in database = not authenticated
There is a field called: aspnetusers.SecurityStamp, however my research tells me that this is not the Salt.
Update
I have just read Scott Chamberlain. Please see the steps below:
1) A user enters: Hello123 as the password during registration and the Salt (randomly generated) is: 456, then the password entered into PasswordHash is: Hello123+456
2) The user then attempts to login and types Hello123 (correctly) as the password. The salt (randomly generated) is: 567. Therefore Hello123+456 is compared to Hello123+567 and the authentication fails.
In this case the user enters the correct password and is not authenticated. I am obviously missing something fundamental here.
In cryptography, salt is randomly generated for each password. In a typical setting, the salt and the password are concatenated and processed with a cryptographic hash function, and the resulting output (but not the original password) is stored with the salt in a database.
The ASP.NET Identity system is designed to replace the previous ASP.NET Membership and Simple Membership systems. It includes profile support, OAuth integration, works with OWIN, and is included with the ASP.NET templates shipped with Visual Studio 2013.
ASP.NET Identity is Microsoft's user management library for ASP.NET. It includes functionality such as password hashing, password validation, user storage, and claims management. It usually also comes with some basic authentication, bringing its own cookies and multi-factor authentication to the party.
Same for asp.net core 3.
Salt + Hash
are joined and stored into the passwordHash
field in the db.
Here is the source code of how the passwordHash is being generated.
*password
parameter is the plaintext password.
*subkey
is the hash
.
https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Extensions.Core/src/PasswordHasher.cs
private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
{
// Produce a version 3 (see comment above) text hash.
byte[] salt = new byte[saltSize];
rng.GetBytes(salt);
byte[] subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);
var outputBytes = new byte[13 + salt.Length + subkey.Length];
outputBytes[0] = 0x01; // format marker
WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
WriteNetworkByteOrder(outputBytes, 5, (uint)iterCount);
WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize);
Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
return outputBytes;
}
You have the pattern incorrect, the correct one would be
Hash(PasswordEntered + Salt) = hash in database = authenticated
Hash(PasswordEntered + Salt) <> hash in database = not authenticated
The way the provider for ASP.net works is it stores Salt + Hash(PasswordEntered + Salt)
in the password field. So when you go to test a password you just use the part before the separator in the salt and compare it to the part after the separator.
In your update the part you have wrong is there is no randomly generated salt when the user logs in. It re-uses the salt that was randomly generated at registration for the user, that salt is stored in plain-text in the database and is not hashed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With