public byte[] DeriveKey(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
        {
            Debug.Assert(password != null);
            Debug.Assert(salt != null);
            Debug.Assert(iterationCount > 0);
            Debug.Assert(numBytesRequested > 0);

            // PBKDF2 is defined in NIST SP800-132, Sec. 5.3.
            // http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf

            byte[] retVal = new byte[numBytesRequested];
            int numBytesWritten = 0;
            int numBytesRemaining = numBytesRequested;

            // For each block index, U_0 := Salt || block_index
            byte[] saltWithBlockIndex = new byte[checked(salt.Length + sizeof(uint))];
            Buffer.BlockCopy(salt, 0, saltWithBlockIndex, 0, salt.Length);

            using (var hashAlgorithm = PrfToManagedHmacAlgorithm(prf, password))
            {
                for (uint blockIndex = 1; numBytesRemaining > 0; blockIndex++)
                {
                    // write the block index out as big-endian
                    saltWithBlockIndex[saltWithBlockIndex.Length - 4] = (byte)(blockIndex >> 24);
                    saltWithBlockIndex[saltWithBlockIndex.Length - 3] = (byte)(blockIndex >> 16);
                    saltWithBlockIndex[saltWithBlockIndex.Length - 2] = (byte)(blockIndex >> 8);
                    saltWithBlockIndex[saltWithBlockIndex.Length - 1] = (byte)blockIndex;

                    // U_1 = PRF(U_0) = PRF(Salt || block_index)
                    // T_blockIndex = U_1
                    byte[] U_iter = hashAlgorithm.ComputeHash(saltWithBlockIndex); // this is U_1
                    byte[] T_blockIndex = U_iter;

                    for (int iter = 1; iter < iterationCount; iter++)
                    {
                        U_iter = hashAlgorithm.ComputeHash(U_iter);
                        XorBuffers(src: U_iter, dest: T_blockIndex);
                        // At this point, the 'U_iter' variable actually contains U_{iter+1} (due to indexing differences).
                    }

                    // At this point, we're done iterating on this block, so copy the transformed block into retVal.
                    int numBytesToCopy = Math.Min(numBytesRemaining, T_blockIndex.Length);
                    Buffer.BlockCopy(T_blockIndex, 0, retVal, numBytesWritten, numBytesToCopy);
                    numBytesWritten += numBytesToCopy;
                    numBytesRemaining -= numBytesToCopy;
                }
            }

            // retVal := T_1 || T_2 || ... || T_n, where T_n may be truncated to meet the desired output length
            return retVal;
        }
Пример #2
0
        /// <summary>
        /// Performs key derivation using the PBKDF2 algorithm.
        /// </summary>
        /// <param name="password">The password from which to derive the key.</param>
        /// <param name="salt">The salt to be used during the key derivation process.</param>
        /// <param name="prf">The pseudo-random function to be used in the key derivation process.</param>
        /// <param name="iterationCount">The number of iterations of the pseudo-random function to apply
        /// during the key derivation process.</param>
        /// <param name="numBytesRequested">The desired length (in bytes) of the derived key.</param>
        /// <returns>The derived key.</returns>
        /// <remarks>
        /// The PBKDF2 algorithm is specified in RFC 2898.
        /// </remarks>
        public static byte[] Pbkdf2(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
        {
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }

            if (salt == null)
            {
                throw new ArgumentNullException(nameof(salt));
            }

            // parameter checking
            if (prf < KeyDerivationPrf.HMACSHA1 || prf > KeyDerivationPrf.HMACSHA512)
            {
                throw new ArgumentOutOfRangeException(nameof(prf));
            }
            if (iterationCount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(iterationCount));
            }
            if (numBytesRequested <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(numBytesRequested));
            }

            return Pbkdf2Util.Pbkdf2Provider.DeriveKey(password, salt, prf, iterationCount, numBytesRequested);
        }
 private static BCryptAlgorithmHandle PrfToCachedCngAlgorithmInstance(KeyDerivationPrf prf)
 {
     switch (prf)
     {
         case KeyDerivationPrf.HMACSHA1:
             return CachedAlgorithmHandles.HMAC_SHA1;
         case KeyDerivationPrf.HMACSHA256:
             return CachedAlgorithmHandles.HMAC_SHA256;
         case KeyDerivationPrf.HMACSHA512:
             return CachedAlgorithmHandles.HMAC_SHA512;
         default:
             throw CryptoUtil.Fail("Unrecognized PRF.");
     }
 }
Пример #4
0
    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 = KeyDerivation.Pbkdf2(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;
    }
