Something went wrong. Try again.
A personal wiki written in .NET
Something went wrong. Try again.
2.6 kB · 78 lines
C#
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778using System;using System.Security.Cryptography;using Microsoft.AspNetCore.Cryptography.KeyDerivation;
namespace MiniWiki.Web.Auth;
public class PasswordService{ private const int SaltSize = 16; private const int HashSize = 32; private const int Iterations = 600_000; // OWASP recommendation
/// <summary> /// Hashes a password using PBKDF2 with a random salt /// </summary> /// <param name="password">The password to hash</param> /// <returns>The hashed password</returns> /// <exception cref="ArgumentException">Thrown if <paramref name="password" /> is empty</exception> public string HashPassword(string password) { ArgumentException.ThrowIfNullOrWhiteSpace(password);
var salt = RandomNumberGenerator.GetBytes(SaltSize); var hash = KeyDerivation.Pbkdf2( password, salt, KeyDerivationPrf.HMACSHA256, Iterations, HashSize);
var combined = new byte[SaltSize + HashSize]; Buffer.BlockCopy(salt, 0, combined, 0, SaltSize); Buffer.BlockCopy(hash, 0, combined, SaltSize, HashSize);
return Convert.ToBase64String(combined); }
/// <summary> /// Verifies if the given <paramref name="password" /> hash is equal to the <paramref name="hashedPassword" /> /// </summary> /// <param name="password">The password to compare</param> /// <param name="hashedPassword">The hashed password to compare</param> /// <returns>True if the passwords match</returns> public bool VerifyPassword(string password, string hashedPassword) { if (string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(hashedPassword)) return false;
try { var combined = Convert.FromBase64String(hashedPassword);
if (combined.Length != SaltSize + HashSize) return false;
// extract salt var salt = new byte[SaltSize]; Buffer.BlockCopy(combined, 0, salt, 0, SaltSize);
// extract hash var storedHash = new byte[HashSize]; Buffer.BlockCopy(combined, SaltSize, storedHash, 0, HashSize);
// hash the provided password with the extracted salt var computedHash = KeyDerivation.Pbkdf2( password, salt, KeyDerivationPrf.HMACSHA256, Iterations, HashSize);
// compare hashes return CryptographicOperations.FixedTimeEquals(storedHash, computedHash); } catch { return false; } }}