public static bool VerifyHashedPassword(string hashedPassword, string password) { if (hashedPassword == null) { throw new ArgumentNullException("hashedPassword"); } if (password == null) { throw new ArgumentNullException("password"); } var hashedPasswordBytes = Convert.FromBase64String(hashedPassword); // Verify a version 0 (see comment above) password hash. if (hashedPasswordBytes.Length != (1 + SaltSize + Pbkdf2SubkeyLength) || hashedPasswordBytes[0] != 0x00) { // Wrong length or version header. return false; } var salt = new byte[SaltSize]; Buffer.BlockCopy(hashedPasswordBytes, 1, salt, 0, SaltSize); var storedSubkey = new byte[Pbkdf2SubkeyLength]; Buffer.BlockCopy(hashedPasswordBytes, 1 + SaltSize, storedSubkey, 0, Pbkdf2SubkeyLength); byte[] generatedSubkey; using (var deriveBytes = new Rfc2898DeriveBytes_HMACSHA256(password, salt, Iterations)) { generatedSubkey = deriveBytes.GetBytes(Pbkdf2SubkeyLength); } return ByteArraysEqual(storedSubkey, generatedSubkey); }
/* ======================= * HASHED PASSWORD FORMAT * ======================= * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations. * Format: { 0x00, salt, subkey } */ public static string HashPassword(string password) { if (string.IsNullOrWhiteSpace(password)) { throw new ArgumentNullException("password"); } // Produce a version 0 (see comment above) password hash. byte[] salt; byte[] subkey; using (var deriveBytes = new Rfc2898DeriveBytes_HMACSHA256(password, SaltSize, Iterations)) { salt = deriveBytes.Salt; subkey = deriveBytes.GetBytes(Pbkdf2SubkeyLength); } var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength]; Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize); Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength); return Convert.ToBase64String(outputBytes); }