Пример #5
0
        private static byte[] HashPasswordV3(string password, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
        {
            // Produce a version 3 (see comment above) text hash.
            byte[] salt = new byte[saltSize];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }
            byte[] subkey = KeyDerivation.Pbkdf2(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 byte[] ComputeHash(string password, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
        {
            byte[] salt = new byte[saltSize];
            _rng.GetBytes(salt);

            byte[] subkey = _pbdkf2Provider.DeriveKey(password, salt, prf, iterCount, numBytesRequested);

            var outputBytes = new byte[13 + salt.Length + subkey.Length];

            outputBytes[0] = 0x01; // format marker -- version

            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);
        }
Пример #7
0
        public static byte[] HashPasswordV2(string password)
        {
            RandomNumberGenerator  rng       = RandomNumberGenerator.Create();
            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 text hash.
            byte[] salt = new byte[SaltSize];
            rng.GetBytes(salt);
            byte[] subkey = KeyDerivation.Pbkdf2(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);
        }
Пример #8
0
        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.
            var salt = new byte[saltSize];

            rng.GetBytes(salt);
            var subkey = KeyDerivation.Pbkdf2(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);
        }
Пример #9
0
        public static bool VerifyHashedPassword(byte[] hashedPassword, string guess)
        {
            KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1);
            int iterCount        = (int)ReadNetworkByteOrder(hashedPassword, 5);
            int saltLength       = (int)ReadNetworkByteOrder(hashedPassword, 9);

            byte[] salt = new byte[saltLength];
            Buffer.BlockCopy(hashedPassword, 13, salt, 0, salt.Length);

            int subkeyLength = hashedPassword.Length - 13 - salt.Length;

            byte[] expectedSubkey = new byte[subkeyLength];
            Buffer.BlockCopy(hashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);

            // Hash incoming password and verify it
            byte[] actualSubkey = KeyDerivation.Pbkdf2(guess, salt, prf, iterCount, subkeyLength);
            bool   verified     = ByteArraysEqual(actualSubkey, expectedSubkey);

            return(verified);
        }
Пример #10
0
        private static bool VerifyHashedPassword(byte[] hashedPassword, string password)
        {
            int 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 = KeyDerivation.Pbkdf2(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);
            }
        }
Пример #11
0
        private static HashSalt Hash(string word)
        {
            const KeyDerivationPrf Pbkdf2Prf = KeyDerivationPrf.HMACSHA256;
            const int pbkdfIterCount         = 1000;
            const int pbkdf2SubkeyLength     = 256 / 8;
            const int saltSize = 128 / 8;

            byte[] salt = new byte[saltSize];
            RandomNumberGenerator rng = RandomNumberGenerator.Create();

            rng.GetBytes(salt);
            byte[] subkey = KeyDerivation.Pbkdf2(word, salt, Pbkdf2Prf, pbkdfIterCount, pbkdf2SubkeyLength);

            var outputBytes = new byte[1 + saltSize + pbkdf2SubkeyLength];

            outputBytes[0] = 0x00;
            Buffer.BlockCopy(salt, 0, outputBytes, 1, saltSize);
            Buffer.BlockCopy(subkey, 0, outputBytes, 1 + saltSize, pbkdf2SubkeyLength);

            return(new HashSalt(outputBytes, salt));
        }
Пример #12
0
        public byte[] HashUserPassword(string password)
        {
            _logger.LogInformation("Hashing user password");
            const KeyDerivationPrf pbkdf2Prf = KeyDerivationPrf.HMACSHA512; // 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.
            var salt = new byte[saltSize];

            _randomNumberGenerator.Value.GetBytes(salt);
            var subkey = KeyDerivation.Pbkdf2(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);
        }
        /// <summary>
        /// Hash a password using PBKDF2
        /// </summary>
        /// <param name="password">Plain text password to hash</param>
        /// <param name="iteration">Amount of iteration</param>
        /// <param name="salt">Salt used in hashing</param>
        /// <param name="function">Key derivation function</param>
        /// <returns>Byte array of hash</returns>
        public byte[] HashPassword(string password, int iteration, byte[] salt, KeyDerivationPrf function)
        {
            // Use Pbkdf2 on password and salt to create key.
            var key = KeyDerivation.Pbkdf2(
                password: password,
                salt: salt,
                prf: function,
                iterationCount: iteration,
                numBytesRequested: Constants.HashLength);

            // Create hash with the size of salt and key.
            var hashed = new byte[Constants.HashLength + Constants.saltLength];

            // Copy the salt to the hashed array.
            Array.Copy(salt, 0, hashed, 0, Constants.saltLength);

            // Copy the key into the hashed array.
            Array.Copy(key, 0, hashed, Constants.saltLength, Constants.HashLength);

            return(hashed);
        }
