private byte[] HashPassword(string password, RandomNumberGenerator rng, Pbkdf2Provider pbkdf2Provider) { return(HashPasswordV3(password, iterCount: _pbkdf2IterCount, saltSize: _saltSize, numBytesRequested: _pbkdf2SubkeyLength, rng: rng, pbkdf2Provider: pbkdf2Provider)); }
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 const int _saltSize = 128 / 8; // 128 bits /// <summary> /// Creates a new instance of <see cref="PasswordHasher{TUser}"/>. /// </summary> /// <param name="optionsAccessor">The options for this instance.</param> public SimplePasswordHasher() { _rng = RandomNumberGenerator.Create(); _pbkdf2Provider = new Pbkdf2Provider(); }
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); } }