public static byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) { // The classes that call us are sealed and their base class has checked this already. Debug.Assert(data != null); Debug.Assert(count >= 0 && count <= data.Length); Debug.Assert(offset >= 0 && offset <= data.Length - count); Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); #if NET5_0_OR_GREATER ReadOnlySpan <byte> source = data.AsSpan(offset, count); return (hashAlgorithm == HashAlgorithmName.SHA256 ? SHA256.HashData(source) : hashAlgorithm == HashAlgorithmName.SHA1 ? SHA1.HashData(source) : hashAlgorithm == HashAlgorithmName.SHA512 ? SHA512.HashData(source) : hashAlgorithm == HashAlgorithmName.SHA384 ? SHA384.HashData(source) : hashAlgorithm == HashAlgorithmName.MD5 ? MD5.HashData(source) : throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)); #else using (HashAlgorithm hasher = GetHashAlgorithm(hashAlgorithm)) { return(hasher.ComputeHash(data, offset, count)); } #endif }
private static byte[] GetHashForChannelBinding(X509Certificate2 cert) { Oid signatureAlgorithm = cert.SignatureAlgorithm; switch (signatureAlgorithm.Value) { // RFC 5929 4.1 says that MD5 and SHA1 both upgrade to SHA256 for cbt calculation case "1.2.840.113549.2.5": // MD5 case "1.2.840.113549.1.1.4": // MD5RSA case "1.3.14.3.2.26": // SHA1 case "1.2.840.10040.4.3": // SHA1DSA case "1.2.840.10045.4.1": // SHA1ECDSA case "1.2.840.113549.1.1.5": // SHA1RSA case "2.16.840.1.101.3.4.2.1": // SHA256 case "1.2.840.10045.4.3.2": // SHA256ECDSA case "1.2.840.113549.1.1.11": // SHA256RSA return(SHA256.HashData(cert.RawDataMemory.Span)); case "2.16.840.1.101.3.4.2.2": // SHA384 case "1.2.840.10045.4.3.3": // SHA384ECDSA case "1.2.840.113549.1.1.12": // SHA384RSA return(SHA384.HashData(cert.RawDataMemory.Span)); case "2.16.840.1.101.3.4.2.3": // SHA512 case "1.2.840.10045.4.3.4": // SHA512ECDSA case "1.2.840.113549.1.1.13": // SHA512RSA return(SHA512.HashData(cert.RawDataMemory.Span)); default: throw new ArgumentException(signatureAlgorithm.Value); } }
public static byte[] HashData(HashAlgorithmName hashName, ReadOnlySpan <byte> data) { return(hashName.Name switch { "SHA1" => SHA1.HashData(data), "SHA256" or "HS256" or "RS256" or "ES256" or "PS256" => SHA256.HashData(data), "SHA384" or "HS384" or "RS384" or "ES384" or "PS384" => SHA384.HashData(data), "SHA512" or "HS512" or "RS512" or "ES512" or "PS512" => SHA512.HashData(data), _ => throw new ArgumentOutOfRangeException(nameof(hashName)), });
public static byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) { // The classes that call us are sealed and their base class has checked this already. Debug.Assert(data != null); Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); return (hashAlgorithm == HashAlgorithmName.SHA256 ? SHA256.HashData(data) : hashAlgorithm == HashAlgorithmName.SHA1 ? SHA1.HashData(data) : hashAlgorithm == HashAlgorithmName.SHA512 ? SHA512.HashData(data) : hashAlgorithm == HashAlgorithmName.SHA384 ? SHA384.HashData(data) : hashAlgorithm == HashAlgorithmName.MD5 ? MD5.HashData(data) : throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)); }
protected override byte[] HashData(Stream source) => SHA384.HashData(source);
protected override int HashData(Stream source, Span <byte> destination) => SHA384.HashData(source, destination);
protected override int HashData(ReadOnlySpan <byte> source, Span <byte> destination) => SHA384.HashData(source, destination);
protected override byte[] HashData(ReadOnlySpan <byte> source) => SHA384.HashData(source);
private static unsafe void FillKeyDerivation( ReadOnlySpan <byte> password, ReadOnlySpan <byte> salt, int iterations, string hashAlgorithmName, Span <byte> destination) { SafeBCryptKeyHandle keyHandle; int hashBlockSizeBytes = GetHashBlockSize(hashAlgorithmName); // stackalloc 0 to let compiler know this cannot escape. Span <byte> clearSpan = stackalloc byte[0]; ReadOnlySpan <byte> symmetricKeyMaterial = stackalloc byte[0]; int symmetricKeyMaterialLength; if (password.IsEmpty) { // CNG won't accept a null pointer for the password. symmetricKeyMaterial = stackalloc byte[1]; symmetricKeyMaterialLength = 0; clearSpan = default; } else if (password.Length <= hashBlockSizeBytes) { // Password is small enough to use as-is. symmetricKeyMaterial = password; symmetricKeyMaterialLength = password.Length; clearSpan = default; } else { // RFC 2104: "The key for HMAC can be of any length (keys longer than B bytes are // first hashed using H). // We denote by B the byte-length of such // blocks (B=64 for all the above mentioned examples of hash functions) // // Windows' PBKDF2 will do this up to a point. To ensure we accept arbitrary inputs for // PBKDF2, we do the hashing ourselves. Span <byte> hashBuffer = stackalloc byte[512 / 8]; // 64 bytes is SHA512, the largest digest handled. int hashBufferSize; switch (hashAlgorithmName) { case HashAlgorithmNames.SHA1: hashBufferSize = SHA1.HashData(password, hashBuffer); break; case HashAlgorithmNames.SHA256: hashBufferSize = SHA256.HashData(password, hashBuffer); break; case HashAlgorithmNames.SHA384: hashBufferSize = SHA384.HashData(password, hashBuffer); break; case HashAlgorithmNames.SHA512: hashBufferSize = SHA512.HashData(password, hashBuffer); break; default: Debug.Fail($"Unexpected hash algorithm '{hashAlgorithmName}'"); throw new CryptographicException(); } clearSpan = hashBuffer.Slice(0, hashBufferSize); symmetricKeyMaterial = clearSpan; symmetricKeyMaterialLength = hashBufferSize; } Debug.Assert(symmetricKeyMaterial.Length > 0); NTSTATUS generateKeyStatus; if (Interop.BCrypt.PseudoHandlesSupported) { fixed(byte *pSymmetricKeyMaterial = symmetricKeyMaterial) { generateKeyStatus = Interop.BCrypt.BCryptGenerateSymmetricKey( (nuint)BCryptAlgPseudoHandle.BCRYPT_PBKDF2_ALG_HANDLE, out keyHandle, pbKeyObject: IntPtr.Zero, cbKeyObject: 0, pSymmetricKeyMaterial, symmetricKeyMaterialLength, dwFlags: 0); } } else { if (s_pbkdf2AlgorithmHandle is null) { NTSTATUS openStatus = Interop.BCrypt.BCryptOpenAlgorithmProvider( out SafeBCryptAlgorithmHandle pbkdf2AlgorithmHandle, Internal.NativeCrypto.BCryptNative.AlgorithmName.Pbkdf2, null, BCryptOpenAlgorithmProviderFlags.None); if (openStatus != NTSTATUS.STATUS_SUCCESS) { pbkdf2AlgorithmHandle.Dispose(); CryptographicOperations.ZeroMemory(clearSpan); throw Interop.BCrypt.CreateCryptographicException(openStatus); } // This might race, and that's okay. Worst case the algorithm is opened // more than once, and the ones that lost will get cleaned up during collection. Interlocked.CompareExchange(ref s_pbkdf2AlgorithmHandle, pbkdf2AlgorithmHandle, null); } fixed(byte *pSymmetricKeyMaterial = symmetricKeyMaterial) { generateKeyStatus = Interop.BCrypt.BCryptGenerateSymmetricKey( s_pbkdf2AlgorithmHandle, out keyHandle, pbKeyObject: IntPtr.Zero, cbKeyObject: 0, pSymmetricKeyMaterial, symmetricKeyMaterialLength, dwFlags: 0); } } CryptographicOperations.ZeroMemory(clearSpan); if (generateKeyStatus != NTSTATUS.STATUS_SUCCESS) { keyHandle.Dispose(); throw Interop.BCrypt.CreateCryptographicException(generateKeyStatus); } Debug.Assert(!keyHandle.IsInvalid); ulong kdfIterations = (ulong)iterations; // Previously asserted to be positive. using (keyHandle) fixed(char *pHashAlgorithmName = hashAlgorithmName) fixed(byte *pSalt = salt) fixed(byte *pDestination = destination) { Span <BCryptBuffer> buffers = stackalloc BCryptBuffer[3]; buffers[0].BufferType = CngBufferDescriptors.KDF_ITERATION_COUNT; buffers[0].pvBuffer = (IntPtr)(&kdfIterations); buffers[0].cbBuffer = sizeof(ulong); buffers[1].BufferType = CngBufferDescriptors.KDF_SALT; buffers[1].pvBuffer = (IntPtr)pSalt; buffers[1].cbBuffer = salt.Length; buffers[2].BufferType = CngBufferDescriptors.KDF_HASH_ALGORITHM; buffers[2].pvBuffer = (IntPtr)pHashAlgorithmName; // C# spec: "A char* value produced by fixing a string instance always points to a null-terminated string" buffers[2].cbBuffer = checked ((hashAlgorithmName.Length + 1) * sizeof(char)); // Add null terminator. fixed(BCryptBuffer *pBuffers = buffers) { Interop.BCrypt.BCryptBufferDesc bufferDesc; bufferDesc.ulVersion = Interop.BCrypt.BCRYPTBUFFER_VERSION; bufferDesc.cBuffers = buffers.Length; bufferDesc.pBuffers = (IntPtr)pBuffers; NTSTATUS deriveStatus = Interop.BCrypt.BCryptKeyDerivation( keyHandle, &bufferDesc, pDestination, destination.Length, out uint resultLength, dwFlags: 0); if (deriveStatus != NTSTATUS.STATUS_SUCCESS) { throw Interop.BCrypt.CreateCryptographicException(deriveStatus); } if (destination.Length != resultLength) { Debug.Fail("PBKDF2 resultLength != destination.Length"); throw new CryptographicException(); } } } }