Пример #14
0
        public virtual byte[] Encrypt(string password)
        {
            //128 bit salt. 128/8 bytes
            byte[] salt = new byte[SaltSize / 8];
            Random rnd  = new Random(Seed);

            rnd.NextBytes(salt);
            this.Salt = salt;

            // derive a 256-bit subkey (use HMACSHA256 with 10,000 iterations)
            KeyDerivationPrf prf  = KeyDerivationPrf.HMACSHA256;
            int numBytesRequested = 256 / 8;
            int iterationCount    = 1000;

            return(KeyDerivation.Pbkdf2(
                       password: password,
                       salt: salt,
                       prf: prf,
                       iterationCount: iterationCount,
                       numBytesRequested: numBytesRequested
                       ));
        }
        private static BCryptKeyHandle PasswordToPbkdfKeyHandle(string password, BCryptAlgorithmHandle pbkdf2AlgHandle, KeyDerivationPrf prf)
        {
            byte dummy; // CLR doesn't like pinning zero-length buffers, so this provides a valid memory address when working with zero-length buffers

            // Convert password string to bytes.
            // Allocate on the stack whenever we can to save allocations.
            int cbPasswordBuffer = Encoding.UTF8.GetMaxByteCount(password.Length);
            fixed (byte* pbHeapAllocatedPasswordBuffer = (cbPasswordBuffer > Constants.MAX_STACKALLOC_BYTES) ? new byte[cbPasswordBuffer] : null)
            {
                byte* pbPasswordBuffer = pbHeapAllocatedPasswordBuffer;
                if (pbPasswordBuffer == null)
                {
                    if (cbPasswordBuffer == 0)
                    {
                        pbPasswordBuffer = &dummy;
                    }
                    else
                    {
                        byte* pbStackAllocPasswordBuffer = stackalloc byte[cbPasswordBuffer]; // will be released when the frame unwinds
                        pbPasswordBuffer = pbStackAllocPasswordBuffer;
                    }
                }

                try
                {
                    int cbPasswordBufferUsed; // we're not filling the entire buffer, just a partial buffer
                    fixed (char* pszPassword = password)
                    {
                        cbPasswordBufferUsed = Encoding.UTF8.GetBytes(pszPassword, password.Length, pbPasswordBuffer, cbPasswordBuffer);
                    }

                    return PasswordToPbkdfKeyHandleStep2(pbkdf2AlgHandle, pbPasswordBuffer, (uint)cbPasswordBufferUsed, prf);
                }
                finally
                {
                    UnsafeBufferUtil.SecureZeroMemory(pbPasswordBuffer, cbPasswordBuffer);
                }
            }
        }
Пример #16
0
        static void Main(string[] args)
        {
            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 text hash.
            byte[] salt = new byte[SaltSize];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }
            byte[] subkey = KeyDerivation.Pbkdf2(args[0], 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);
            Console.WriteLine($"{Convert.ToBase64String(outputBytes)}");
        }
Пример #17
0
        private static bool VerifyHashInternal(byte[] hashedData, string providedInput)
        {
            try
            {
                // Read header information
                KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedData, 1);
                int iterCount        = (int)ReadNetworkByteOrder(hashedData, 5);
                int saltLength       = (int)ReadNetworkByteOrder(hashedData, 9);

                // Read the salt: must be >= 128 bits
                if (saltLength < 128 / 8)
                {
                    return(false);
                }
                byte[] salt = new byte[saltLength];
                Buffer.BlockCopy(hashedData, 13, salt, 0, salt.Length);

                // Read the subkey (the rest of the payload): must be >= 128 bits
                int subkeyLength = hashedData.Length - 13 - salt.Length;
                if (subkeyLength < 128 / 8)
                {
                    return(false);
                }
                byte[] expectedSubkey = new byte[subkeyLength];
                Buffer.BlockCopy(hashedData, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);

                // Hash the incoming credential and verify it
                byte[] actualSubkey = KeyDerivation.Pbkdf2(providedInput, salt, prf, 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);
            }
        }
Пример #18
0
        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 = KeyDerivation.Pbkdf2(password, salt, Pbkdf2Prf, Pbkdf2IterCount, Pbkdf2SubkeyLength);
            return(ByteArraysEqual(actualSubkey, expectedSubkey));
        }
 private static KeyedHashAlgorithm PrfToManagedHmacAlgorithm(KeyDerivationPrf prf, string password)
 {
     byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
     try
     {
         switch (prf)
         {
             case KeyDerivationPrf.HMACSHA1:
                 return new HMACSHA1(passwordBytes);
             case KeyDerivationPrf.HMACSHA256:
                 return new HMACSHA256(passwordBytes);
             case KeyDerivationPrf.HMACSHA512:
                 return new HMACSHA512(passwordBytes);
             default:
                 throw CryptoUtil.Fail("Unrecognized PRF.");
         }
     }
     finally
     {
         // The HMAC ctor makes a duplicate of this key; we clear original buffer to limit exposure to the GC.
         Array.Clear(passwordBytes, 0, passwordBytes.Length);
     }
 }
