private static byte[] HashPasswordV3(string password, int iterCount, int saltSize, int numBytesRequested, RandomNumberGenerator rng, Pbkdf2Provider pbkdf2Provider) { // Produce a version 2 (see comment above) text hash. byte[] salt = new byte[_saltSize]; rng.GetBytes(salt); byte[] subkey = pbkdf2Provider.DeriveKey(password, salt, iterCount, numBytesRequested); var outputBytes = new byte[13 + salt.Length + subkey.Length]; outputBytes[0] = 0x01; // format marker WriteNetworkByteOrder(outputBytes, 1, (uint)KeyDerivationPrf.HMACSHA256); 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); }
private static bool VerifyHashedPassword(byte[] hashedPassword, string password, Pbkdf2Provider pbkdf2Provider) { try { // Read header information //KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1); var iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5); int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9); // Lower iteration count will be denied. if (iterCount < _pbkdf2IterCount) { return(false); } // Read the salt: must be >= 128 bits if (saltLength < 128 / 8) { return(false); } byte[] salt = new byte[saltLength]; Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length); // Read the subkey (the rest of the payload): must be >= 128 bits int subkeyLength = hashedPassword.Length - 13 - salt.Length; if (subkeyLength < 128 / 8) { return(false); } byte[] expectedSubkey = new byte[subkeyLength]; Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); // Hash the incoming password and verify it byte[] actualSubkey = pbkdf2Provider.DeriveKey(password, salt, iterCount, subkeyLength); return(ByteArraysEqual(actualSubkey, expectedSubkey)); } catch { // This should never occur except in the case of a malformed payload, where // we might go off the end of the array. Regardless, a malformed payload // implies verification failed. return(false); } }