/// <summary> /// Compute the PBKDF2 function on the given inputs using the CNG implementation in the <c>BCryptKeyDerivation</c> API. /// </summary> /// <param name="hashName">The hash function to use, must be one of the strings in <seealso cref="PBKDF2HashAlgorithm"/>.</param> /// <param name="password">The password, as a byte array (i.e., without a string termination character).</param> /// <param name="salt">The salt, a cryptographically random value. Should be 16-bytes or longer.</param> /// <param name="cIterations">The number of iterations of PBKDF2 to apply.</param> /// <returns>The digest of the password (also sometimes called derived key). The length of the digest /// will be equal to the length of the chosen hash function output.</returns> /// <remarks> /// See http://msdn.microsoft.com/en-us/library/windows/desktop/hh448506 for a description /// of the wrapped function. Larger values of cIterations will cause the function to use more /// CPU time, and will also increase the workfactor for an attacker in a brute-force attack. /// </remarks> public static byte[] ComputeHash(string hashName, byte[] password, byte[] salt, Int64 cIterations) { if (cIterations < 1) { throw new ArgumentException("Iteration count must be greater than zero.", "cIterations"); } if (salt == null) { throw new ArgumentException("Salt must be non-null", "salt"); } if (password == null) { throw new ArgumentException("Password must be non-null", "password"); } if (!PBKDF2HashAlgorithm.ValidateHashName(hashName)) { throw new ArgumentException("Invalid hash name for PBKDF2"); } byte[] digest = null; double vers = Environment.OSVersion.Version.Major + Environment.OSVersion.Version.Minor * 0.1; if (vers > 6.1) { // The BCryptKeyDerivation API is only supported on Win8/Server 2012 and above digest = BCryptNative.PBKDF2BCryptKeyDerivation(hashName, password, salt, (UInt64)cIterations); } else { // Fall back to BCryptDeriveKeyPBKDF2, which is roughly 2x slower on systems without the KeyDerivation API digest = BCryptNative.PBKDF2BCryptDeriveKeyPBKDF2(hashName, password, salt, (UInt64)cIterations); } return(digest); }