Пример #20
0
        private static bool VerifyHashedPassword(byte[] hashedPassword, string password, out int iterCount)
        {
            iterCount = default(int);

            try
            {
                KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(hashedPassword, 1);
                iterCount = (int)ReadNetworkByteOrder(hashedPassword, 5);
                int saltLength = (int)ReadNetworkByteOrder(hashedPassword, 9);

                if (saltLength < 128 / 8)
                {
                    return(false);
                }

                byte[] salt = new byte[saltLength];
                Buffer.BlockCopy(hashedPassword, 13, salt, 0, saltLength);

                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);

                byte[] actualSubKey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, expectedSubKey.Length);

                return(CryptographicOperations.FixedTimeEquals(actualSubKey, expectedSubKey));
            }

            catch
            {
                return(false);
            }
        }
Пример #21
0
        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 = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, subkeyLength);
                return(ByteArraysEqual(actualSubkey, expectedSubkey));
            }
            catch
            {
                return(false);
            }
        }
Пример #22
0
        private static byte[] HashPasswordV3
            (string password,
            RandomNumberGenerator random,
            KeyDerivationPrf prf  = KeyDerivationPrf.HMACSHA256,
            int iterCount         = IterCount,
            int saltSize          = 128 / 8,
            int numBytesRequested = 256 / 8)
        {
            // Produce a version 3 (see comment above) text hash.
            var salt = new byte[saltSize];

            random.GetBytes(salt);
            var subkey      = KeyDerivation.Pbkdf2(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);
        }
Пример #23
0
        private static byte[] DeriveKeyImpl(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
        {
            HashAlgorithmName algorithmName;

            switch (prf)
            {
            case KeyDerivationPrf.HMACSHA1:
                algorithmName = HashAlgorithmName.SHA1;
                break;

            case KeyDerivationPrf.HMACSHA256:
                algorithmName = HashAlgorithmName.SHA256;
                break;

            case KeyDerivationPrf.HMACSHA512:
                algorithmName = HashAlgorithmName.SHA512;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(password), salt, iterationCount, algorithmName, numBytesRequested));
        }
