From 6bc6da1c7d709bc6cef8d27c4e7d2ad115929b22 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Tue, 15 Apr 2014 22:10:09 -0700 Subject: [PATCH] Fix build break: inadvertently removed PBKDF2.cs and related functionality --- .../Algorithms.cs | 21 +++--- .../PBKDF2.cs | 65 +++++++++++++++++++ .../UnsafeNativeMethods.cs | 13 ++++ 3 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 src/Microsoft.AspNet.Security.DataProtection/PBKDF2.cs diff --git a/src/Microsoft.AspNet.Security.DataProtection/Algorithms.cs b/src/Microsoft.AspNet.Security.DataProtection/Algorithms.cs index a2e3589613..bd721c207c 100644 --- a/src/Microsoft.AspNet.Security.DataProtection/Algorithms.cs +++ b/src/Microsoft.AspNet.Security.DataProtection/Algorithms.cs @@ -31,11 +31,11 @@ namespace Microsoft.AspNet.Security.DataProtection return algHandle; } - private static BCryptAlgorithmHandle CreateHMACSHA256AlgorithmHandle() + + internal static BCryptAlgorithmHandle CreateGenericHMACHandleFromPrimitiveProvider(string algorithmName) { - // create the HMACSHA-256 instance BCryptAlgorithmHandle algHandle; - int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SHA256_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG); + int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, algorithmName, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG); if (status != 0 || algHandle == null || algHandle.IsInvalid) { throw new CryptographicException(status); @@ -44,17 +44,16 @@ namespace Microsoft.AspNet.Security.DataProtection return algHandle; } + private static BCryptAlgorithmHandle CreateHMACSHA256AlgorithmHandle() + { + // create the HMACSHA-256 instance + return CreateGenericHMACHandleFromPrimitiveProvider(Constants.BCRYPT_SHA256_ALGORITHM); + } + private static BCryptAlgorithmHandle CreateHMACSHA512AlgorithmHandle() { // create the HMACSHA-512 instance - BCryptAlgorithmHandle algHandle; - int status = UnsafeNativeMethods.BCryptOpenAlgorithmProvider(out algHandle, Constants.BCRYPT_SHA512_ALGORITHM, Constants.MS_PRIMITIVE_PROVIDER, dwFlags: BCryptAlgorithmFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG); - if (status != 0 || algHandle == null || algHandle.IsInvalid) - { - throw new CryptographicException(status); - } - - return algHandle; + return CreateGenericHMACHandleFromPrimitiveProvider(Constants.BCRYPT_SHA512_ALGORITHM); } } } diff --git a/src/Microsoft.AspNet.Security.DataProtection/PBKDF2.cs b/src/Microsoft.AspNet.Security.DataProtection/PBKDF2.cs new file mode 100644 index 0000000000..c8824b37c1 --- /dev/null +++ b/src/Microsoft.AspNet.Security.DataProtection/PBKDF2.cs @@ -0,0 +1,65 @@ +using System; +using System.Security.Cryptography; + +namespace Microsoft.AspNet.Security.DataProtection +{ + /// + /// Helper class to derive keys from low-entropy passwords using the PBKDF2 algorithm. + /// + public static class PBKDF2 + { + /// + /// Derives a key from a low-entropy password. + /// + /// The name of the PRF to use for key derivation. + /// The low-entropy password from which to generate a key. + /// The salt used to randomize the key derivation. + /// The number of iterations to perform. + /// The desired byte length of the derived key. + /// A key derived from the provided password. + /// For compatibility with the Rfc2898DeriveBytes class, specify "SHA1" for the algorithmName parameter. + public unsafe static byte[] DeriveKey(string algorithmName, byte[] password, byte[] salt, ulong iterationCount, uint numBytesToDerive) + { + if (String.IsNullOrEmpty(algorithmName)) + { + throw new ArgumentException(Res.Common_NullOrEmpty, "algorithmName"); + } + if (password == null || password.Length == 0) + { + throw new ArgumentException(Res.Common_NullOrEmpty, "password"); + } + if (salt == null || salt.Length == 0) + { + throw new ArgumentException(Res.Common_NullOrEmpty, "salt"); + } + if (iterationCount <= 0) + { + throw new ArgumentOutOfRangeException("iterationCount"); + } + + byte[] derivedKey = new byte[numBytesToDerive]; + int status; + + using (BCryptAlgorithmHandle algHandle = Algorithms.CreateGenericHMACHandleFromPrimitiveProvider(algorithmName)) + { + fixed (byte* pPassword = password) + fixed (byte* pSalt = salt) + fixed (byte* pDerivedKey = derivedKey) + { + status = UnsafeNativeMethods.BCryptDeriveKeyPBKDF2( + algHandle, pPassword, (uint)password.Length, pSalt, (uint)salt.Length, iterationCount, + pDerivedKey, numBytesToDerive, dwFlags: 0); + } + } + + if (status == 0 /* STATUS_SUCCESS */) + { + return derivedKey; + } + else + { + throw new CryptographicException(status); + } + } + } +} diff --git a/src/Microsoft.AspNet.Security.DataProtection/UnsafeNativeMethods.cs b/src/Microsoft.AspNet.Security.DataProtection/UnsafeNativeMethods.cs index 88e8eb961a..086de32397 100644 --- a/src/Microsoft.AspNet.Security.DataProtection/UnsafeNativeMethods.cs +++ b/src/Microsoft.AspNet.Security.DataProtection/UnsafeNativeMethods.cs @@ -46,6 +46,19 @@ namespace Microsoft.AspNet.Security.DataProtection [Out] out uint pcbResult, [In] BCryptEncryptFlags dwFlags); + [DllImport(BCRYPT_LIB, CallingConvention = CallingConvention.Winapi)] + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd433795(v=vs.85).aspx + internal static extern int BCryptDeriveKeyPBKDF2( + [In] BCryptAlgorithmHandle hPrf, + [In] byte* pbPassword, + [In] uint cbPassword, + [In] byte* pbSalt, + [In] uint cbSalt, + [In] ulong cIterations, + [In] byte* pbDerivedKey, + [In] uint cbDerivedKey, + [In] uint dwFlags); + [DllImport(BCRYPT_LIB, CallingConvention = CallingConvention.Winapi)] // http://msdn.microsoft.com/en-us/library/windows/desktop/aa375399(v=vs.85).aspx internal static extern int BCryptDestroyHash(