Quantcast
Channel: damienbod – Software Engineering
Viewing all articles
Browse latest Browse all 357

Creating hashes in .NET

$
0
0

This article looks at different ways to create hashes in .NET Core. Hashes are useful for one way encryption which can be used for password storage, JWT validation and some other security use cases. When storing hashes in a database, extra care must be taken and the recommended approach from Microsoft should be used when implementing this. In general, creating hashes and storing the hashes in a database should be avoided as much as possible.

Using SHA512

The fastest and simplest way is to user the SHA512 directly. This takes a string and hashes it directly using a one way encryption. This is good when the hashes are not persisted in a database or when attackers don’t have time to do a dictionary attack.

public static bool VerifyCode(string code, string storedCode)
{
    if (!ToHashedCode(code).Equals(storedCode))
    {
       return true;
    }

    return false;
}

public static string ToHashedCode(string code)
{
    using var sha512 = SHA512.Create();
    var bytes = Encoding.UTF8.GetBytes(code);
    var hash = sha512.ComputeHash(bytes);
    return Convert.ToBase64String(hash);
}

Using Rfc2898DeriveBytes.Pbkdf2

The Rfc2898DeriveBytes.Pbkdf2 method can be used to create hashes and when using this, a salt of 8 bytes or more should be used and more than 10000 iterations. This makes it harder to reverse engineer the original hash values.

private const int _keySize = 32;
private const int _iterations = 10000;
private static readonly HashAlgorithmName _algorithm = HashAlgorithmName.SHA512;

public static string ToHashedCode(string toHash, string userId)
{
     var salt = Encoding.UTF8.GetBytes(userId);

     var hash = Rfc2898DeriveBytes.Pbkdf2(
         toHash,
         salt,
         _iterations,
         _algorithm,
         _keySize
     );

     return Convert.ToBase64String(hash);
}

public static bool VerifyCode(string code, string userId, string storedCode)
{
     var salt = Encoding.UTF8.GetBytes(userId);
     var storedHash = Convert.FromBase64String(storedCode);

     var hash = Rfc2898DeriveBytes.Pbkdf2(
         code,
         salt,
         _iterations,
         _algorithm,
         _keySize
     );

     return CryptographicOperations.FixedTimeEquals(hash, storedHash);
}

Using ASP.NET Core Identity

ASP.NET Core Identity provides interfaces to create password hashes for data storage. You can use any C# type to define the password hasher and the Identity user class is normally used to create an instance of the PasswordHasher class. The hashes from this implementation can be saved to a database. This hash implementation is slow to create the hashes.

private readonly PasswordHasher<string> _passwordHasher = new();
    
public static string ToHashedCode(string code, string userId, 
      PasswordHasher<string> passwordHasher)
{
	var hash = passwordHasher.HashPassword(userId, code);
	return hash;
}

public static bool VerifyCode(string code, string userId, string storedCode)
{
	var passwordHasher = new PasswordHasher<string>();
	var result = passwordHasher.VerifyHashedPassword(userId, storedCode, code);
	return result == PasswordVerificationResult.Success;
}

Notes

Using the right hash implementation is important and choosing the wrong one could result in a security problem. You should aim for solutions where implementing this should not be required. When storing hash values to a database, the Microsoft recommendations should be followed. Best would be to use the default implementation from ASP.NET Core Identity, when this is possible.

Links

https://andrewlock.net/exploring-the-asp-net-core-identity-passwordhasher/

https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-configuration

https://github.com/damienbod/SendingEncryptedData


Viewing all articles
Browse latest Browse all 357

Trending Articles