Пример #24
0
        public byte[] DeriveKey(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
        {
            Debug.Assert(password != null);
            Debug.Assert(salt != null);
            Debug.Assert(iterationCount > 0);
            Debug.Assert(numBytesRequested > 0);

            string algorithmName = PrfToCngAlgorithmId(prf);
            fixed (byte* pbHeapAllocatedSalt = salt)
            {
                byte dummy; // CLR doesn't like pinning zero-length buffers, so this provides a valid memory address when working with zero-length buffers
                byte* pbSalt = (pbHeapAllocatedSalt != null) ? pbHeapAllocatedSalt : &dummy;

                byte[] retVal = new byte[numBytesRequested];
                using (BCryptKeyHandle keyHandle = PasswordToPbkdfKeyHandle(password, CachedAlgorithmHandles.PBKDF2, prf))
                {
                    fixed (byte* pbRetVal = retVal)
                    {
                        DeriveKeyCore(keyHandle, algorithmName, pbSalt, (uint)salt.Length, (ulong)iterationCount, pbRetVal, (uint)retVal.Length);
                    }
                    return retVal;
                }
            }
        }
Пример #25
0
        /// <summary>
        /// Verify given hashed value with plan string value after hashing with same settings,
        /// that was provided on hash
        /// </summary>
        /// <param name="hashedValue">string - Encrypted value</param>
        /// <param name="sourceSalt">string - Based 64 string</param>
        /// <param name="sourceToCheck">string - plan text</param>
        /// <param name="iterationCount">integer - Number of iteratation, default is 1000 </param>
        /// <param name="algorithm">Enum type of KeyDerivationPrf, default is HMACSHA256</param>
        /// <returns>boolean - return true if comparision success otherwise returns false</returns>
        public static bool VerifyHashString(string hashedValue, string sourceSalt, string sourceToCheck, int iterationCount = 1000, KeyDerivationPrf algorithm = KeyDerivationPrf.HMACSHA256)
        {
            if (hashedValue == null || sourceSalt == null)
            {
                return(false);
            }
            var salt = Convert.FromBase64String(sourceSalt);

            if (salt == null)
            {
                return(false);
            }
            // hash the given source
            var(hashOfstringToCheck, returnsalt) = GenerateHashString(sourceToCheck, iterationCount, algorithm, salt, true);
            // compare both hashes
            return(String.Compare(hashedValue, hashOfstringToCheck) == 0);
        }
Пример #26
0
        private static BCryptKeyHandle PasswordToPbkdfKeyHandleStep2(BCryptAlgorithmHandle pbkdf2AlgHandle, byte* pbPassword, uint cbPassword, KeyDerivationPrf prf)
        {
            const uint PBKDF2_MAX_KEYLENGTH_IN_BYTES = 2048; // GetSupportedKeyLengths() on a Win8 box; value should never be lowered in any future version of Windows
            if (cbPassword <= PBKDF2_MAX_KEYLENGTH_IN_BYTES)
            {
                // Common case: the password is small enough to be consumed directly by the PBKDF2 algorithm.
                return pbkdf2AlgHandle.GenerateSymmetricKey(pbPassword, cbPassword);
            }
            else
            {
                // Rare case: password is very long; we must hash manually.
                // PBKDF2 uses the PRFs in HMAC mode, and when the HMAC input key exceeds the hash function's
                // block length the key is hashed and run back through the key initialization function.

                BCryptAlgorithmHandle prfAlgorithmHandle; // cached; don't dispose
                switch (prf)
                {
                    case KeyDerivationPrf.HMACSHA1:
                        prfAlgorithmHandle = CachedAlgorithmHandles.SHA1;
                        break;
                    case KeyDerivationPrf.HMACSHA256:
                        prfAlgorithmHandle = CachedAlgorithmHandles.SHA256;
                        break;
                    case KeyDerivationPrf.HMACSHA512:
                        prfAlgorithmHandle = CachedAlgorithmHandles.SHA512;
                        break;
                    default:
                        throw CryptoUtil.Fail("Unrecognized PRF.");
                }

                // Final sanity check: don't hash the password if the HMAC key initialization function wouldn't have done it for us.
                if (cbPassword <= prfAlgorithmHandle.GetHashBlockLength() /* in bytes */)
                {
                    return pbkdf2AlgHandle.GenerateSymmetricKey(pbPassword, cbPassword);
                }

                // Hash the password and use the hash as input to PBKDF2.
                uint cbPasswordDigest = prfAlgorithmHandle.GetHashDigestLength();
                CryptoUtil.Assert(cbPasswordDigest > 0, "cbPasswordDigest > 0");
                fixed (byte* pbPasswordDigest = new byte[cbPasswordDigest])
                {
                    try
                    {
                        using (var hashHandle = prfAlgorithmHandle.CreateHash())
                        {
                            hashHandle.HashData(pbPassword, cbPassword, pbPasswordDigest, cbPasswordDigest);
                        }
                        return pbkdf2AlgHandle.GenerateSymmetricKey(pbPasswordDigest, cbPasswordDigest);
                    }
                    finally
                    {
                        UnsafeBufferUtil.SecureZeroMemory(pbPasswordDigest, cbPasswordDigest);
                    }
                }
            }
        }
Пример #27
0
 private static string PrfToCngAlgorithmId(KeyDerivationPrf prf)
 {
     switch (prf)
     {
         case KeyDerivationPrf.HMACSHA1:
             return Constants.BCRYPT_SHA1_ALGORITHM;
         case KeyDerivationPrf.HMACSHA256:
             return Constants.BCRYPT_SHA256_ALGORITHM;
         case KeyDerivationPrf.HMACSHA512:
             return Constants.BCRYPT_SHA512_ALGORITHM;
         default:
             throw CryptoUtil.Fail("Unrecognized PRF.");
     }
 }
Пример #28
0
        private static BCryptKeyHandle PasswordToPbkdfKeyHandle(string password, BCryptAlgorithmHandle pbkdf2AlgHandle, KeyDerivationPrf prf)
        {
            byte dummy; // CLR doesn't like pinning zero-length buffers, so this provides a valid memory address when working with zero-length buffers

            // Convert password string to bytes.
            // Allocate on the stack whenever we can to save allocations.
            int cbPasswordBuffer = Encoding.UTF8.GetMaxByteCount(password.Length);

            fixed(byte *pbHeapAllocatedPasswordBuffer = (cbPasswordBuffer > Constants.MAX_STACKALLOC_BYTES)?new byte[cbPasswordBuffer] : null)
            {
                byte *pbPasswordBuffer = pbHeapAllocatedPasswordBuffer;

                if (pbPasswordBuffer == null)
                {
                    if (cbPasswordBuffer == 0)
                    {
                        pbPasswordBuffer = &dummy;
                    }
                    else
                    {
                        byte *pbStackAllocPasswordBuffer = stackalloc byte[cbPasswordBuffer]; // will be released when the frame unwinds
                        pbPasswordBuffer = pbStackAllocPasswordBuffer;
                    }
                }

                try
                {
                    int cbPasswordBufferUsed; // we're not filling the entire buffer, just a partial buffer
                    fixed(char *pszPassword = password)
                    {
                        cbPasswordBufferUsed = Encoding.UTF8.GetBytes(pszPassword, password.Length, pbPasswordBuffer, cbPasswordBuffer);
                    }

                    return(PasswordToPbkdfKeyHandleStep2(pbkdf2AlgHandle, pbPasswordBuffer, (uint)cbPasswordBufferUsed, prf));
                }
                finally
                {
                    UnsafeBufferUtil.SecureZeroMemory(pbPasswordBuffer, cbPasswordBuffer);
                }
            }
        }
Пример #29
0
        private static BCryptKeyHandle PasswordToPbkdfKeyHandleStep2(BCryptAlgorithmHandle pbkdf2AlgHandle, byte *pbPassword, uint cbPassword, KeyDerivationPrf prf)
        {
            const uint PBKDF2_MAX_KEYLENGTH_IN_BYTES = 2048; // GetSupportedKeyLengths() on a Win8 box; value should never be lowered in any future version of Windows

            if (cbPassword <= PBKDF2_MAX_KEYLENGTH_IN_BYTES)
            {
                // Common case: the password is small enough to be consumed directly by the PBKDF2 algorithm.
                return(pbkdf2AlgHandle.GenerateSymmetricKey(pbPassword, cbPassword));
            }
            else
            {
                // Rare case: password is very long; we must hash manually.
                // PBKDF2 uses the PRFs in HMAC mode, and when the HMAC input key exceeds the hash function's
                // block length the key is hashed and run back through the key initialization function.

                BCryptAlgorithmHandle prfAlgorithmHandle; // cached; don't dispose
                switch (prf)
                {
                case KeyDerivationPrf.Sha1:
                    prfAlgorithmHandle = CachedAlgorithmHandles.SHA1;
                    break;

                case KeyDerivationPrf.Sha256:
                    prfAlgorithmHandle = CachedAlgorithmHandles.SHA256;
                    break;

                case KeyDerivationPrf.Sha512:
                    prfAlgorithmHandle = CachedAlgorithmHandles.SHA512;
                    break;

                default:
                    throw CryptoUtil.Fail("Unrecognized PRF.");
                }

                // Final sanity check: don't hash the password if the HMAC key initialization function wouldn't have done it for us.
                if (cbPassword <= prfAlgorithmHandle.GetHashBlockLength() /* in bytes */)
                {
                    return(pbkdf2AlgHandle.GenerateSymmetricKey(pbPassword, cbPassword));
                }

                // Hash the password and use the hash as input to PBKDF2.
                uint cbPasswordDigest = prfAlgorithmHandle.GetHashDigestLength();
                CryptoUtil.Assert(cbPasswordDigest > 0, "cbPasswordDigest > 0");
                fixed(byte *pbPasswordDigest = new byte[cbPasswordDigest])
                {
                    try
                    {
                        using (var hashHandle = prfAlgorithmHandle.CreateHash())
                        {
                            hashHandle.HashData(pbPassword, cbPassword, pbPasswordDigest, cbPasswordDigest);
                        }
                        return(pbkdf2AlgHandle.GenerateSymmetricKey(pbPasswordDigest, cbPasswordDigest));
                    }
                    finally
                    {
                        UnsafeBufferUtil.SecureZeroMemory(pbPasswordDigest, cbPasswordDigest);
                    }
                }
            }
        }
Пример #30
0
        public byte[] DeriveKey(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
        {
            Debug.Assert(password != null);
            Debug.Assert(salt != null);
            Debug.Assert(iterationCount > 0);
            Debug.Assert(numBytesRequested > 0);

            byte dummy; // CLR doesn't like pinning zero-length buffers, so this provides a valid memory address when working with zero-length buffers

            // Don't dispose of this algorithm instance; it is cached and reused!
            var algHandle = PrfToCachedCngAlgorithmInstance(prf);

            // Convert password string to bytes.
            // Allocate on the stack whenever we can to save allocations.
            int cbPasswordBuffer = Encoding.UTF8.GetMaxByteCount(password.Length);
            fixed (byte* pbHeapAllocatedPasswordBuffer = (cbPasswordBuffer > Constants.MAX_STACKALLOC_BYTES) ? new byte[cbPasswordBuffer] : null)
            {
                byte* pbPasswordBuffer = pbHeapAllocatedPasswordBuffer;
                if (pbPasswordBuffer == null)
                {
                    if (cbPasswordBuffer == 0)
                    {
                        pbPasswordBuffer = &dummy;
                    }
                    else
                    {
                        byte* pbStackAllocPasswordBuffer = stackalloc byte[cbPasswordBuffer]; // will be released when the frame unwinds
                        pbPasswordBuffer = pbStackAllocPasswordBuffer;
                    }
                }

                try
                {
                    int cbPasswordBufferUsed; // we're not filling the entire buffer, just a partial buffer
                    fixed (char* pszPassword = password)
                    {
                        cbPasswordBufferUsed = Encoding.UTF8.GetBytes(pszPassword, password.Length, pbPasswordBuffer, cbPasswordBuffer);
                    }

                    fixed (byte* pbHeapAllocatedSalt = salt)
                    {
                        byte* pbSalt = (pbHeapAllocatedSalt != null) ? pbHeapAllocatedSalt : &dummy;

                        byte[] retVal = new byte[numBytesRequested];
                        fixed (byte* pbRetVal = retVal)
                        {
                            int ntstatus = UnsafeNativeMethods.BCryptDeriveKeyPBKDF2(
                                hPrf: algHandle,
                                pbPassword: pbPasswordBuffer,
                                cbPassword: (uint)cbPasswordBufferUsed,
                                pbSalt: pbSalt,
                                cbSalt: (uint)salt.Length,
                                cIterations: (ulong)iterationCount,
                                pbDerivedKey: pbRetVal,
                                cbDerivedKey: (uint)retVal.Length,
                                dwFlags: 0);
                            UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus);
                        }
                        return retVal;
                    }
                }
                finally
                {
                    UnsafeBufferUtil.SecureZeroMemory(pbPasswordBuffer, cbPasswordBuffer);
                }
            }
        }
Пример #31
0
        /// <summary>
        /// Simplified version of https://github.com/dotnet/aspnetcore/blob/9428ac6f4c2103227c46a4da23b4de9cb780dc08/src/Identity/Extensions.Core/src/PasswordHasher.cs#L141
        /// Uses a fixed salt, as we need reproducible results
        /// </summary>
        private string Hash(string original, byte[] salt, KeyDerivationPrf prf, int iterCount, int numBytesRequested)
        {
            var hashBytes = KeyDerivation.Pbkdf2(original, salt, prf, iterCount, numBytesRequested);

            return(Convert.ToBase64String(hashBytes));
        }
Пример #32
0
 public static IServiceCollection RegisterCryptographicCredentials <TCryptographicCredentials>(this IServiceCollection services,
                                                                                               KeyDerivationPrf keyDerivationPrf, Encoding encoding, string password,
                                                                                               string salt, int iterations, int totalNumberOfBytes, IEnumerable <byte> initialVector)
     where TCryptographicCredentials : ICryptographicCredentials
 {
     return(services.AddSingleton <ICryptographicCredentials>(serviceProvider => serviceProvider
                                                              .GetRequiredService <ICryptographyProvider>()
                                                              .GetCryptographicCredentials <TCryptographicCredentials>(keyDerivationPrf, encoding, password, salt,
                                                                                                                       iterations, totalNumberOfBytes, initialVector)));
 }
Пример #33
0
 static PasswordHelper()
 {
     HashType = KeyDerivationPrf.HMACSHA512;
 }
Пример #34
0
        /// <summary>
        /// Generate hash value using Password-Based Key Derivation Function 2
        /// </summary>
        /// <param name="targetValue">string - Value to be hash</param>
        /// <param name="iterationCount">integer - Number of iteratation, default is 1000 </param>
        /// <param name="algorithm">KeyDerivationPrf - Enum type of KeyDerivationPrf, default is HMACSHA256 </param>
        /// <param name="salt">byte[] - 128/8 byte code, default is null</param>
        /// <param name="needsOnlyHash">boolean - condition to return hash</param>
        /// <returns>type Tuple - (hashed value, salt value)</returns>
        public static (string, string) GenerateHashString(string targetValue, int iterationCount = 1000, KeyDerivationPrf algorithm = KeyDerivationPrf.HMACSHA256, byte[] salt = null, bool needsOnlyHash = false)
        {
            if (salt == null || salt.Length != 16)
            {
                // generate a 128-bit salt using a secure PRNG
                salt          = new byte[128 / 8];
                using var rng = RandomNumberGenerator.Create();
                rng.GetBytes(salt);
            }

            string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
                                                       password: targetValue,
                                                       salt: salt,
                                                       prf: algorithm,
                                                       iterationCount: iterationCount,
                                                       numBytesRequested: 256 / 8));

            if (needsOnlyHash)
            {
                return(hashed, string.Empty);
            }

            return(hashed, Convert.ToBase64String(salt));
        }
