internal HashProviderCng(string hashAlgId, ReadOnlySpan <byte> key, bool isHmac) { BCryptOpenAlgorithmProviderFlags dwFlags = BCryptOpenAlgorithmProviderFlags.None; if (isHmac) { _key = key.ToArray(); dwFlags |= BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG; } _hAlgorithm = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle(hashAlgId, dwFlags, out _hashSize); // Win7 won't set hHash, Win8+ will; and both will set _hHash. // So keep hHash trapped in this scope to prevent (mis-)use of it. { SafeBCryptHashHandle?hHash = null; NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash(_hAlgorithm, out hHash, IntPtr.Zero, 0, key, key == null ? 0 : key.Length, BCryptCreateHashFlags.BCRYPT_HASH_REUSABLE_FLAG); if (ntStatus == NTSTATUS.STATUS_INVALID_PARAMETER) { // If we got here, we're running on a downlevel OS (pre-Win8) that doesn't support reusable CNG hash objects. Fall back to creating a // new HASH object each time. ResetHashObject(); } else if (ntStatus != NTSTATUS.STATUS_SUCCESS) { throw Interop.BCrypt.CreateCryptographicException(ntStatus); } else { _hHash = hHash; _reusable = true; } } }
internal LiteHash(string algorithm) { BCryptOpenAlgorithmProviderFlags algorithmFlags = BCryptOpenAlgorithmProviderFlags.None; // This is a shared handle, do not put this in a using. SafeBCryptAlgorithmHandle algorithmHandle = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle( algorithm, algorithmFlags, out _hashSizeInBytes); SafeBCryptHashHandle hashHandle; NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash( algorithmHandle, out hashHandle, pbHashObject: IntPtr.Zero, cbHashObject: 0, secret: ReadOnlySpan <byte> .Empty, cbSecret: 0, BCryptCreateHashFlags.None); if (ntStatus != NTSTATUS.STATUS_SUCCESS) { hashHandle.Dispose(); throw Interop.BCrypt.CreateCryptographicException(ntStatus); } _hashHandle = hashHandle; }
private static unsafe void FillDeriveKeyPBKDF2( ReadOnlySpan <byte> password, ReadOnlySpan <byte> salt, int iterations, string hashAlgorithmName, Span <byte> destination) { const BCryptOpenAlgorithmProviderFlags OpenAlgorithmFlags = BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG; // This code path will only be taken on Windows 7, so we can assume pseudo handles are not supported. // Do not dispose handle since it is shared and cached. SafeBCryptAlgorithmHandle handle = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle(hashAlgorithmName, OpenAlgorithmFlags, out _); fixed(byte *pPassword = password) fixed(byte *pSalt = salt) fixed(byte *pDestination = destination) { NTSTATUS status = Interop.BCrypt.BCryptDeriveKeyPBKDF2( handle, pPassword, password.Length, pSalt, salt.Length, (ulong)iterations, pDestination, destination.Length, dwFlags: 0); if (status != NTSTATUS.STATUS_SUCCESS) { throw Interop.BCrypt.CreateCryptographicException(status); } } }
// // - "hashAlgId" must be a name recognized by BCryptOpenAlgorithmProvider(). Examples: MD5, SHA1, SHA256. // // - "key" activates MAC hashing if present. If null, this HashProvider performs a regular old hash. // public HashProviderCng(string hashAlgId, byte[] key) { BCryptOpenAlgorithmProviderFlags dwFlags = BCryptOpenAlgorithmProviderFlags.None; if (key != null) { _key = key.CloneByteArray(); dwFlags |= BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG; } _hAlgorithm = Interop.BCrypt.BCryptAlgorithmCache.GetCachedBCryptAlgorithmHandle(hashAlgId, dwFlags); // Win7 won't set hHash, Win8+ will; and both will set _hHash. // So keep hHash trapped in this scope to prevent (mis-)use of it. { SafeBCryptHashHandle hHash = null; NTSTATUS ntStatus = Interop.BCrypt.BCryptCreateHash(_hAlgorithm, out hHash, IntPtr.Zero, 0, key, key == null ? 0 : key.Length, BCryptCreateHashFlags.BCRYPT_HASH_REUSABLE_FLAG); if (ntStatus == NTSTATUS.STATUS_INVALID_PARAMETER) { // If we got here, we're running on a downlevel OS (pre-Win8) that doesn't support reusable CNG hash objects. Fall back to creating a // new HASH object each time. ResetHashObject(); } else if (ntStatus != NTSTATUS.STATUS_SUCCESS) { throw Interop.BCrypt.CreateCryptographicException(ntStatus); } else { _hHash = hHash; //begin: gost if (hashAlgId != GostConstants.GOST3411_STRING) { //end: gost _reusable = true; //begin: gost } //end: gost } } unsafe { int cbSizeOfHashSize; int hashSize; NTSTATUS ntStatus = Interop.BCrypt.BCryptGetProperty(_hHash, Interop.BCrypt.BCryptPropertyStrings.BCRYPT_HASH_LENGTH, &hashSize, sizeof(int), out cbSizeOfHashSize, 0); if (ntStatus != NTSTATUS.STATUS_SUCCESS) { throw Interop.BCrypt.CreateCryptographicException(ntStatus); } _hashSize = hashSize; } return; }