Problem
How to use hash data (e.g. passwords) in ASP.NET Core.
Solution
The new Data Protection API in .NET Core includes functionality to create hashes using PBKDF2algorithm. ASP.NET Core uses this behind the scenes functionality in PasswordHasher class, which is used in ASP.NET Core Identity.
Create a class library and add the following NuGet package -
Microsoft.AspNetCore.Cryptography.KeyDerivation
Add a class to encapsulate the hashing logic.
- public class Hash
- {
- public static string Create(string value, string salt)
- {
- var valueBytes = KeyDerivation.Pbkdf2(
- password: value,
- salt: Encoding.UTF8.GetBytes(salt),
- prf: KeyDerivationPrf.HMACSHA512,
- iterationCount: 10000,
- numBytesRequested: 256 / 8);
-
- return Convert.ToBase64String(valueBytes);
- }
-
- public static bool Validate(string value, string salt, string hash)
- => Create(value, salt) == hash;
- }
Add a class to encapsulate the logic for creating a random salt.
- public class Salt
- {
- public static string Create()
- {
- byte[] randomBytes = new byte[128 / 8];
- using (var generator = RandomNumberGenerator.Create())
- {
- generator.GetBytes(randomBytes);
- return Convert.ToBase64String(randomBytes);
- }
- }
- }
Add tests to verify the functionality, e.g,
- [Fact(DisplayName = "Untampered_hash_matches_the_text")]
- public void Untampered_hash_matches_the_text()
- {
-
- var message = "passw0rd";
- var salt = Salt.Create();
- var hash = Hash.Create(message, salt);
-
-
- var match = Hash.Validate(message, salt, hash);
-
-
- Assert.True(match);
- }
-
- [Fact(DisplayName = "Tampered_hash_does_not_matche_the_text")]
- public void Tampered_hash_does_not_matche_the_text()
- {
-
- var message = "passw0rd";
- var salt = Salt.Create();
- var hash = "blahblahblah";
-
-
- var match = Hash.Validate(message, salt, hash);
-
-
- Assert.False(match);
- }
-
- [Fact(DisplayName = "Hash_of_two_different_messages_dont_match")]
- public void Hash_of_two_different_messages_dont_match()
- {
-
- var message1 = "passw0rd";
- var message2 = "password";
- var salt = Salt.Create();
-
-
- var hash1 = Hash.Create(message1, salt);
- var hash2 = Hash.Create(message2, salt);
-
-
- Assert.True(hash1 != hash2);
- }
Source Code
GitHub