Пример #35
0
        public string DeriveKey(string passphrase, byte[] salt, int iterationCount = 10000, KeyDerivationPrf prf = KeyDerivationPrf.HMACSHA256, int numBytes = 32)
        {
            var key = KeyDerivation.Pbkdf2(
                password: passphrase,
                salt: salt,
                prf: prf,
                iterationCount: iterationCount,
                numBytesRequested: numBytes
                );

            return(key.ToHex());
        }
Пример #36
0
        private static byte[] HashPasswordV3(string password, RandomNumberGenerator rng, KeyDerivationPrf prf, int iterCount, int saltSize, int numBytesRequested)
        {
            byte[] salt = new byte[saltSize];
            rng.GetBytes(salt);
            byte[] subkey = KeyDerivation.Pbkdf2(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);
        }
Пример #37
0
 public SecretKeyGenerator(KeyDerivationPrf algorithm) => Algorithm = AssertUtils.AssertNotNull(algorithm);
Пример #38
0
 public static string PrfName(KeyDerivationPrf prf)
 {
     return(Enum.GetName(typeof(KeyDerivationPrf), prf));
 }
 public static string GeneratePasswordHash(this string password, KeyDerivationPrf prf = KeyDerivationPrf.HMACSHA256, int iterationCount = 10000, int saltSize = 16)
 {
     return(PasswordManager.GeneratePasswordHash(password, prf, iterationCount, saltSize));
 }
