private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested) { // Produce a version 3 (see comment above) text hash. byte[] salt = new byte[saltSize]; rng.GetBytes(salt); byte[] subkey = NetCorePbkdf2Provider.DeriveKey(password, salt, prf, iterCount, numBytesRequested); var outputBytes = new byte[13 + salt.Length + subkey.Length]; outputBytes[0] = 0x01; // format marker WriteNetworkByteOrder(outputBytes, 1, (uint)prf); 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 byte[] HashPasswordV2(string password, RandomNumberGenerator rng) { const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits const int SaltSize = 128 / 8; // 128 bits // Produce a version 2 (see comment above) text hash. byte[] salt = new byte[SaltSize]; rng.GetBytes(salt); byte[] subkey = NetCorePbkdf2Provider.DeriveKey(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength); var outputBytes = new byte[1 + SaltSize + Pbkdf2SubkeyLength]; outputBytes[0] = 0x00; // format marker Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize); Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, Pbkdf2SubkeyLength); return(outputBytes); }
private static bool VerifyHashedPasswordV3(byte[] hashedPassword, string password, out int iterCount) { iterCount = default(int); try { // Read header information KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1); iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5); int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9); // 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 = NetCorePbkdf2Provider.DeriveKey(password, salt, prf, iterCount, subkeyLength); return(CryptographicOperations.FixedTimeEquals(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); } }
private static bool VerifyHashedPasswordV2(byte[] hashedPassword, string password) { const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA1; // default for Rfc2898DeriveBytes const int Pbkdf2IterCount = 1000; // default for Rfc2898DeriveBytes const int Pbkdf2SubkeyLength = 256 / 8; // 256 bits const int SaltSize = 128 / 8; // 128 bits // We know ahead of time the exact length of a valid hashed password payload. if (hashedPassword.Length != 1 + SaltSize + Pbkdf2SubkeyLength) { return(false); // bad size } byte[] salt = new byte[SaltSize]; Buffer.BlockCopy(hashedPassword, 1, salt, 0, salt.Length); byte[] expectedSubkey = new byte[Pbkdf2SubkeyLength]; Buffer.BlockCopy(hashedPassword, 1 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); // Hash the incoming password and verify it byte[] actualSubkey = NetCorePbkdf2Provider.DeriveKey(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength); return(CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey)); }