Пример #40
0
    public byte[] DeriveKey(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
    {
        Debug.Assert(password != null);
        Debug.Assert(salt != null);
        Debug.Assert(iterationCount > 0);
        Debug.Assert(numBytesRequested > 0);

        byte dummy; // CLR doesn't like pinning zero-length buffers, so this provides a valid memory address when working with zero-length buffers

        // Don't dispose of this algorithm instance; it is cached and reused!
        var algHandle = PrfToCachedCngAlgorithmInstance(prf);

        // Convert password string to bytes.
        // Allocate on the stack whenever we can to save allocations.
        int cbPasswordBuffer = Encoding.UTF8.GetMaxByteCount(password.Length);

        fixed(byte *pbHeapAllocatedPasswordBuffer = (cbPasswordBuffer > Constants.MAX_STACKALLOC_BYTES)?new byte[cbPasswordBuffer] : null)
        {
            byte *pbPasswordBuffer = pbHeapAllocatedPasswordBuffer;

            if (pbPasswordBuffer == null)
            {
                if (cbPasswordBuffer == 0)
                {
                    pbPasswordBuffer = &dummy;
                }
                else
                {
                    byte *pbStackAllocPasswordBuffer = stackalloc byte[cbPasswordBuffer]; // will be released when the frame unwinds
                    pbPasswordBuffer = pbStackAllocPasswordBuffer;
                }
            }

            try
            {
                int cbPasswordBufferUsed; // we're not filling the entire buffer, just a partial buffer
                fixed(char *pszPassword = password)
                {
                    cbPasswordBufferUsed = Encoding.UTF8.GetBytes(pszPassword, password.Length, pbPasswordBuffer, cbPasswordBuffer);
                }

                fixed(byte *pbHeapAllocatedSalt = salt)
                {
                    byte *pbSalt = (pbHeapAllocatedSalt != null) ? pbHeapAllocatedSalt : &dummy;

                    byte[] retVal = new byte[numBytesRequested];
                    fixed(byte *pbRetVal = retVal)
                    {
                        int ntstatus = UnsafeNativeMethods.BCryptDeriveKeyPBKDF2(
                            hPrf: algHandle,
                            pbPassword: pbPasswordBuffer,
                            cbPassword: (uint)cbPasswordBufferUsed,
                            pbSalt: pbSalt,
                            cbSalt: (uint)salt.Length,
                            cIterations: (ulong)iterationCount,
                            pbDerivedKey: pbRetVal,
                            cbDerivedKey: (uint)retVal.Length,
                            dwFlags: 0);

                        UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus);
                    }
                    return(retVal);
                }
            }
            finally
            {
                UnsafeBufferUtil.SecureZeroMemory(pbPasswordBuffer, cbPasswordBuffer);
            }
        }
    }