diff --git a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Evp.DigestAlgs.cs b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Evp.DigestAlgs.cs
index 8ba0658735a297..d7325ca8e8574c 100644
--- a/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Evp.DigestAlgs.cs
+++ b/src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Evp.DigestAlgs.cs
@@ -47,12 +47,33 @@ internal static IntPtr EvpSha512() =>
internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId) => hashAlgorithmId switch
{
- nameof(HashAlgorithmName.SHA1) => EvpSha1(),
- nameof(HashAlgorithmName.SHA256) => EvpSha256(),
- nameof(HashAlgorithmName.SHA384) => EvpSha384(),
- nameof(HashAlgorithmName.SHA512) => EvpSha512(),
- nameof(HashAlgorithmName.MD5) => EvpMd5(),
+ HashAlgorithmNames.SHA1 => EvpSha1(),
+ HashAlgorithmNames.SHA256 => EvpSha256(),
+ HashAlgorithmNames.SHA384 => EvpSha384(),
+ HashAlgorithmNames.SHA512 => EvpSha512(),
+ HashAlgorithmNames.MD5 => EvpMd5(),
+ HashAlgorithmNames.SHA3_256 or HashAlgorithmNames.SHA3_384 or HashAlgorithmNames.SHA3_512 =>
+ throw new PlatformNotSupportedException(),
_ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId))
};
+
+ internal static bool HashAlgorithmSupported(string hashAlgorithmId)
+ {
+ switch (hashAlgorithmId)
+ {
+ case HashAlgorithmNames.SHA1:
+ case HashAlgorithmNames.SHA256:
+ case HashAlgorithmNames.SHA384:
+ case HashAlgorithmNames.SHA512:
+ case HashAlgorithmNames.MD5:
+ return true;
+ case HashAlgorithmNames.SHA3_256:
+ case HashAlgorithmNames.SHA3_384:
+ case HashAlgorithmNames.SHA3_512:
+ return false;
+ default:
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
+ }
+ }
}
}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs
index abaefab1dab6fc..dec9bdd84a5ddf 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs
@@ -14,45 +14,128 @@ internal static partial class Crypto
private static volatile IntPtr s_evpSha256;
private static volatile IntPtr s_evpSha384;
private static volatile IntPtr s_evpSha512;
+ private static volatile IntPtr s_evpSha3_256;
+ private static volatile IntPtr s_evpSha3_384;
+ private static volatile IntPtr s_evpSha3_512;
+ private static volatile bool s_evpSha3_256Cached;
+ private static volatile bool s_evpSha3_384Cached;
+ private static volatile bool s_evpSha3_512Cached;
[LibraryImport(Libraries.CryptoNative)]
private static partial IntPtr CryptoNative_EvpMd5();
- internal static IntPtr EvpMd5() =>
+ private static IntPtr EvpMd5() =>
s_evpMd5 != IntPtr.Zero ? s_evpMd5 : (s_evpMd5 = CryptoNative_EvpMd5());
[LibraryImport(Libraries.CryptoNative)]
- internal static partial IntPtr CryptoNative_EvpSha1();
+ private static partial IntPtr CryptoNative_EvpSha1();
- internal static IntPtr EvpSha1() =>
+ private static IntPtr EvpSha1() =>
s_evpSha1 != IntPtr.Zero ? s_evpSha1 : (s_evpSha1 = CryptoNative_EvpSha1());
[LibraryImport(Libraries.CryptoNative)]
- internal static partial IntPtr CryptoNative_EvpSha256();
+ private static partial IntPtr CryptoNative_EvpSha256();
- internal static IntPtr EvpSha256() =>
+ private static IntPtr EvpSha256() =>
s_evpSha256 != IntPtr.Zero ? s_evpSha256 : (s_evpSha256 = CryptoNative_EvpSha256());
[LibraryImport(Libraries.CryptoNative)]
- internal static partial IntPtr CryptoNative_EvpSha384();
+ private static partial IntPtr CryptoNative_EvpSha384();
- internal static IntPtr EvpSha384() =>
+ private static IntPtr EvpSha384() =>
s_evpSha384 != IntPtr.Zero ? s_evpSha384 : (s_evpSha384 = CryptoNative_EvpSha384());
[LibraryImport(Libraries.CryptoNative)]
- internal static partial IntPtr CryptoNative_EvpSha512();
+ private static partial IntPtr CryptoNative_EvpSha512();
- internal static IntPtr EvpSha512() =>
+ private static IntPtr EvpSha512() =>
s_evpSha512 != IntPtr.Zero ? s_evpSha512 : (s_evpSha512 = CryptoNative_EvpSha512());
- internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId) => hashAlgorithmId switch
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial IntPtr CryptoNative_EvpSha3_256();
+
+ private static IntPtr EvpSha3_256()
+ {
+ if (!s_evpSha3_256Cached)
+ {
+ s_evpSha3_256 = CryptoNative_EvpSha3_256();
+ s_evpSha3_256Cached = true;
+ }
+
+ return s_evpSha3_256;
+ }
+
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial IntPtr CryptoNative_EvpSha3_384();
+
+ private static IntPtr EvpSha3_384()
+ {
+ if (!s_evpSha3_384Cached)
+ {
+ s_evpSha3_384 = CryptoNative_EvpSha3_384();
+ s_evpSha3_384Cached = true;
+ }
+
+ return s_evpSha3_384;
+ }
+
+ [LibraryImport(Libraries.CryptoNative)]
+ private static partial IntPtr CryptoNative_EvpSha3_512();
+
+ private static IntPtr EvpSha3_512()
+ {
+ if (!s_evpSha3_512Cached)
+ {
+ s_evpSha3_512 = CryptoNative_EvpSha3_512();
+ s_evpSha3_512Cached = true;
+ }
+
+ return s_evpSha3_512;
+ }
+
+
+ internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId)
+ {
+ switch (hashAlgorithmId)
+ {
+ case HashAlgorithmNames.SHA1: return EvpSha1();
+ case HashAlgorithmNames.SHA256: return EvpSha256();
+ case HashAlgorithmNames.SHA384: return EvpSha384();
+ case HashAlgorithmNames.SHA512: return EvpSha512();
+ case HashAlgorithmNames.SHA3_256:
+ IntPtr sha3_256 = EvpSha3_256();
+ return sha3_256 != 0 ? sha3_256 : throw new PlatformNotSupportedException();
+ case HashAlgorithmNames.SHA3_384:
+ IntPtr sha3_384 = EvpSha3_384();
+ return sha3_384 != 0 ? sha3_384 : throw new PlatformNotSupportedException();
+ case HashAlgorithmNames.SHA3_512:
+ IntPtr sha3_512 = EvpSha3_512();
+ return sha3_512 != 0 ? sha3_512 : throw new PlatformNotSupportedException();
+ case nameof(HashAlgorithmName.MD5): return EvpMd5();
+ default:
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
+ };
+ }
+
+ internal static bool HashAlgorithmSupported(string hashAlgorithmId)
{
- nameof(HashAlgorithmName.SHA1) => EvpSha1(),
- nameof(HashAlgorithmName.SHA256) => EvpSha256(),
- nameof(HashAlgorithmName.SHA384) => EvpSha384(),
- nameof(HashAlgorithmName.SHA512) => EvpSha512(),
- nameof(HashAlgorithmName.MD5) => EvpMd5(),
- _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId))
- };
+ switch (hashAlgorithmId)
+ {
+ case HashAlgorithmNames.SHA1:
+ case HashAlgorithmNames.SHA256:
+ case HashAlgorithmNames.SHA384:
+ case HashAlgorithmNames.SHA512:
+ case HashAlgorithmNames.MD5:
+ return true;
+ case HashAlgorithmNames.SHA3_256:
+ return EvpSha3_256() != 0;
+ case HashAlgorithmNames.SHA3_384:
+ return EvpSha3_384() != 0;
+ case HashAlgorithmNames.SHA3_512:
+ return EvpSha3_512() != 0;
+ default:
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
+ }
+ }
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/BCryptAlgorithmCache.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/BCryptAlgorithmCache.cs
index aec34aeb523478..5f060292a666c7 100644
--- a/src/libraries/Common/src/Interop/Windows/BCrypt/BCryptAlgorithmCache.cs
+++ b/src/libraries/Common/src/Interop/Windows/BCrypt/BCryptAlgorithmCache.cs
@@ -13,6 +13,7 @@ internal static partial class BCrypt
internal static class BCryptAlgorithmCache
{
private static readonly ConcurrentDictionary<(string HashAlgorithmId, BCryptOpenAlgorithmProviderFlags Flags), (SafeBCryptAlgorithmHandle Handle, int HashSizeInBytes)> s_handles = new();
+ private static readonly ConcurrentDictionary<(string HashAlgorithmId, BCryptOpenAlgorithmProviderFlags Flags), bool> s_supported = new();
///
/// Returns a SafeBCryptAlgorithmHandle of the desired algorithm and flags. This is a shared handle so do not dispose it!
@@ -43,6 +44,42 @@ public static unsafe SafeBCryptAlgorithmHandle GetCachedBCryptAlgorithmHandle(st
}
}
}
+
+ public static unsafe bool IsBCryptAlgorithmSupported(string hashAlgorithmId, BCryptOpenAlgorithmProviderFlags flags)
+ {
+ var key = (hashAlgorithmId, flags);
+
+ if (s_supported.TryGetValue(key, out bool supported))
+ {
+ return supported;
+ }
+
+ NTSTATUS status = BCryptOpenAlgorithmProvider(
+ out SafeBCryptAlgorithmHandle handle,
+ key.hashAlgorithmId,
+ null,
+ key.flags);
+
+ bool isSupported = status == NTSTATUS.STATUS_SUCCESS;
+
+ if (s_supported.TryAdd(key, isSupported) && isSupported)
+ {
+ // It's a valid algorithm. Let's prime the handle cache while we are here. Presumably it's
+ // going to get used if we're asking if it's supported.
+ int hashSize = BCryptGetDWordProperty(handle, BCryptPropertyStrings.BCRYPT_HASH_LENGTH);
+ Debug.Assert(hashSize > 0);
+
+ if (s_handles.TryAdd(key, (handle, hashSize)))
+ {
+ // If we added the handle to the cache, don't dispose of it and return our answer.
+ return isSupported;
+ }
+ }
+
+ // Either the algorithm isn't supported or we don't need it for priming the cache, so Dispose.
+ handle.Dispose();
+ return isSupported;
+ }
}
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptAlgPseudoHandle.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptAlgPseudoHandle.cs
index 57c508bf709479..d0a4e878f2764a 100644
--- a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptAlgPseudoHandle.cs
+++ b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptAlgPseudoHandle.cs
@@ -23,6 +23,12 @@ public enum BCryptAlgPseudoHandle : uint
BCRYPT_HMAC_SHA384_ALG_HANDLE = 0x000000c1,
BCRYPT_HMAC_SHA512_ALG_HANDLE = 0x000000d1,
BCRYPT_PBKDF2_ALG_HANDLE = 0x00000331,
+ BCRYPT_SHA3_256_ALG_HANDLE = 0x000003B1,
+ BCRYPT_SHA3_384_ALG_HANDLE = 0x000003C1,
+ BCRYPT_SHA3_512_ALG_HANDLE = 0x000003D1,
+ BCRYPT_HMAC_SHA3_256_ALG_HANDLE = 0x000003E1,
+ BCRYPT_HMAC_SHA3_384_ALG_HANDLE = 0x000003F1,
+ BCRYPT_HMAC_SHA3_512_ALG_HANDLE = 0x00000401,
}
internal static bool PseudoHandlesSupported { get; } =
diff --git a/src/libraries/Common/src/System/Security/Cryptography/HashOneShotHelpers.cs b/src/libraries/Common/src/System/Security/Cryptography/HashOneShotHelpers.cs
index debc16c329b1e5..f80e69c8bf53a8 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/HashOneShotHelpers.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/HashOneShotHelpers.cs
@@ -12,28 +12,18 @@ internal static class HashOneShotHelpers
{
internal static byte[] HashData(HashAlgorithmName hashAlgorithm, ReadOnlySpan source)
{
- if (hashAlgorithm == HashAlgorithmName.SHA256)
- {
- return SHA256.HashData(source);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA1)
- {
- return SHA1.HashData(source);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA512)
- {
- return SHA512.HashData(source);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA384)
- {
- return SHA384.HashData(source);
- }
- else if (Helpers.HasMD5 && hashAlgorithm == HashAlgorithmName.MD5)
- {
- return MD5.HashData(source);
- }
-
- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
+ return hashAlgorithm.Name switch
+ {
+ HashAlgorithmNames.SHA256 => SHA256.HashData(source),
+ HashAlgorithmNames.SHA1 => SHA1.HashData(source),
+ HashAlgorithmNames.SHA512 => SHA512.HashData(source),
+ HashAlgorithmNames.SHA384 => SHA384.HashData(source),
+ HashAlgorithmNames.SHA3_256 => SHA3_256.HashData(source),
+ HashAlgorithmNames.SHA3_384 => SHA3_384.HashData(source),
+ HashAlgorithmNames.SHA3_512 => SHA3_512.HashData(source),
+ HashAlgorithmNames.MD5 when Helpers.HasMD5 => MD5.HashData(source),
+ _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)),
+ };
}
internal static bool TryHashData(
@@ -42,54 +32,34 @@ internal static bool TryHashData(
Span destination,
out int bytesWritten)
{
- if (hashAlgorithm == HashAlgorithmName.SHA256)
- {
- return SHA256.TryHashData(source, destination, out bytesWritten);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA1)
- {
- return SHA1.TryHashData(source, destination, out bytesWritten);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA512)
- {
- return SHA512.TryHashData(source, destination, out bytesWritten);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA384)
- {
- return SHA384.TryHashData(source, destination, out bytesWritten);
- }
- else if (Helpers.HasMD5 && hashAlgorithm == HashAlgorithmName.MD5)
- {
- return MD5.TryHashData(source, destination, out bytesWritten);
- }
-
- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
+ return hashAlgorithm.Name switch
+ {
+ HashAlgorithmNames.SHA256 => SHA256.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.SHA1 => SHA1.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.SHA512 => SHA512.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.SHA384 => SHA384.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.SHA3_256 => SHA3_256.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.SHA3_384 => SHA3_384.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.SHA3_512 => SHA3_512.TryHashData(source, destination, out bytesWritten),
+ HashAlgorithmNames.MD5 when Helpers.HasMD5 => MD5.TryHashData(source, destination, out bytesWritten),
+ _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)),
+ };
}
internal static byte[] HashData(HashAlgorithmName hashAlgorithm, Stream source)
{
- if (hashAlgorithm == HashAlgorithmName.SHA256)
- {
- return SHA256.HashData(source);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA1)
- {
- return SHA1.HashData(source);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA512)
- {
- return SHA512.HashData(source);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA384)
- {
- return SHA384.HashData(source);
- }
- else if (Helpers.HasMD5 && hashAlgorithm == HashAlgorithmName.MD5)
- {
- return MD5.HashData(source);
- }
-
- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
+ return hashAlgorithm.Name switch
+ {
+ HashAlgorithmNames.SHA256 => SHA256.HashData(source),
+ HashAlgorithmNames.SHA1 => SHA1.HashData(source),
+ HashAlgorithmNames.SHA512 => SHA512.HashData(source),
+ HashAlgorithmNames.SHA384 => SHA384.HashData(source),
+ HashAlgorithmNames.SHA3_256 => SHA3_256.HashData(source),
+ HashAlgorithmNames.SHA3_384 => SHA3_384.HashData(source),
+ HashAlgorithmNames.SHA3_512 => SHA3_512.HashData(source),
+ HashAlgorithmNames.MD5 when Helpers.HasMD5 => MD5.HashData(source),
+ _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)),
+ };
}
internal static int MacData(
@@ -98,28 +68,18 @@ internal static int MacData(
ReadOnlySpan source,
Span destination)
{
- if (hashAlgorithm == HashAlgorithmName.SHA256)
- {
- return HMACSHA256.HashData(key, source, destination);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA1)
- {
- return HMACSHA1.HashData(key, source, destination);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA512)
- {
- return HMACSHA512.HashData(key, source, destination);
- }
- else if (hashAlgorithm == HashAlgorithmName.SHA384)
- {
- return HMACSHA384.HashData(key, source, destination);
- }
- else if (Helpers.HasMD5 && hashAlgorithm == HashAlgorithmName.MD5)
- {
- return HMACMD5.HashData(key, source, destination);
- }
-
- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
+ return hashAlgorithm.Name switch
+ {
+ HashAlgorithmNames.SHA256 => HMACSHA256.HashData(key, source, destination),
+ HashAlgorithmNames.SHA1 => HMACSHA1.HashData(key, source, destination),
+ HashAlgorithmNames.SHA512 => HMACSHA512.HashData(key, source, destination),
+ HashAlgorithmNames.SHA384 => HMACSHA384.HashData(key, source, destination),
+ HashAlgorithmNames.SHA3_256 => HMACSHA3_256.HashData(key, source, destination),
+ HashAlgorithmNames.SHA3_384 => HMACSHA3_384.HashData(key, source, destination),
+ HashAlgorithmNames.SHA3_512 => HMACSHA3_512.HashData(key, source, destination),
+ HashAlgorithmNames.MD5 when Helpers.HasMD5 => HMACMD5.HashData(key, source, destination),
+ _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name)),
+ };
}
}
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Oids.cs b/src/libraries/Common/src/System/Security/Cryptography/Oids.cs
index 40e761dab09d4c..b7364108222ad1 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/Oids.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/Oids.cs
@@ -24,6 +24,9 @@ internal static partial class Oids
internal const string RsaPkcs1Sha256 = "1.2.840.113549.1.1.11";
internal const string RsaPkcs1Sha384 = "1.2.840.113549.1.1.12";
internal const string RsaPkcs1Sha512 = "1.2.840.113549.1.1.13";
+ internal const string RsaPkcs1Sha3_256 = "2.16.840.1.101.3.4.3.14";
+ internal const string RsaPkcs1Sha3_384 = "2.16.840.1.101.3.4.3.15";
+ internal const string RsaPkcs1Sha3_512 = "2.16.840.1.101.3.4.3.16";
internal const string Esdh = "1.2.840.113549.1.9.16.3.5";
internal const string EcDiffieHellman = "1.3.132.1.12";
internal const string DiffieHellman = "1.2.840.10046.2.1";
@@ -65,6 +68,9 @@ internal static partial class Oids
internal const string Sha256 = "2.16.840.1.101.3.4.2.1";
internal const string Sha384 = "2.16.840.1.101.3.4.2.2";
internal const string Sha512 = "2.16.840.1.101.3.4.2.3";
+ internal const string Sha3_256 = "2.16.840.1.101.3.4.2.8";
+ internal const string Sha3_384 = "2.16.840.1.101.3.4.2.9";
+ internal const string Sha3_512 = "2.16.840.1.101.3.4.2.10";
// DSA CMS uses the combined signature+digest OID
internal const string DsaWithSha1 = "1.2.840.10040.4.3";
@@ -84,6 +90,10 @@ internal static partial class Oids
internal const string ECDsaWithSha384 = "1.2.840.10045.4.3.3";
internal const string ECDsaWithSha512 = "1.2.840.10045.4.3.4";
+ internal const string ECDsaWithSha3_256 = "2.16.840.1.101.3.4.3.10";
+ internal const string ECDsaWithSha3_384 = "2.16.840.1.101.3.4.3.11";
+ internal const string ECDsaWithSha3_512 = "2.16.840.1.101.3.4.3.12";
+
internal const string Mgf1 = "1.2.840.113549.1.1.8";
internal const string PSpecified = "1.2.840.113549.1.1.9";
diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
index dc002fdfd59732..34ad612323f2d7 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs
@@ -873,6 +873,18 @@ private static void ValidatePadding(RSAEncryptionPadding padding)
{
throw PaddingModeNotSupported();
}
+
+ // If the hash algorithm is not supported by the platform, such as SHA3, then we don't support it for
+ // RSAOpenSsl, even if OpenSSL itself might support OAEP-SHA3. We use the platform's hashing in some
+ // places for RSA, regardless of what is implementing RSA. If RSAOpenSsl were used on macOS, then
+ // there would be some incongruence between what hashes OpenSSL supports and what macOS support. Signing
+ // for example, always uses the platform's implementation of hashing.
+ if (padding.Mode == RSAEncryptionPaddingMode.Oaep &&
+ padding.OaepHashAlgorithm.Name is string name &&
+ !HashProviderDispenser.HashSupported(name))
+ {
+ throw new PlatformNotSupportedException();
+ }
}
private static void ValidatePadding(RSASignaturePadding padding)
diff --git a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
index 4db95b2ff4d242..66256440b7e708 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/RsaPaddingProcessor.cs
@@ -44,41 +44,62 @@ internal static class RsaPaddingProcessor
0x40,
};
+ private static ReadOnlySpan DigestInfoSha3_256 => new byte[]
+ {
+ 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x65, 0x03, 0x04, 0x02, 0x08, 0x05, 0x00, 0x04,
+ 0x20,
+ };
+
+ private static ReadOnlySpan DigestInfoSha3_384 => new byte[]
+ {
+ 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x65, 0x03, 0x04, 0x02, 0x09, 0x05, 0x00, 0x04,
+ 0x30,
+ };
+
+ private static ReadOnlySpan DigestInfoSha3_512 => new byte[]
+ {
+ 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
+ 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A, 0x05, 0x00, 0x04,
+ 0x40,
+ };
+
private static ReadOnlySpan EightZeros => new byte[8];
private static ReadOnlySpan GetDigestInfoForAlgorithm(
HashAlgorithmName hashAlgorithmName,
out int digestLengthInBytes)
{
- if (hashAlgorithmName == HashAlgorithmName.MD5)
- {
- digestLengthInBytes = MD5.HashSizeInBytes;
- return DigestInfoMD5;
- }
- else if (hashAlgorithmName == HashAlgorithmName.SHA1)
- {
- digestLengthInBytes = SHA1.HashSizeInBytes;
- return DigestInfoSha1;
- }
- else if (hashAlgorithmName == HashAlgorithmName.SHA256)
- {
- digestLengthInBytes = SHA256.HashSizeInBytes;
- return DigestInfoSha256;
- }
- else if (hashAlgorithmName == HashAlgorithmName.SHA384)
+ switch (hashAlgorithmName.Name)
{
- digestLengthInBytes = SHA384.HashSizeInBytes;
- return DigestInfoSha384;
- }
- else if (hashAlgorithmName == HashAlgorithmName.SHA512)
- {
- digestLengthInBytes = SHA512.HashSizeInBytes;
- return DigestInfoSha512;
- }
- else
- {
- Debug.Fail("Unknown digest algorithm");
- throw new CryptographicException();
+ case HashAlgorithmNames.MD5:
+ digestLengthInBytes = MD5.HashSizeInBytes;
+ return DigestInfoMD5;
+ case HashAlgorithmNames.SHA1:
+ digestLengthInBytes = SHA1.HashSizeInBytes;
+ return DigestInfoSha1;
+ case HashAlgorithmNames.SHA256:
+ digestLengthInBytes = SHA256.HashSizeInBytes;
+ return DigestInfoSha256;
+ case HashAlgorithmNames.SHA384:
+ digestLengthInBytes = SHA384.HashSizeInBytes;
+ return DigestInfoSha384;
+ case HashAlgorithmNames.SHA512:
+ digestLengthInBytes = SHA512.HashSizeInBytes;
+ return DigestInfoSha512;
+ case HashAlgorithmNames.SHA3_256:
+ digestLengthInBytes = SHA3_256.HashSizeInBytes;
+ return DigestInfoSha3_256;
+ case HashAlgorithmNames.SHA3_384:
+ digestLengthInBytes = SHA3_384.HashSizeInBytes;
+ return DigestInfoSha3_384;
+ case HashAlgorithmNames.SHA3_512:
+ digestLengthInBytes = SHA3_512.HashSizeInBytes;
+ return DigestInfoSha3_512;
+ default:
+ Debug.Fail("Unknown digest algorithm");
+ throw new CryptographicException();
}
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdf.cs b/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdf.cs
index 6598136dfe7a77..a9f37b0fb11a4e 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdf.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdf.cs
@@ -559,6 +559,26 @@ private static void CheckHashAlgorithm(HashAlgorithmName hashAlgorithm)
case HashAlgorithmNames.SHA384:
case HashAlgorithmNames.SHA512:
break;
+#if NET8_0_OR_GREATER
+ case HashAlgorithmNames.SHA3_256:
+ if (!HMACSHA3_256.IsSupported)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ break;
+ case HashAlgorithmNames.SHA3_384:
+ if (!HMACSHA3_384.IsSupported)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ break;
+ case HashAlgorithmNames.SHA3_512:
+ if (!HMACSHA3_512.IsSupported)
+ {
+ throw new PlatformNotSupportedException();
+ }
+ break;
+#endif
default:
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName));
}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs b/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs
index ca8f72c61428aa..46143f15c86acc 100644
--- a/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs
+++ b/src/libraries/Common/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs
@@ -193,7 +193,7 @@ private static unsafe SafeBCryptKeyHandle CreateSymmetricKey(byte* symmetricKey,
private static int GetHashBlockSize(string hashAlgorithmName)
{
- // Block sizes per NIST FIPS pub 180-4.
+ // Block sizes per NIST FIPS pub 180-4 and FIPS 202.
switch (hashAlgorithmName)
{
case HashAlgorithmNames.SHA1:
@@ -202,6 +202,12 @@ private static int GetHashBlockSize(string hashAlgorithmName)
case HashAlgorithmNames.SHA384:
case HashAlgorithmNames.SHA512:
return 1024 / 8;
+ case HashAlgorithmNames.SHA3_256:
+ return 1088 / 8;
+ case HashAlgorithmNames.SHA3_384:
+ return 832 / 8;
+ case HashAlgorithmNames.SHA3_512:
+ return 576 / 8;
default:
Debug.Fail($"Unexpected hash algorithm '{hashAlgorithmName}'");
throw new CryptographicException();
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs
index 6497640809f3ab..84bbea4587eef4 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanFactory.cs
@@ -14,6 +14,7 @@ public interface IECDiffieHellmanProvider
bool ExplicitCurvesSupported { get; }
bool CanDeriveNewPublicKey { get; }
bool SupportsRawDerivation { get; }
+ bool SupportsSha3 { get; }
}
public static partial class ECDiffieHellmanFactory
@@ -45,5 +46,7 @@ public static bool IsCurveValid(Oid oid)
public static bool CanDeriveNewPublicKey => s_provider.CanDeriveNewPublicKey;
public static bool SupportsRawDerivation => s_provider.SupportsRawDerivation;
+
+ public static bool SupportsSha3 => s_provider.SupportsSha3;
}
}
diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs
index dfca203f4fa14c..0065092e52aad1 100644
--- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs
+++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/ECDiffieHellman/ECDiffieHellmanTests.Hash.cs
@@ -207,56 +207,87 @@ public static void DeriveKeyMaterialEquivalentToDeriveKeyFromHash()
public static IEnumerable
private static HashAlgorithmName AlgorithmToHashAlgorithmName(HashAlgorithm hashAlgorithm)
{
+ // CAPI CSP doesn't support SHA-3, so don't add it here.
return hashAlgorithm switch
{
SHA256 => HashAlgorithmName.SHA256,
@@ -50,6 +51,7 @@ private static HashAlgorithmName AlgorithmToHashAlgorithmName(HashAlgorithm hash
private static HashAlgorithmName OidToHashAlgorithmName(string oid)
{
+ // CAPI CSP doesn't support SHA-3, so don't add it here.
return oid switch
{
Oids.Sha256 => HashAlgorithmName.SHA256,
@@ -63,6 +65,7 @@ private static HashAlgorithmName OidToHashAlgorithmName(string oid)
private static HashAlgorithmName HashAlgorithmTypeToHashAlgorithmName(Type hashAlgType)
{
+ // CAPI CSP doesn't support SHA-3, so don't add it here.
if (typeof(SHA1).IsAssignableFrom(hashAlgType))
return HashAlgorithmName.SHA1;
if (typeof(SHA256).IsAssignableFrom(hashAlgType))
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HKDF.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HKDF.cs
index abb85e9a972e8c..1de6138cc1ec92 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HKDF.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HKDF.cs
@@ -286,6 +286,18 @@ private static int HashLength(HashAlgorithmName hashAlgorithmName)
{
return HMACSHA512.HashSizeInBytes;
}
+ else if (hashAlgorithmName == HashAlgorithmName.SHA3_256)
+ {
+ return HMACSHA3_256.HashSizeInBytes;
+ }
+ else if (hashAlgorithmName == HashAlgorithmName.SHA3_384)
+ {
+ return HMACSHA3_384.HashSizeInBytes;
+ }
+ else if (hashAlgorithmName == HashAlgorithmName.SHA3_512)
+ {
+ return HMACSHA3_512.HashSizeInBytes;
+ }
else if (hashAlgorithmName == HashAlgorithmName.MD5)
{
return HMACMD5.HashSizeInBytes;
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACCommon.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACCommon.cs
index fec3c37cd3c620..25210f555df861 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACCommon.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACCommon.cs
@@ -57,14 +57,37 @@ public void ChangeKey(byte[] key)
if (key.Length > _blockSize && _blockSize > 0)
{
// Perform RFC 2104, section 2 key adjustment.
- modifiedKey = _hashAlgorithmId switch
+ switch (_hashAlgorithmId)
{
- HashAlgorithmNames.SHA256 => SHA256.HashData(key),
- HashAlgorithmNames.SHA384 => SHA384.HashData(key),
- HashAlgorithmNames.SHA512 => SHA512.HashData(key),
- HashAlgorithmNames.SHA1 => SHA1.HashData(key),
- HashAlgorithmNames.MD5 when Helpers.HasMD5 => MD5.HashData(key),
- _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, _hashAlgorithmId)),
+ case HashAlgorithmNames.SHA256:
+ modifiedKey = SHA256.HashData(key);
+ break;
+ case HashAlgorithmNames.SHA384:
+ modifiedKey = SHA384.HashData(key);
+ break;
+ case HashAlgorithmNames.SHA512:
+ modifiedKey = SHA512.HashData(key);
+ break;
+ case HashAlgorithmNames.SHA3_256:
+ Debug.Assert(SHA3_256.IsSupported);
+ modifiedKey = SHA3_256.HashData(key);
+ break;
+ case HashAlgorithmNames.SHA3_384:
+ Debug.Assert(SHA3_384.IsSupported);
+ modifiedKey = SHA3_384.HashData(key);
+ break;
+ case HashAlgorithmNames.SHA3_512:
+ Debug.Assert(SHA3_512.IsSupported);
+ modifiedKey = SHA3_512.HashData(key);
+ break;
+ case HashAlgorithmNames.SHA1:
+ modifiedKey = SHA1.HashData(key);
+ break;
+ case HashAlgorithmNames.MD5 when Helpers.HasMD5:
+ modifiedKey = MD5.HashData(key);
+ break;
+ default:
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, _hashAlgorithmId));
};
}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_256.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_256.cs
new file mode 100644
index 00000000000000..d71c41bdf98540
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_256.cs
@@ -0,0 +1,390 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Cryptography;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA3-256 hash function.
+ ///
+ public class HMACSHA3_256 : HMAC
+ {
+ private HMACCommon _hMacCommon;
+ internal const int BlockSize = 136; // FIPS 202 Table 3.
+
+ ///
+ /// The hash size produced by the HMAC SHA3-256 algorithm, in bits.
+ ///
+ public const int HashSizeInBits = 256;
+
+ ///
+ /// The hash size produced by the HMAC SHA3-256 algorithm, in bytes.
+ ///
+ public const int HashSizeInBytes = HashSizeInBits / 8;
+
+ ///
+ /// Initializes a new instance of the class with a randomly generated key.
+ ///
+ ///
+ ///
+ /// is a type of keyed hash algorithm that is constructed from the SHA3-256 hash
+ /// function and used as a Hash-based Message Authentication Code (HMAC). The HMAC process mixes a secret key
+ /// with the message data, hashes the result with the hash function, mixes that hash value with the secret key
+ /// again, and then applies the hash function a second time. The output hash is 256 bits in length.
+ ///
+ ///
+ /// This constructor uses a 136-byte, randomly generated key.
+ ///
+ ///
+ public HMACSHA3_256()
+ : this(RandomNumberGenerator.GetBytes(BlockSize))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data.
+ ///
+ ///
+ /// The secret key for . The key can be any length.
+ ///
+ ///
+ /// is .
+ ///
+ public HMACSHA3_256(byte[] key)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ CheckSha3Support();
+
+ this.HashName = HashAlgorithmNames.SHA3_256;
+ _hMacCommon = new HMACCommon(HashAlgorithmNames.SHA3_256, key, BlockSize);
+ base.Key = _hMacCommon.ActualKey!;
+ BlockSizeValue = BlockSize;
+ HashSizeValue = HashSizeInBits;
+ Debug.Assert(HashSizeValue == _hMacCommon.HashSizeInBits);
+ }
+
+ ///
+ /// Gets a value that indicates whether the algorithm is supported on the current platform.
+ ///
+ ///
+ /// if the algorithm is supported; otherwise, .
+ ///
+ public static bool IsSupported { get; } = HashProviderDispenser.MacSupported(HashAlgorithmNames.SHA3_256);
+
+ ///
+ public override byte[] Key
+ {
+ get
+ {
+ return base.Key;
+ }
+ set
+ {
+ ArgumentNullException.ThrowIfNull(value);
+ _hMacCommon.ChangeKey(value);
+ base.Key = _hMacCommon.ActualKey!;
+ }
+ }
+
+ ///
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
+ _hMacCommon.AppendHashData(rgb, ib, cb);
+
+ ///
+ protected override void HashCore(ReadOnlySpan source) =>
+ _hMacCommon.AppendHashData(source);
+
+ ///
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ ///
+ protected override bool TryHashFinal(Span destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
+
+ ///
+ public override void Initialize() => _hMacCommon.Reset();
+
+ ///
+ /// Computes the HMAC of data using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ ArgumentNullException.ThrowIfNull(source);
+
+ return HashData(new ReadOnlySpan(key), new ReadOnlySpan(source));
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source)
+ {
+ byte[] buffer = new byte[HashSizeInBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The buffer to receive the HMAC value.
+ /// The total number of bytes written to .
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-256 algorithm always produces a 256-bit HMAC, or 32 bytes.
+ ///
+ public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ ///
+ /// Attempts to compute the HMAC of data using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The buffer to receive the HMAC value.
+ ///
+ /// When this method returns, the total number of bytes written into .
+ ///
+ ///
+ /// if is too small to hold the
+ /// calculated hash, otherwise.
+ ///
+ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten)
+ {
+ CheckSha3Support();
+
+ if (destination.Length < HashSizeInBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA3_256, key, source, destination);
+ Debug.Assert(bytesWritten == HashSizeInBytes);
+
+ return true;
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The buffer to receive the HMAC value.
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated HMAC
+ /// size. The SHA3-256 algorithm always produces a 256-bit HMAC, or 32 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA3_256, key, source, destination);
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static byte[] HashData(ReadOnlySpan key, Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA3_256, HashSizeInBytes, key, source);
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static byte[] HashData(byte[] key, Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ return HashData(new ReadOnlySpan(key), source);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The HMAC of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA3_256, key.Span, source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-256 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The buffer to receive the HMAC value.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-256 algorithm always produces a 256-bit hash, or 32 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ public static ValueTask HashDataAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStreamAsync(
+ HashAlgorithmNames.SHA3_256,
+ key.Span,
+ source,
+ destination,
+ cancellationToken);
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ HMACCommon hMacCommon = _hMacCommon;
+ if (hMacCommon != null)
+ {
+ _hMacCommon = null!;
+ hMacCommon.Dispose(disposing);
+ }
+ }
+ base.Dispose(disposing);
+ }
+
+ private static void CheckSha3Support()
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_384.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_384.cs
new file mode 100644
index 00000000000000..3e7497443098df
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_384.cs
@@ -0,0 +1,390 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Cryptography;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA3-384 hash function.
+ ///
+ public class HMACSHA3_384 : HMAC
+ {
+ private HMACCommon _hMacCommon;
+ internal const int BlockSize = 104; // FIPS 202 Table 3.
+
+ ///
+ /// The hash size produced by the HMAC SHA3-384 algorithm, in bits.
+ ///
+ public const int HashSizeInBits = 384;
+
+ ///
+ /// The hash size produced by the HMAC SHA3-384 algorithm, in bytes.
+ ///
+ public const int HashSizeInBytes = HashSizeInBits / 8;
+
+ ///
+ /// Initializes a new instance of the class with a randomly generated key.
+ ///
+ ///
+ ///
+ /// is a type of keyed hash algorithm that is constructed from the SHA3-384 hash
+ /// function and used as a Hash-based Message Authentication Code (HMAC). The HMAC process mixes a secret key
+ /// with the message data, hashes the result with the hash function, mixes that hash value with the secret key
+ /// again, and then applies the hash function a second time. The output hash is 384 bits in length.
+ ///
+ ///
+ /// This constructor uses a 104-byte, randomly generated key.
+ ///
+ ///
+ public HMACSHA3_384()
+ : this(RandomNumberGenerator.GetBytes(BlockSize))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data.
+ ///
+ ///
+ /// The secret key for . The key can be any length.
+ ///
+ ///
+ /// is .
+ ///
+ public HMACSHA3_384(byte[] key)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ CheckSha3Support();
+
+ this.HashName = HashAlgorithmNames.SHA3_384;
+ _hMacCommon = new HMACCommon(HashAlgorithmNames.SHA3_384, key, BlockSize);
+ base.Key = _hMacCommon.ActualKey!;
+ BlockSizeValue = BlockSize;
+ HashSizeValue = HashSizeInBits;
+ Debug.Assert(HashSizeValue == _hMacCommon.HashSizeInBits);
+ }
+
+ ///
+ /// Gets a value that indicates whether the algorithm is supported on the current platform.
+ ///
+ ///
+ /// if the algorithm is supported; otherwise, .
+ ///
+ public static bool IsSupported { get; } = HashProviderDispenser.MacSupported(HashAlgorithmNames.SHA3_384);
+
+ ///
+ public override byte[] Key
+ {
+ get
+ {
+ return base.Key;
+ }
+ set
+ {
+ ArgumentNullException.ThrowIfNull(value);
+ _hMacCommon.ChangeKey(value);
+ base.Key = _hMacCommon.ActualKey!;
+ }
+ }
+
+ ///
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
+ _hMacCommon.AppendHashData(rgb, ib, cb);
+
+ ///
+ protected override void HashCore(ReadOnlySpan source) =>
+ _hMacCommon.AppendHashData(source);
+
+ ///
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ ///
+ protected override bool TryHashFinal(Span destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
+
+ ///
+ public override void Initialize() => _hMacCommon.Reset();
+
+ ///
+ /// Computes the HMAC of data using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ ArgumentNullException.ThrowIfNull(source);
+
+ return HashData(new ReadOnlySpan(key), new ReadOnlySpan(source));
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source)
+ {
+ byte[] buffer = new byte[HashSizeInBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The buffer to receive the HMAC value.
+ /// The total number of bytes written to .
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-384 algorithm always produces a 384-bit HMAC, or 48 bytes.
+ ///
+ public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ ///
+ /// Attempts to compute the HMAC of data using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The buffer to receive the HMAC value.
+ ///
+ /// When this method returns, the total number of bytes written into .
+ ///
+ ///
+ /// if is too small to hold the
+ /// calculated hash, otherwise.
+ ///
+ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten)
+ {
+ CheckSha3Support();
+
+ if (destination.Length < HashSizeInBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA3_384, key, source, destination);
+ Debug.Assert(bytesWritten == HashSizeInBytes);
+
+ return true;
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The buffer to receive the HMAC value.
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated HMAC
+ /// size. The SHA3-384 algorithm always produces a 384-bit HMAC, or 48 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA3_384, key, source, destination);
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static byte[] HashData(ReadOnlySpan key, Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA3_384, HashSizeInBytes, key, source);
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static byte[] HashData(byte[] key, Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ return HashData(new ReadOnlySpan(key), source);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The HMAC of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA3_384, key.Span, source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-384 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The buffer to receive the HMAC value.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-384 algorithm always produces a 384-bit hash, or 48 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ public static ValueTask HashDataAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStreamAsync(
+ HashAlgorithmNames.SHA3_384,
+ key.Span,
+ source,
+ destination,
+ cancellationToken);
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ HMACCommon hMacCommon = _hMacCommon;
+ if (hMacCommon != null)
+ {
+ _hMacCommon = null!;
+ hMacCommon.Dispose(disposing);
+ }
+ }
+ base.Dispose(disposing);
+ }
+
+ private static void CheckSha3Support()
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_512.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_512.cs
new file mode 100644
index 00000000000000..62a6bb4f174072
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HMACSHA3_512.cs
@@ -0,0 +1,390 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Cryptography;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA3-512 hash function.
+ ///
+ public class HMACSHA3_512 : HMAC
+ {
+ private HMACCommon _hMacCommon;
+ internal const int BlockSize = 72; // FIPS 202 Table 3.
+
+ ///
+ /// The hash size produced by the HMAC SHA3-512 algorithm, in bits.
+ ///
+ public const int HashSizeInBits = 512;
+
+ ///
+ /// The hash size produced by the HMAC SHA3-512 algorithm, in bytes.
+ ///
+ public const int HashSizeInBytes = HashSizeInBits / 8;
+
+ ///
+ /// Initializes a new instance of the class with a randomly generated key.
+ ///
+ ///
+ ///
+ /// is a type of keyed hash algorithm that is constructed from the SHA3-512 hash
+ /// function and used as a Hash-based Message Authentication Code (HMAC). The HMAC process mixes a secret key
+ /// with the message data, hashes the result with the hash function, mixes that hash value with the secret key
+ /// again, and then applies the hash function a second time. The output hash is 512 bits in length.
+ ///
+ ///
+ /// This constructor uses a 72-byte, randomly generated key.
+ ///
+ ///
+ public HMACSHA3_512()
+ : this(RandomNumberGenerator.GetBytes(BlockSize))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data.
+ ///
+ ///
+ /// The secret key for . The key can be any length.
+ ///
+ ///
+ /// is .
+ ///
+ public HMACSHA3_512(byte[] key)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ CheckSha3Support();
+
+ this.HashName = HashAlgorithmNames.SHA3_512;
+ _hMacCommon = new HMACCommon(HashAlgorithmNames.SHA3_512, key, BlockSize);
+ base.Key = _hMacCommon.ActualKey!;
+ BlockSizeValue = BlockSize;
+ HashSizeValue = HashSizeInBits;
+ Debug.Assert(HashSizeValue == _hMacCommon.HashSizeInBits);
+ }
+
+ ///
+ /// Gets a value that indicates whether the algorithm is supported on the current platform.
+ ///
+ ///
+ /// if the algorithm is supported; otherwise, .
+ ///
+ public static bool IsSupported { get; } = HashProviderDispenser.MacSupported(HashAlgorithmNames.SHA3_512);
+
+ ///
+ public override byte[] Key
+ {
+ get
+ {
+ return base.Key;
+ }
+ set
+ {
+ ArgumentNullException.ThrowIfNull(value);
+ _hMacCommon.ChangeKey(value);
+ base.Key = _hMacCommon.ActualKey!;
+ }
+ }
+
+ ///
+ protected override void HashCore(byte[] rgb, int ib, int cb) =>
+ _hMacCommon.AppendHashData(rgb, ib, cb);
+
+ ///
+ protected override void HashCore(ReadOnlySpan source) =>
+ _hMacCommon.AppendHashData(source);
+
+ ///
+ protected override byte[] HashFinal() =>
+ _hMacCommon.FinalizeHashAndReset();
+
+ ///
+ protected override bool TryHashFinal(Span destination, out int bytesWritten) =>
+ _hMacCommon.TryFinalizeHashAndReset(destination, out bytesWritten);
+
+ ///
+ public override void Initialize() => _hMacCommon.Reset();
+
+ ///
+ /// Computes the HMAC of data using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ public static byte[] HashData(byte[] key, byte[] source)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+ ArgumentNullException.ThrowIfNull(source);
+
+ return HashData(new ReadOnlySpan(key), new ReadOnlySpan(source));
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source)
+ {
+ byte[] buffer = new byte[HashSizeInBytes];
+
+ int written = HashData(key, source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The buffer to receive the HMAC value.
+ /// The total number of bytes written to .
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-512 algorithm always produces a 512-bit HMAC, or 64 bytes.
+ ///
+ public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination)
+ {
+ if (!TryHashData(key, source, destination, out int bytesWritten))
+ {
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+ }
+
+ return bytesWritten;
+ }
+
+ ///
+ /// Attempts to compute the HMAC of data using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The buffer to receive the HMAC value.
+ ///
+ /// When this method returns, the total number of bytes written into .
+ ///
+ ///
+ /// if is too small to hold the
+ /// calculated hash, otherwise.
+ ///
+ public static bool TryHashData(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten)
+ {
+ CheckSha3Support();
+
+ if (destination.Length < HashSizeInBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.MacData(HashAlgorithmNames.SHA3_512, key, source, destination);
+ Debug.Assert(bytesWritten == HashSizeInBytes);
+
+ return true;
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The buffer to receive the HMAC value.
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated HMAC
+ /// size. The SHA3-512 algorithm always produces a 512-bit HMAC, or 64 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ public static int HashData(ReadOnlySpan key, Stream source, Span destination)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA3_512, key, source, destination);
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static byte[] HashData(ReadOnlySpan key, Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStream(HashAlgorithmNames.SHA3_512, HashSizeInBytes, key, source);
+ }
+
+ ///
+ /// Computes the HMAC of a stream using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static byte[] HashData(byte[] key, Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ return HashData(new ReadOnlySpan(key), source);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The HMAC of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStreamAsync(HashAlgorithmNames.SHA3_512, key.Span, source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(key);
+
+ return HashDataAsync(new ReadOnlyMemory(key), source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the HMAC of a stream using the SHA3-512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The stream to HMAC.
+ /// The buffer to receive the HMAC value.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-512 algorithm always produces a 512-bit hash, or 64 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ public static ValueTask HashDataAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HmacStreamAsync(
+ HashAlgorithmNames.SHA3_512,
+ key.Span,
+ source,
+ destination,
+ cancellationToken);
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ HMACCommon hMacCommon = _hMacCommon;
+ if (hMacCommon != null)
+ {
+ _hMacCommon = null!;
+ hMacCommon.Dispose(disposing);
+ }
+ }
+ base.Dispose(disposing);
+ }
+
+ private static void CheckSha3Support()
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException();
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmName.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmName.cs
index f7df0f24280251..c2e444b63a352a 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmName.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmName.cs
@@ -52,6 +52,21 @@ namespace System.Security.Cryptography
///
public static HashAlgorithmName SHA512 { get { return new HashAlgorithmName("SHA512"); } }
+ ///
+ /// Gets a representing "SHA3-256"
+ ///
+ public static HashAlgorithmName SHA3_256 => new HashAlgorithmName("SHA3-256");
+
+ ///
+ /// Gets a representing "SHA3-384"
+ ///
+ public static HashAlgorithmName SHA3_384 => new HashAlgorithmName("SHA3-384");
+
+ ///
+ /// Gets a representing "SHA3-512"
+ ///
+ public static HashAlgorithmName SHA3_512 => new HashAlgorithmName("SHA3-512");
+
private readonly string? _name;
///
@@ -142,6 +157,15 @@ public static bool TryFromOid(string oidValue, out HashAlgorithmName value)
case Oids.Sha512:
value = SHA512;
return true;
+ case Oids.Sha3_256:
+ value = SHA3_256;
+ return true;
+ case Oids.Sha3_384:
+ value = SHA3_384;
+ return true;
+ case Oids.Sha3_512:
+ value = SHA3_512;
+ return true;
default:
value = default;
return false;
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs
index 1b8f225ce4b7a1..00cfa2636a0170 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashAlgorithmNames.cs
@@ -14,6 +14,10 @@ internal static partial class HashAlgorithmNames
public const string SHA384 = "SHA384";
public const string SHA512 = "SHA512";
+ public const string SHA3_256 = "SHA3-256";
+ public const string SHA3_384 = "SHA3-384";
+ public const string SHA3_512 = "SHA3-512";
+
///
/// Map HashAlgorithm type to string; .NET Framework uses CryptoConfig functionality.
///
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs
index 296cafef903597..58ed1b42610e61 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Apple.cs
@@ -21,6 +21,23 @@ public static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpa
return new AppleHmacProvider(hashAlgorithmId, key);
}
+ internal static bool HashSupported(string hashAlgorithmId)
+ {
+ switch (hashAlgorithmId)
+ {
+ case HashAlgorithmNames.MD5:
+ case HashAlgorithmNames.SHA1:
+ case HashAlgorithmNames.SHA256:
+ case HashAlgorithmNames.SHA384:
+ case HashAlgorithmNames.SHA512:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ internal static bool MacSupported(string hashAlgorithmId) => HashSupported(hashAlgorithmId);
+
internal static class OneShotHashProvider
{
public static unsafe int MacData(
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Browser.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Browser.cs
index 8bae776c7ac933..eea8e204cdc589 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Browser.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Browser.cs
@@ -5,6 +5,22 @@ namespace System.Security.Cryptography
{
internal static partial class HashProviderDispenser
{
+ internal static bool HashSupported(string hashAlgorithmId)
+ {
+ switch (hashAlgorithmId)
+ {
+ case HashAlgorithmNames.SHA1:
+ case HashAlgorithmNames.SHA256:
+ case HashAlgorithmNames.SHA384:
+ case HashAlgorithmNames.SHA512:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ internal static bool MacSupported(string hashAlgorithmId) => HashSupported(hashAlgorithmId);
+
public static HashProvider CreateHashProvider(string hashAlgorithmId)
{
switch (hashAlgorithmId)
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs
index 32cdc7dd93b1cc..78b8cd632b4340 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.OpenSsl.cs
@@ -22,6 +22,13 @@ internal static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlyS
return new HmacHashProvider(hashAlgorithmId, key);
}
+ internal static bool HashSupported(string hashAlgorithmId)
+ {
+ return Interop.Crypto.HashAlgorithmSupported(hashAlgorithmId);
+ }
+
+ internal static bool MacSupported(string hashAlgorithmId) => HashSupported(hashAlgorithmId);
+
internal static class OneShotHashProvider
{
public static int MacData(
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Windows.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Windows.cs
index e195a153393924..f6ae0f97eb2307 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Windows.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/HashProviderDispenser.Windows.cs
@@ -27,6 +27,50 @@ public static HashProvider CreateMacProvider(string hashAlgorithmId, ReadOnlySpa
return new HashProviderCng(hashAlgorithmId, key, isHmac: true);
}
+ internal static bool HashSupported(string hashAlgorithmId)
+ {
+ switch (hashAlgorithmId)
+ {
+ // We know that MD5, SHA1, and SHA2 are supported on all platforms. Don't bother asking.
+ case HashAlgorithmNames.MD5:
+ case HashAlgorithmNames.SHA1:
+ case HashAlgorithmNames.SHA256:
+ case HashAlgorithmNames.SHA384:
+ case HashAlgorithmNames.SHA512:
+ return true;
+ case HashAlgorithmNames.SHA3_256:
+ case HashAlgorithmNames.SHA3_384:
+ case HashAlgorithmNames.SHA3_512:
+ return BCryptAlgorithmCache.IsBCryptAlgorithmSupported(
+ hashAlgorithmId,
+ BCryptOpenAlgorithmProviderFlags.None);
+ default:
+ return false;
+ }
+ }
+
+ internal static bool MacSupported(string hashAlgorithmId)
+ {
+ switch (hashAlgorithmId)
+ {
+ // We know that MD5, SHA1, and SHA2 are supported on all platforms. Don't bother asking.
+ case HashAlgorithmNames.MD5:
+ case HashAlgorithmNames.SHA1:
+ case HashAlgorithmNames.SHA256:
+ case HashAlgorithmNames.SHA384:
+ case HashAlgorithmNames.SHA512:
+ return true;
+ case HashAlgorithmNames.SHA3_256:
+ case HashAlgorithmNames.SHA3_384:
+ case HashAlgorithmNames.SHA3_512:
+ return BCryptAlgorithmCache.IsBCryptAlgorithmSupported(
+ hashAlgorithmId,
+ BCryptOpenAlgorithmProviderFlags.BCRYPT_ALG_HANDLE_HMAC_FLAG);
+ default:
+ return false;
+ }
+ }
+
public static class OneShotHashProvider
{
public static unsafe int MacData(
@@ -143,6 +187,27 @@ private static unsafe void HashDataUsingPseudoHandle(
Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA512_ALG_HANDLE;
digestSizeInBytes = SHA512.HashSizeInBytes;
}
+ else if (hashAlgorithmId == HashAlgorithmNames.SHA3_256)
+ {
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA3_256_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA3_256_ALG_HANDLE;
+ digestSizeInBytes = SHA3_256.HashSizeInBytes;
+ }
+ else if (hashAlgorithmId == HashAlgorithmNames.SHA3_384)
+ {
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA3_384_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA3_384_ALG_HANDLE;
+ digestSizeInBytes = SHA3_384.HashSizeInBytes;
+ }
+ else if (hashAlgorithmId == HashAlgorithmNames.SHA3_512)
+ {
+ algHandle = isHmac ?
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_HMAC_SHA3_512_ALG_HANDLE :
+ Interop.BCrypt.BCryptAlgPseudoHandle.BCRYPT_SHA3_512_ALG_HANDLE;
+ digestSizeInBytes = SHA3_512.HashSizeInBytes;
+ }
else
{
Debug.Fail("Unknown hash algorithm.");
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/IncrementalHash.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/IncrementalHash.cs
index 904c72c1c28050..022476b0bd3cc7 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/IncrementalHash.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/IncrementalHash.cs
@@ -308,6 +308,7 @@ public void Dispose()
public static IncrementalHash CreateHash(HashAlgorithmName hashAlgorithm)
{
ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
+ CheckSha3Support(hashAlgorithm.Name);
return new IncrementalHash(hashAlgorithm, HashProviderDispenser.CreateHashProvider(hashAlgorithm.Name));
}
@@ -366,8 +367,28 @@ public static IncrementalHash CreateHMAC(HashAlgorithmName hashAlgorithm, byte[]
public static IncrementalHash CreateHMAC(HashAlgorithmName hashAlgorithm, ReadOnlySpan key)
{
ArgumentException.ThrowIfNullOrEmpty(hashAlgorithm.Name, nameof(hashAlgorithm));
+ CheckSha3Support(hashAlgorithm.Name);
return new IncrementalHash(hashAlgorithm, new HMACCommon(hashAlgorithm.Name, key, -1));
}
+
+ private static void CheckSha3Support(string hashAlgorithmName)
+ {
+ switch (hashAlgorithmName)
+ {
+ case HashAlgorithmNames.SHA3_256 when !SHA3_256.IsSupported:
+ Debug.Assert(!HMACSHA3_256.IsSupported);
+ throw new PlatformNotSupportedException();
+ case HashAlgorithmNames.SHA3_384 when !SHA3_384.IsSupported:
+ Debug.Assert(!HMACSHA3_384.IsSupported);
+ throw new PlatformNotSupportedException();
+ case HashAlgorithmNames.SHA3_512 when !SHA3_512.IsSupported:
+ Debug.Assert(!HMACSHA3_512.IsSupported);
+ throw new PlatformNotSupportedException();
+ default:
+ // Other unknown algorithms will be handled separately as CryptographicExceptions.
+ break;
+ }
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Pbkdf2Implementation.Windows.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Pbkdf2Implementation.Windows.cs
index 6829cbf7b63571..d05af7124b3af5 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Pbkdf2Implementation.Windows.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Pbkdf2Implementation.Windows.cs
@@ -97,6 +97,15 @@ private static unsafe void FillKeyDerivation(
case HashAlgorithmNames.SHA512:
hashBufferSize = SHA512.HashData(password, hashBuffer);
break;
+ case HashAlgorithmNames.SHA3_256:
+ hashBufferSize = SHA3_256.HashData(password, hashBuffer);
+ break;
+ case HashAlgorithmNames.SHA3_384:
+ hashBufferSize = SHA3_384.HashData(password, hashBuffer);
+ break;
+ case HashAlgorithmNames.SHA3_512:
+ hashBufferSize = SHA3_512.HashData(password, hashBuffer);
+ break;
default:
Debug.Fail($"Unexpected hash algorithm '{hashAlgorithmName}'");
throw new CryptographicException();
@@ -259,7 +268,7 @@ private static unsafe void FillDeriveKeyPBKDF2(
private static int GetHashBlockSize(string hashAlgorithmName)
{
- // Block sizes per NIST FIPS pub 180-4.
+ // Block sizes per NIST FIPS pub 180-4 and FIPS 202.
switch (hashAlgorithmName)
{
case HashAlgorithmNames.SHA1:
@@ -268,6 +277,12 @@ private static int GetHashBlockSize(string hashAlgorithmName)
case HashAlgorithmNames.SHA384:
case HashAlgorithmNames.SHA512:
return 1024 / 8;
+ case HashAlgorithmNames.SHA3_256:
+ return HMACSHA3_256.BlockSize;
+ case HashAlgorithmNames.SHA3_384:
+ return HMACSHA3_384.BlockSize;
+ case HashAlgorithmNames.SHA3_512:
+ return HMACSHA3_512.BlockSize;
default:
Debug.Fail($"Unexpected hash algorithm '{hashAlgorithmName}'");
throw new CryptographicException();
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs
index e6977e2e67e83f..7789143feb5b82 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSACryptoServiceProvider.Unix.cs
@@ -183,6 +183,8 @@ public override byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, RS
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.SignData(data, hashAlgorithm, padding);
}
@@ -195,6 +197,8 @@ public override byte[] SignData(byte[] data, int offset, int count, HashAlgorith
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.SignData(data, offset, count, hashAlgorithm, padding);
}
@@ -207,6 +211,8 @@ public override bool TrySignData(ReadOnlySpan data, Span destination
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.TrySignData(data, destination, hashAlgorithm, padding, out bytesWritten);
}
@@ -228,6 +234,8 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.SignHash(hash, hashAlgorithm, padding);
}
@@ -240,6 +248,8 @@ public override bool TrySignHash(ReadOnlySpan hash, Span destination
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.TrySignHash(hash, destination, hashAlgorithm, padding, out bytesWritten);
}
@@ -268,6 +278,8 @@ public override bool VerifyData(byte[] data, int offset, int count, byte[] signa
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.VerifyData(data, offset, count, signature, hashAlgorithm, padding);
}
@@ -280,6 +292,8 @@ public override bool VerifyData(ReadOnlySpan data, ReadOnlySpan sign
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.VerifyData(data, signature, hashAlgorithm, padding);
}
@@ -300,6 +314,8 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign
throw PaddingModeNotSupported();
}
+ CheckSHA3HashAlgorithm(hashAlgorithm);
+
return _impl.VerifyHash(hash, signature, hashAlgorithm, padding);
}
@@ -345,5 +361,16 @@ private static bool IsPublic(byte[] keyBlob)
return true;
}
+
+ private static void CheckSHA3HashAlgorithm(HashAlgorithmName hashAlgorithm)
+ {
+ if (hashAlgorithm == HashAlgorithmName.SHA3_256 ||
+ hashAlgorithm == HashAlgorithmName.SHA3_384 ||
+ hashAlgorithm == HashAlgorithmName.SHA3_512)
+ {
+ // Compat: Windows throws CryptographicException for SHA-3 HashAlgorithmName. So we will here, too.
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
+ }
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSAEncryptionPadding.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSAEncryptionPadding.cs
index c31f665ad40008..9a2feee6dac982 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSAEncryptionPadding.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSAEncryptionPadding.cs
@@ -10,36 +10,45 @@ namespace System.Security.Cryptography
///
public sealed class RSAEncryptionPadding : IEquatable
{
- private static readonly RSAEncryptionPadding s_pkcs1 = new RSAEncryptionPadding(RSAEncryptionPaddingMode.Pkcs1, default(HashAlgorithmName));
- private static readonly RSAEncryptionPadding s_oaepSHA1 = CreateOaep(HashAlgorithmName.SHA1);
- private static readonly RSAEncryptionPadding s_oaepSHA256 = CreateOaep(HashAlgorithmName.SHA256);
- private static readonly RSAEncryptionPadding s_oaepSHA384 = CreateOaep(HashAlgorithmName.SHA384);
- private static readonly RSAEncryptionPadding s_oaepSHA512 = CreateOaep(HashAlgorithmName.SHA512);
-
///
/// mode.
///
- public static RSAEncryptionPadding Pkcs1 { get { return s_pkcs1; } }
+ public static RSAEncryptionPadding Pkcs1 { get; } = new RSAEncryptionPadding(RSAEncryptionPaddingMode.Pkcs1, default);
///
/// mode with SHA1 hash algorithm.
///
- public static RSAEncryptionPadding OaepSHA1 { get { return s_oaepSHA1; } }
+ public static RSAEncryptionPadding OaepSHA1 { get; } = CreateOaep(HashAlgorithmName.SHA1);
///
/// mode with SHA256 hash algorithm.
///
- public static RSAEncryptionPadding OaepSHA256 { get { return s_oaepSHA256; } }
+ public static RSAEncryptionPadding OaepSHA256 { get; } = CreateOaep(HashAlgorithmName.SHA256);
///
/// mode with SHA384 hash algorithm.
///
- public static RSAEncryptionPadding OaepSHA384 { get { return s_oaepSHA384; } }
+ public static RSAEncryptionPadding OaepSHA384 { get; } = CreateOaep(HashAlgorithmName.SHA384);
///
/// mode with SHA512 hash algorithm.
///
- public static RSAEncryptionPadding OaepSHA512 { get { return s_oaepSHA512; } }
+ public static RSAEncryptionPadding OaepSHA512 { get; } = CreateOaep(HashAlgorithmName.SHA512);
+
+ ///
+ /// mode with SHA3-256 hash algorithm.
+ ///
+ public static RSAEncryptionPadding OaepSHA3_256 { get; } = CreateOaep(HashAlgorithmName.SHA3_256);
+
+ ///
+ /// mode with SHA3-384 hash algorithm.
+ ///
+ public static RSAEncryptionPadding OaepSHA3_384 { get; } = CreateOaep(HashAlgorithmName.SHA3_384);
+
+ ///
+ /// mode with SHA3-512 hash algorithm.
+ ///
+ public static RSAEncryptionPadding OaepSHA3_512 { get; } = CreateOaep(HashAlgorithmName.SHA3_512);
private readonly RSAEncryptionPaddingMode _mode;
private readonly HashAlgorithmName _oaepHashAlgorithm;
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.OneShot.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.OneShot.cs
index 88ca89094e3da0..a07718238a6d34 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.OneShot.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.OneShot.cs
@@ -323,13 +323,29 @@ private static void ValidateHashAlgorithm(HashAlgorithmName hashAlgorithm)
ArgumentException.ThrowIfNullOrEmpty(hashAlgorithmName, nameof(hashAlgorithm));
// MD5 intentionally left out.
- if (hashAlgorithmName != HashAlgorithmName.SHA1.Name &&
- hashAlgorithmName != HashAlgorithmName.SHA256.Name &&
- hashAlgorithmName != HashAlgorithmName.SHA384.Name &&
- hashAlgorithmName != HashAlgorithmName.SHA512.Name)
+ if (hashAlgorithmName == HashAlgorithmName.SHA1.Name ||
+ hashAlgorithmName == HashAlgorithmName.SHA256.Name ||
+ hashAlgorithmName == HashAlgorithmName.SHA384.Name ||
+ hashAlgorithmName == HashAlgorithmName.SHA512.Name)
{
- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName));
+ return;
+ }
+
+ if (hashAlgorithmName == HashAlgorithmName.SHA3_256.Name ||
+ hashAlgorithmName == HashAlgorithmName.SHA3_384.Name ||
+ hashAlgorithmName == HashAlgorithmName.SHA3_512.Name)
+ {
+ // All current platforms support HMAC-SHA3-256, 384, and 512 together, so we can simplify the check
+ // to just checking HMAC-SHA3-256 for the availability of 384 and 512, too.
+ if (HMACSHA3_256.IsSupported)
+ {
+ return;
+ }
+
+ throw new PlatformNotSupportedException();
}
+
+ throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName));
}
}
}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs
index 736fc089ee9041..4c1ee1acc8663f 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs
@@ -252,7 +252,10 @@ private IncrementalHash OpenHmac(ReadOnlySpan password)
if (hashAlgorithm != HashAlgorithmName.SHA1 &&
hashAlgorithm != HashAlgorithmName.SHA256 &&
hashAlgorithm != HashAlgorithmName.SHA384 &&
- hashAlgorithm != HashAlgorithmName.SHA512)
+ hashAlgorithm != HashAlgorithmName.SHA512 &&
+ hashAlgorithm != HashAlgorithmName.SHA3_256 &&
+ hashAlgorithm != HashAlgorithmName.SHA3_384 &&
+ hashAlgorithm != HashAlgorithmName.SHA3_512)
{
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_256.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_256.cs
new file mode 100644
index 00000000000000..659fa2d2926550
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_256.cs
@@ -0,0 +1,324 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Cryptography;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes the SHA3-256 hash for the input data.
+ ///
+ ///
+ /// This algorithm is specified by FIPS 202.
+ ///
+ public abstract class SHA3_256 : HashAlgorithm
+ {
+ ///
+ /// The hash size produced by the SHA3-256 algorithm, in bits.
+ ///
+ public const int HashSizeInBits = 256;
+
+ ///
+ /// The hash size produced by the SHA3-256 algorithm, in bytes.
+ ///
+ public const int HashSizeInBytes = HashSizeInBits / 8;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ protected SHA3_256()
+ {
+ HashSizeValue = HashSizeInBits;
+ }
+
+ ///
+ /// Gets a value that indicates whether the algorithm is supported on the current platform.
+ ///
+ ///
+ /// if the algorithm is supported; otherwise, .
+ ///
+ public static bool IsSupported { get; } = HashProviderDispenser.HashSupported(HashAlgorithmNames.SHA3_256);
+
+ ///
+ /// Creates an instance of the default implementation of .
+ ///
+ ///
+ /// A new instance of .
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static new SHA3_256 Create()
+ {
+ CheckSha3Support();
+ return new Implementation();
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-256 algorithm.
+ ///
+ /// The data to hash.
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static byte[] HashData(byte[] source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ return HashData(new ReadOnlySpan(source));
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-256 algorithm.
+ ///
+ /// The data to hash.
+ /// The hash of the data.
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static byte[] HashData(ReadOnlySpan source)
+ {
+ byte[] buffer = new byte[HashSizeInBytes];
+
+ int written = HashData(source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-256 algorithm.
+ ///
+ /// The data to hash.
+ /// The buffer to receive the hash value.
+ /// The total number of bytes written to .
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-256 algorithm always produces a 256-bit hash, or 32 bytes.
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static int HashData(ReadOnlySpan source, Span destination)
+ {
+ if (!TryHashData(source, destination, out int bytesWritten))
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ return bytesWritten;
+ }
+
+ ///
+ /// Attempts to compute the hash of data using the SHA3-256 algorithm.
+ ///
+ /// The data to hash.
+ /// The buffer to receive the hash value.
+ ///
+ /// When this method returns, the total number of bytes written into .
+ ///
+ ///
+ /// if is too small to hold the
+ /// calculated hash, otherwise.
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten)
+ {
+ CheckSha3Support();
+
+ if (destination.Length < HashSizeInBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.HashData(HashAlgorithmNames.SHA3_256, source, destination);
+ Debug.Assert(bytesWritten == HashSizeInBytes);
+
+ return true;
+ }
+
+ ///
+ /// Computes the hash of a stream using the SHA3-256 algorithm.
+ ///
+ /// The stream to hash.
+ /// The buffer to receive the hash value.
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-256 algorithm always produces a 256-bit hash, or 32 bytes.
+ ///
+ ///
-or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static int HashData(Stream source, Span destination)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStream(HashAlgorithmNames.SHA3_256, source, destination);
+ }
+
+ ///
+ /// Computes the hash of a stream using the SHA3-256 algorithm.
+ ///
+ /// The stream to hash.
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static byte[] HashData(Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStream(HashAlgorithmNames.SHA3_256, HashSizeInBytes, source);
+ }
+
+ ///
+ /// Asynchronously computes the hash of a stream using the SHA3-256 algorithm.
+ ///
+ /// The stream to hash.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA3_256, source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the hash of a stream using the SHA3-256 algorithm.
+ ///
+ /// The stream to hash.
+ /// The buffer to receive the hash value.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-256 algorithm always produces a 256-bit hash, or 32 bytes.
+ ///
+ ///
-or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ ///
+ /// The platform does not support SHA3-256.
+ ///
+ public static ValueTask HashDataAsync(
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStreamAsync(
+ HashAlgorithmNames.SHA3_256,
+ source,
+ destination,
+ cancellationToken);
+ }
+
+ private static void CheckSha3Support()
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException();
+ }
+
+ private sealed class Implementation : SHA3_256
+ {
+ private readonly HashProvider _hashProvider;
+
+ public Implementation()
+ {
+ _hashProvider = HashProviderDispenser.CreateHashProvider(HashAlgorithmNames.SHA3_256);
+ HashSizeValue = _hashProvider.HashSizeInBytes * 8;
+ }
+
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
+ _hashProvider.AppendHashData(array, ibStart, cbSize);
+
+ protected sealed override void HashCore(ReadOnlySpan source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
+
+ public sealed override void Initialize() => _hashProvider.Reset();
+
+ protected sealed override void Dispose(bool disposing)
+ {
+ _hashProvider.Dispose(disposing);
+ base.Dispose(disposing);
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_384.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_384.cs
new file mode 100644
index 00000000000000..d74787d4698e93
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_384.cs
@@ -0,0 +1,325 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Cryptography;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes the SHA3-384 hash for the input data.
+ ///
+ ///
+ /// This algorithm is specified by FIPS 202.
+ ///
+ public abstract class SHA3_384 : HashAlgorithm
+ {
+ ///
+ /// The hash size produced by the SHA3-384 algorithm, in bits.
+ ///
+ public const int HashSizeInBits = 384;
+
+ ///
+ /// The hash size produced by the SHA3-384 algorithm, in bytes.
+ ///
+ public const int HashSizeInBytes = HashSizeInBits / 8;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ protected SHA3_384()
+ {
+ HashSizeValue = HashSizeInBits;
+ }
+
+ ///
+ /// Gets a value that indicates whether the algorithm is supported on the current platform.
+ ///
+ ///
+ /// if the algorithm is supported; otherwise, .
+ ///
+ public static bool IsSupported { get; } = HashProviderDispenser.HashSupported(HashAlgorithmNames.SHA3_384);
+
+ ///
+ /// Creates an instance of the default implementation of .
+ ///
+ ///
+ /// A new instance of .
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static new SHA3_384 Create()
+ {
+ CheckSha3Support();
+ return new Implementation();
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-384 algorithm.
+ ///
+ /// The data to hash.
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static byte[] HashData(byte[] source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ return HashData(new ReadOnlySpan(source));
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-384 algorithm.
+ ///
+ /// The data to hash.
+ /// The hash of the data.
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static byte[] HashData(ReadOnlySpan source)
+ {
+ byte[] buffer = new byte[HashSizeInBytes];
+
+ int written = HashData(source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-384 algorithm.
+ ///
+ /// The data to hash.
+ /// The buffer to receive the hash value.
+ /// The total number of bytes written to .
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-384 algorithm always produces a 384-bit hash, or 48 bytes.
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static int HashData(ReadOnlySpan source, Span destination)
+ {
+ if (!TryHashData(source, destination, out int bytesWritten))
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ return bytesWritten;
+ }
+
+
+ ///
+ /// Attempts to compute the hash of data using the SHA3-384 algorithm.
+ ///
+ /// The data to hash.
+ /// The buffer to receive the hash value.
+ ///
+ /// When this method returns, the total number of bytes written into .
+ ///
+ ///
+ /// if is too small to hold the
+ /// calculated hash, otherwise.
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten)
+ {
+ CheckSha3Support();
+
+ if (destination.Length < HashSizeInBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.HashData(HashAlgorithmNames.SHA3_384, source, destination);
+ Debug.Assert(bytesWritten == HashSizeInBytes);
+
+ return true;
+ }
+
+ ///
+ /// Computes the hash of a stream using the SHA3-384 algorithm.
+ ///
+ /// The stream to hash.
+ /// The buffer to receive the hash value.
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-384 algorithm always produces a 384-bit hash, or 48 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static int HashData(Stream source, Span destination)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStream(HashAlgorithmNames.SHA3_384, source, destination);
+ }
+
+ ///
+ /// Computes the hash of a stream using the SHA3-384 algorithm.
+ ///
+ /// The stream to hash.
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static byte[] HashData(Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStream(HashAlgorithmNames.SHA3_384, HashSizeInBytes, source);
+ }
+
+ ///
+ /// Asynchronously computes the hash of a stream using the SHA3-384 algorithm.
+ ///
+ /// The stream to hash.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA3_384, source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the hash of a stream using the SHA3-384 algorithm.
+ ///
+ /// The stream to hash.
+ /// The buffer to receive the hash value.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-384 algorithm always produces a 384-bit hash, or 48 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ ///
+ /// The platform does not support SHA3-384.
+ ///
+ public static ValueTask HashDataAsync(
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStreamAsync(
+ HashAlgorithmNames.SHA3_384,
+ source,
+ destination,
+ cancellationToken);
+ }
+
+ private static void CheckSha3Support()
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException();
+ }
+
+ private sealed class Implementation : SHA3_384
+ {
+ private readonly HashProvider _hashProvider;
+
+ public Implementation()
+ {
+ _hashProvider = HashProviderDispenser.CreateHashProvider(HashAlgorithmNames.SHA3_384);
+ HashSizeValue = _hashProvider.HashSizeInBytes * 8;
+ }
+
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
+ _hashProvider.AppendHashData(array, ibStart, cbSize);
+
+ protected sealed override void HashCore(ReadOnlySpan source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
+
+ public sealed override void Initialize() => _hashProvider.Reset();
+
+ protected sealed override void Dispose(bool disposing)
+ {
+ _hashProvider.Dispose(disposing);
+ base.Dispose(disposing);
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_512.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_512.cs
new file mode 100644
index 00000000000000..2c716453827a3c
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHA3_512.cs
@@ -0,0 +1,324 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.Cryptography;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes the SHA3-512 hash for the input data.
+ ///
+ ///
+ /// This algorithm is specified by FIPS 202.
+ ///
+ public abstract class SHA3_512 : HashAlgorithm
+ {
+ ///
+ /// The hash size produced by the SHA3-512 algorithm, in bits.
+ ///
+ public const int HashSizeInBits = 512;
+
+ ///
+ /// The hash size produced by the SHA3-512 algorithm, in bytes.
+ ///
+ public const int HashSizeInBytes = HashSizeInBits / 8;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ protected SHA3_512()
+ {
+ HashSizeValue = HashSizeInBits;
+ }
+
+ ///
+ /// Gets a value that indicates whether the algorithm is supported on the current platform.
+ ///
+ ///
+ /// if the algorithm is supported; otherwise, .
+ ///
+ public static bool IsSupported { get; } = HashProviderDispenser.HashSupported(HashAlgorithmNames.SHA3_512);
+
+ ///
+ /// Creates an instance of the default implementation of .
+ ///
+ ///
+ /// A new instance of .
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static new SHA3_512 Create()
+ {
+ CheckSha3Support();
+ return new Implementation();
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-512 algorithm.
+ ///
+ /// The data to hash.
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static byte[] HashData(byte[] source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ return HashData(new ReadOnlySpan(source));
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-512 algorithm.
+ ///
+ /// The data to hash.
+ /// The hash of the data.
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static byte[] HashData(ReadOnlySpan source)
+ {
+ byte[] buffer = new byte[HashSizeInBytes];
+
+ int written = HashData(source, buffer.AsSpan());
+ Debug.Assert(written == buffer.Length);
+
+ return buffer;
+ }
+
+ ///
+ /// Computes the hash of data using the SHA3-512 algorithm.
+ ///
+ /// The data to hash.
+ /// The buffer to receive the hash value.
+ /// The total number of bytes written to .
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-512 algorithm always produces a 512-bit hash, or 64 bytes.
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static int HashData(ReadOnlySpan source, Span destination)
+ {
+ if (!TryHashData(source, destination, out int bytesWritten))
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ return bytesWritten;
+ }
+
+ ///
+ /// Attempts to compute the hash of data using the SHA3-512 algorithm.
+ ///
+ /// The data to hash.
+ /// The buffer to receive the hash value.
+ ///
+ /// When this method returns, the total number of bytes written into .
+ ///
+ ///
+ /// if is too small to hold the
+ /// calculated hash, otherwise.
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten)
+ {
+ CheckSha3Support();
+
+ if (destination.Length < HashSizeInBytes)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ bytesWritten = HashProviderDispenser.OneShotHashProvider.HashData(HashAlgorithmNames.SHA3_512, source, destination);
+ Debug.Assert(bytesWritten == HashSizeInBytes);
+
+ return true;
+ }
+
+ ///
+ /// Computes the hash of a stream using the SHA3-512 algorithm.
+ ///
+ /// The stream to hash.
+ /// The buffer to receive the hash value.
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-512 algorithm always produces a 512-bit hash, or 64 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static int HashData(Stream source, Span destination)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStream(HashAlgorithmNames.SHA3_512, source, destination);
+ }
+
+ ///
+ /// Computes the hash of a stream using the SHA3-512 algorithm.
+ ///
+ /// The stream to hash.
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static byte[] HashData(Stream source)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStream(HashAlgorithmNames.SHA3_512, HashSizeInBytes, source);
+ }
+
+ ///
+ /// Asynchronously computes the hash of a stream using the SHA3-512 algorithm.
+ ///
+ /// The stream to hash.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The hash of the data.
+ ///
+ /// is .
+ ///
+ ///
+ /// does not support reading.
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStreamAsync(HashAlgorithmNames.SHA3_512, source, cancellationToken);
+ }
+
+ ///
+ /// Asynchronously computes the hash of a stream using the SHA3-512 algorithm.
+ ///
+ /// The stream to hash.
+ /// The buffer to receive the hash value.
+ ///
+ /// The token to monitor for cancellation requests.
+ /// The default value is .
+ ///
+ /// The total number of bytes written to .
+ ///
+ /// is .
+ ///
+ ///
+ ///
+ /// The buffer in is too small to hold the calculated hash
+ /// size. The SHA3-512 algorithm always produces a 512-bit hash, or 64 bytes.
+ ///
+ /// -or-
+ ///
+ /// does not support reading.
+ ///
+ ///
+ ///
+ /// The platform does not support SHA3-512.
+ ///
+ public static ValueTask HashDataAsync(
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(source);
+
+ if (destination.Length < HashSizeInBytes)
+ throw new ArgumentException(SR.Argument_DestinationTooShort, nameof(destination));
+
+ if (!source.CanRead)
+ throw new ArgumentException(SR.Argument_StreamNotReadable, nameof(source));
+
+ CheckSha3Support();
+ return LiteHashProvider.HashStreamAsync(
+ HashAlgorithmNames.SHA3_512,
+ source,
+ destination,
+ cancellationToken);
+ }
+
+ private static void CheckSha3Support()
+ {
+ if (!IsSupported)
+ throw new PlatformNotSupportedException();
+ }
+
+ private sealed class Implementation : SHA3_512
+ {
+ private readonly HashProvider _hashProvider;
+
+ public Implementation()
+ {
+ _hashProvider = HashProviderDispenser.CreateHashProvider(HashAlgorithmNames.SHA3_512);
+ HashSizeValue = _hashProvider.HashSizeInBytes * 8;
+ }
+
+ protected sealed override void HashCore(byte[] array, int ibStart, int cbSize) =>
+ _hashProvider.AppendHashData(array, ibStart, cbSize);
+
+ protected sealed override void HashCore(ReadOnlySpan source) =>
+ _hashProvider.AppendHashData(source);
+
+ protected sealed override byte[] HashFinal() =>
+ _hashProvider.FinalizeHashAndReset();
+
+ protected sealed override bool TryHashFinal(Span destination, out int bytesWritten) =>
+ _hashProvider.TryFinalizeHashAndReset(destination, out bytesWritten);
+
+ public sealed override void Initialize() => _hashProvider.Reset();
+
+ protected sealed override void Dispose(bool disposing)
+ {
+ _hashProvider.Dispose(disposing);
+ base.Dispose(disposing);
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs
index 75025e598ffc08..77adda425ce3d6 100644
--- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs
+++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs
@@ -65,6 +65,12 @@ private static int HashOneShot(HashAlgorithmName hashAlgorithm, ReadOnlySpan true;
+ public bool SupportsSha3 => false;
+
private static bool IsValueOrFriendlyNameValid(string friendlyNameOrValue)
{
if (string.IsNullOrEmpty(friendlyNameOrValue))
diff --git a/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Unix.cs b/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Unix.cs
index d00c95b27eaffa..162831d72ac696 100644
--- a/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Unix.cs
+++ b/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Unix.cs
@@ -36,6 +36,7 @@ public bool ExplicitCurvesSupported
public bool CanDeriveNewPublicKey { get; } = !PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst;
public bool SupportsRawDerivation => true;
+ public bool SupportsSha3 => PlatformDetection.SupportsSha3;
private static bool IsValueOrFriendlyNameValid(string friendlyNameOrValue)
{
diff --git a/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Windows.cs b/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Windows.cs
index 49f8ff15761e17..71471a532acdb3 100644
--- a/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Windows.cs
+++ b/src/libraries/System.Security.Cryptography/tests/DefaultECDiffieHellmanProvider.Windows.cs
@@ -24,6 +24,7 @@ public bool ExplicitCurvesSupported
public bool CanDeriveNewPublicKey => true;
public bool SupportsRawDerivation => PlatformDetection.IsWindows10OrLater;
+ public bool SupportsSha3 => PlatformDetection.SupportsSha3;
private static bool NativeOidFriendlyNameExists(string oidFriendlyName)
{
diff --git a/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs b/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs
index e39bc782bc04a4..c65b78ace1288e 100644
--- a/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs
+++ b/src/libraries/System.Security.Cryptography/tests/DefaultRSAProvider.cs
@@ -47,6 +47,8 @@ public bool Supports384PrivateKey
public bool SupportsSha2Oaep { get; } = true;
public bool SupportsPss { get; } = true;
+
+ public bool SupportsSha3 { get; } = SHA3_256.IsSupported; // If SHA3_256 is supported, assume 384 and 512 are, too.
}
public partial class RSAFactory
diff --git a/src/libraries/System.Security.Cryptography/tests/HKDFTests.cs b/src/libraries/System.Security.Cryptography/tests/HKDFTests.cs
index 059c60c42bbf90..6f58c00e80994c 100644
--- a/src/libraries/System.Security.Cryptography/tests/HKDFTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HKDFTests.cs
@@ -15,25 +15,25 @@ public abstract class HKDFTests
protected abstract byte[] DeriveKey(HashAlgorithmName hash, byte[] ikm, int outputLength, byte[] salt, byte[] info);
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
- public void Rfc5869ExtractTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCases))]
+ public void ExtractTests(HkdfTestCase test)
{
byte[] prk = Extract(test.Hash, test.Prk.Length, test.Ikm, test.Salt);
Assert.Equal(test.Prk, prk);
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
+ [MemberData(nameof(GetHkdfTestCases))]
[SkipOnPlatform(TestPlatforms.Browser, "MD5 is not supported on Browser")]
- public void Rfc5869ExtractTamperHashTests(Rfc5869TestCase test)
+ public void ExtractTamperHashTests(HkdfTestCase test)
{
byte[] prk = Extract(HashAlgorithmName.MD5, 128 / 8, test.Ikm, test.Salt);
Assert.NotEqual(test.Prk, prk);
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
- public void Rfc5869ExtractTamperIkmTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCases))]
+ public void ExtractTamperIkmTests(HkdfTestCase test)
{
byte[] ikm = test.Ikm.ToArray();
ikm[0] ^= 1;
@@ -42,8 +42,8 @@ public void Rfc5869ExtractTamperIkmTests(Rfc5869TestCase test)
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCasesWithNonEmptySalt))]
- public void Rfc5869ExtractTamperSaltTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCasesWithNonEmptySalt))]
+ public void ExtractTamperSaltTests(HkdfTestCase test)
{
byte[] salt = test.Salt.ToArray();
salt[0] ^= 1;
@@ -52,7 +52,7 @@ public void Rfc5869ExtractTamperSaltTests(Rfc5869TestCase test)
}
[Fact]
- public void Rfc5869ExtractDefaultHash()
+ public void ExtractDefaultHash()
{
byte[] ikm = new byte[20];
byte[] salt = new byte[20];
@@ -62,7 +62,7 @@ public void Rfc5869ExtractDefaultHash()
}
[Fact]
- public void Rfc5869ExtractNonsensicalHash()
+ public void ExtractNonsensicalHash()
{
byte[] ikm = new byte[20];
byte[] salt = new byte[20];
@@ -72,7 +72,7 @@ public void Rfc5869ExtractNonsensicalHash()
}
[Fact]
- public void Rfc5869ExtractEmptyIkm()
+ public void ExtractEmptyIkm()
{
byte[] salt = new byte[20];
byte[] ikm = Array.Empty();
@@ -83,7 +83,7 @@ public void Rfc5869ExtractEmptyIkm()
}
[Fact]
- public void Rfc5869ExtractEmptySalt()
+ public void ExtractEmptySalt()
{
byte[] ikm = new byte[20];
byte[] salt = Array.Empty();
@@ -92,15 +92,15 @@ public void Rfc5869ExtractEmptySalt()
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
- public void Rfc5869ExpandTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCases))]
+ public void ExpandTests(HkdfTestCase test)
{
byte[] okm = Expand(test.Hash, test.Prk, test.Okm.Length, test.Info);
Assert.Equal(test.Okm, okm);
}
[Fact]
- public void Rfc5869ExpandDefaultHash()
+ public void ExpandDefaultHash()
{
byte[] prk = new byte[20];
AssertExtensions.Throws(
@@ -109,7 +109,7 @@ public void Rfc5869ExpandDefaultHash()
}
[Fact]
- public void Rfc5869ExpandNonsensicalHash()
+ public void ExpandNonsensicalHash()
{
byte[] prk = new byte[20];
AssertExtensions.Throws(
@@ -118,8 +118,8 @@ public void Rfc5869ExpandNonsensicalHash()
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
- public void Rfc5869ExpandTamperPrkTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCases))]
+ public void ExpandTamperPrkTests(HkdfTestCase test)
{
byte[] prk = test.Prk.ToArray();
prk[0] ^= 1;
@@ -129,7 +129,7 @@ public void Rfc5869ExpandTamperPrkTests(Rfc5869TestCase test)
[Theory]
[MemberData(nameof(GetPrkTooShortTestCases))]
- public void Rfc5869ExpandPrkTooShort(HashAlgorithmName hash, int prkSize)
+ public void ExpandPrkTooShort(HashAlgorithmName hash, int prkSize)
{
byte[] prk = new byte[prkSize];
AssertExtensions.Throws(
@@ -138,7 +138,7 @@ public void Rfc5869ExpandPrkTooShort(HashAlgorithmName hash, int prkSize)
}
[Fact]
- public void Rfc5869ExpandOkmMaxSize()
+ public void ExpandOkmMaxSize()
{
byte[] prk = new byte[20];
@@ -148,15 +148,15 @@ public void Rfc5869ExpandOkmMaxSize()
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
- public void Rfc5869DeriveKeyTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCases))]
+ public void DeriveKeyTests(HkdfTestCase test)
{
byte[] okm = DeriveKey(test.Hash, test.Ikm, test.Okm.Length, test.Salt, test.Info);
Assert.Equal(test.Okm, okm);
}
[Fact]
- public void Rfc5869DeriveKeyDefaultHash()
+ public void DeriveKeyDefaultHash()
{
byte[] ikm = new byte[20];
AssertExtensions.Throws(
@@ -165,7 +165,7 @@ public void Rfc5869DeriveKeyDefaultHash()
}
[Fact]
- public void Rfc5869DeriveKeyNonSensicalHash()
+ public void DeriveKeyNonSensicalHash()
{
byte[] ikm = new byte[20];
AssertExtensions.Throws(
@@ -174,8 +174,8 @@ public void Rfc5869DeriveKeyNonSensicalHash()
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCases))]
- public void Rfc5869DeriveKeyTamperIkmTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCases))]
+ public void DeriveKeyTamperIkmTests(HkdfTestCase test)
{
byte[] ikm = test.Ikm.ToArray();
ikm[0] ^= 1;
@@ -184,8 +184,8 @@ public void Rfc5869DeriveKeyTamperIkmTests(Rfc5869TestCase test)
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCasesWithNonEmptySalt))]
- public void Rfc5869DeriveKeyTamperSaltTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCasesWithNonEmptySalt))]
+ public void DeriveKeyTamperSaltTests(HkdfTestCase test)
{
byte[] salt = test.Salt.ToArray();
salt[0] ^= 1;
@@ -194,8 +194,8 @@ public void Rfc5869DeriveKeyTamperSaltTests(Rfc5869TestCase test)
}
[Theory]
- [MemberData(nameof(GetRfc5869TestCasesWithNonEmptyInfo))]
- public void Rfc5869DeriveKeyTamperInfoTests(Rfc5869TestCase test)
+ [MemberData(nameof(GetHkdfTestCasesWithNonEmptyInfo))]
+ public void DeriveKeyTamperInfoTests(HkdfTestCase test)
{
byte[] info = test.Info.ToArray();
info[0] ^= 1;
@@ -203,17 +203,33 @@ public void Rfc5869DeriveKeyTamperInfoTests(Rfc5869TestCase test)
Assert.NotEqual(test.Okm, okm);
}
- public static IEnumerable GetRfc5869TestCases()
+ [Theory]
+ [MemberData(nameof(Sha3TestCases))]
+ public void Sha3Tests(HkdfTestCase test)
+ {
+ if (PlatformDetection.SupportsSha3)
+ {
+ byte[] okm = DeriveKey(test.Hash, test.Ikm, test.Okm.Length, test.Salt, test.Info);
+ Assert.Equal(test.Okm, okm);
+ }
+ else
+ {
+ Assert.Throws(() =>
+ DeriveKey(test.Hash, test.Ikm, test.Okm.Length, test.Salt, test.Info));
+ }
+ }
+
+ public static IEnumerable GetHkdfTestCases()
{
- foreach (Rfc5869TestCase test in Rfc5869TestCases)
+ foreach (HkdfTestCase test in Rfc5869TestCases)
{
yield return new object[] { test };
}
}
- public static IEnumerable GetRfc5869TestCasesWithNonEmptySalt()
+ public static IEnumerable GetHkdfTestCasesWithNonEmptySalt()
{
- foreach (Rfc5869TestCase test in Rfc5869TestCases)
+ foreach (HkdfTestCase test in Rfc5869TestCases)
{
if (test.Salt != null && test.Salt.Length != 0)
{
@@ -222,9 +238,9 @@ public static IEnumerable GetRfc5869TestCasesWithNonEmptySalt()
}
}
- public static IEnumerable GetRfc5869TestCasesWithNonEmptyInfo()
+ public static IEnumerable GetHkdfTestCasesWithNonEmptyInfo()
{
- foreach (Rfc5869TestCase test in Rfc5869TestCases)
+ foreach (HkdfTestCase test in Rfc5869TestCases)
{
if (test.Info != null && test.Info.Length != 0)
{
@@ -245,11 +261,18 @@ public static IEnumerable GetPrkTooShortTestCases()
{
yield return new object[] { HashAlgorithmName.MD5, 128 / 8 - 1 };
}
+
+ if (PlatformDetection.SupportsSha3)
+ {
+ yield return new object[] { HashAlgorithmName.SHA3_256, SHA3_256.HashSizeInBytes - 1 };
+ yield return new object[] { HashAlgorithmName.SHA3_384, SHA3_384.HashSizeInBytes - 1 };
+ yield return new object[] { HashAlgorithmName.SHA3_512, SHA3_512.HashSizeInBytes - 1 };
+ }
}
- private static Rfc5869TestCase[] Rfc5869TestCases { get; } = new Rfc5869TestCase[7]
+ private static HkdfTestCase[] Rfc5869TestCases { get; } = new HkdfTestCase[7]
{
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Basic test case with SHA-256",
Hash = HashAlgorithmName.SHA256,
@@ -264,7 +287,7 @@ public static IEnumerable GetPrkTooShortTestCases()
"2d2d0a90cf1a5a4c5db02d56ecc4c5bf" +
"34007208d5b887185865").HexToByteArray(),
},
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Test with SHA-256 and longer inputs/outputs",
Hash = HashAlgorithmName.SHA256,
@@ -297,7 +320,7 @@ public static IEnumerable GetPrkTooShortTestCases()
"cc30c58179ec3e87c14c01d5c1f3434f" +
"1d87").HexToByteArray(),
},
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Test with SHA-256 and zero-length salt/info",
Hash = HashAlgorithmName.SHA256,
@@ -312,7 +335,7 @@ public static IEnumerable GetPrkTooShortTestCases()
"b8a11f5c5ee1879ec3454e5f3c738d2d" +
"9d201395faa4b61a96c8").HexToByteArray(),
},
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Basic test case with SHA-1",
Hash = HashAlgorithmName.SHA1,
@@ -325,7 +348,7 @@ public static IEnumerable GetPrkTooShortTestCases()
"a4f14b822f5b091568a9cdd4f155fda2" +
"c22e422478d305f3f896").HexToByteArray(),
},
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Test with SHA-1 and longer inputs/outputs",
Hash = HashAlgorithmName.SHA1,
@@ -356,7 +379,7 @@ public static IEnumerable GetPrkTooShortTestCases()
"927336d0441f4c4300e2cff0d0900b52" +
"d3b4").HexToByteArray(),
},
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Test with SHA-1 and zero-length salt/info",
Hash = HashAlgorithmName.SHA1,
@@ -369,7 +392,7 @@ public static IEnumerable GetPrkTooShortTestCases()
"b9ae52057220a306e07b6b87e8df21d0" +
"ea00033de03984d34918").HexToByteArray(),
},
- new Rfc5869TestCase()
+ new HkdfTestCase()
{
Name = "Test with SHA-1, salt not provided (defaults to HashLen zero octets), zero-length info",
Hash = HashAlgorithmName.SHA1,
@@ -384,7 +407,55 @@ public static IEnumerable GetPrkTooShortTestCases()
},
};
- public struct Rfc5869TestCase
+ public static IEnumerable Sha3TestCases
+ {
+ // These cases were generated from the openssl kdf command.
+ // openssl kdf -keylen 8 -kdfopt digest:SHA3-256 -kdfopt hexkey:000102030405060708090A0B0C0D0E0F \
+ // -kdfopt salt:mysalt -kdfopt info:myinfo -binary HKDF | xxd -p
+ get
+ {
+ yield return new object[]
+ {
+ new HkdfTestCase
+ {
+ Name = "SHA3-256 with salt and info",
+ Hash = HashAlgorithmName.SHA3_256,
+ Ikm = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F".HexToByteArray(),
+ Salt = "mysalt"u8.ToArray(),
+ Info = "myinfo"u8.ToArray(),
+ Okm = "35bd9d1c75cf7e30".HexToByteArray(),
+ }
+ };
+
+ yield return new object[]
+ {
+ new HkdfTestCase
+ {
+ Name = "SHA3-384 with salt and info",
+ Hash = HashAlgorithmName.SHA3_384,
+ Ikm = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F".HexToByteArray(),
+ Salt = "mysalt"u8.ToArray(),
+ Info = "myinfo"u8.ToArray(),
+ Okm = "323a8ab50c7190c8".HexToByteArray(),
+ }
+ };
+
+ yield return new object[]
+ {
+ new HkdfTestCase
+ {
+ Name = "SHA3-512 with salt and info",
+ Hash = HashAlgorithmName.SHA3_512,
+ Ikm = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F".HexToByteArray(),
+ Salt = "mysalt"u8.ToArray(),
+ Info = "myinfo"u8.ToArray(),
+ Okm = "27693b36a489e9f1".HexToByteArray(),
+ }
+ };
+ }
+ }
+
+ public struct HkdfTestCase
{
public string Name { get; set; }
public HashAlgorithmName Hash { get; set; }
@@ -415,7 +486,7 @@ protected override byte[] DeriveKey(HashAlgorithmName hash, byte[] ikm, int outp
}
[Fact]
- public void Rfc5869ExtractNullIkm()
+ public void ExtractNullIkm()
{
byte[] salt = new byte[20];
AssertExtensions.Throws(
@@ -424,7 +495,7 @@ public void Rfc5869ExtractNullIkm()
}
[Fact]
- public void Rfc5869ExpandOkmMaxSizePlusOne()
+ public void ExpandOkmMaxSizePlusOne()
{
byte[] prk = new byte[20];
AssertExtensions.Throws(
@@ -433,7 +504,7 @@ public void Rfc5869ExpandOkmMaxSizePlusOne()
}
[Fact]
- public void Rfc5869ExpandOkmPotentiallyOverflowingValue()
+ public void ExpandOkmPotentiallyOverflowingValue()
{
byte[] prk = new byte[20];
AssertExtensions.Throws(
@@ -442,7 +513,7 @@ public void Rfc5869ExpandOkmPotentiallyOverflowingValue()
}
[Fact]
- public void Rfc5869ExpandOutputLengthZero()
+ public void ExpandOutputLengthZero()
{
byte[] prk = new byte[20];
AssertExtensions.Throws(
@@ -451,7 +522,7 @@ public void Rfc5869ExpandOutputLengthZero()
}
[Fact]
- public void Rfc5869ExpandOutputLengthLessThanZero()
+ public void ExpandOutputLengthLessThanZero()
{
byte[] prk = new byte[20];
AssertExtensions.Throws(
@@ -460,7 +531,7 @@ public void Rfc5869ExpandOutputLengthLessThanZero()
}
[Fact]
- public void Rfc5869DeriveKeyNullIkm()
+ public void DeriveKeyNullIkm()
{
AssertExtensions.Throws(
"ikm",
@@ -468,7 +539,7 @@ public void Rfc5869DeriveKeyNullIkm()
}
[Fact]
- public void Rfc5869DeriveKeyOkmMaxSizePlusOne()
+ public void DeriveKeyOkmMaxSizePlusOne()
{
byte[] ikm = new byte[20];
AssertExtensions.Throws(
@@ -477,7 +548,7 @@ public void Rfc5869DeriveKeyOkmMaxSizePlusOne()
}
[Fact]
- public void Rfc5869DeriveKeyOkmPotentiallyOverflowingValue()
+ public void DeriveKeyOkmPotentiallyOverflowingValue()
{
byte[] ikm = new byte[20];
AssertExtensions.Throws(
@@ -486,7 +557,7 @@ public void Rfc5869DeriveKeyOkmPotentiallyOverflowingValue()
}
[Fact]
- public void Rfc5869DeriveOutputLengthZero()
+ public void DeriveOutputLengthZero()
{
byte[] ikm = new byte[20];
AssertExtensions.Throws(
@@ -495,7 +566,7 @@ public void Rfc5869DeriveOutputLengthZero()
}
[Fact]
- public void Rfc5869DeriveOutputLengthLessThanZero()
+ public void DeriveOutputLengthLessThanZero()
{
byte[] ikm = new byte[20];
AssertExtensions.Throws(
@@ -528,7 +599,7 @@ protected override byte[] DeriveKey(HashAlgorithmName hash, byte[] ikm, int outp
}
[Fact]
- public void Rfc5869ExtractPrkTooLong()
+ public void ExtractPrkTooLong()
{
byte[] prk = new byte[24];
@@ -550,7 +621,7 @@ public void Rfc5869ExtractPrkTooLong()
}
[Fact]
- public void Rfc5869OkmMaxSizePlusOne()
+ public void OkmMaxSizePlusOne()
{
byte[] prk = new byte[20];
byte[] okm = new byte[20 * 255 + 1];
@@ -560,7 +631,7 @@ public void Rfc5869OkmMaxSizePlusOne()
}
[Fact]
- public void Rfc5869OkmMaxSizePotentiallyOverflowingValue()
+ public void OkmMaxSizePotentiallyOverflowingValue()
{
byte[] prk = new byte[20];
byte[] okm = new byte[8421505];
@@ -570,7 +641,7 @@ public void Rfc5869OkmMaxSizePotentiallyOverflowingValue()
}
[Fact]
- public void Rfc5869ExpandOutputLengthZero()
+ public void ExpandOutputLengthZero()
{
byte[] prk = new byte[20];
byte[] okm = new byte[0];
@@ -581,7 +652,7 @@ public void Rfc5869ExpandOutputLengthZero()
}
[Fact]
- public void Rfc5869DeriveKeySpanOkmMaxSizePlusOne()
+ public void DeriveKeySpanOkmMaxSizePlusOne()
{
byte[] ikm = new byte[20];
byte[] okm = new byte[20 * 255 + 1];
@@ -591,7 +662,7 @@ public void Rfc5869DeriveKeySpanOkmMaxSizePlusOne()
}
[Fact]
- public void Rfc5869DeriveKeySpanOkmPotentiallyOverflowingValue()
+ public void DeriveKeySpanOkmPotentiallyOverflowingValue()
{
byte[] ikm = new byte[20];
byte[] okm = new byte[8421505];
@@ -601,7 +672,7 @@ public void Rfc5869DeriveKeySpanOkmPotentiallyOverflowingValue()
}
[Fact]
- public void Rfc5869DeriveKeyOutputLengthZero()
+ public void DeriveKeyOutputLengthZero()
{
byte[] ikm = new byte[20];
byte[] okm = new byte[0];
@@ -616,7 +687,7 @@ public void Rfc5869DeriveKeyOutputLengthZero()
[InlineData(0, 10)] // Output +10 offset over ikm
[InlineData(10, 0)] // ikm +10 offset over output
[InlineData(10, 20)] // Both offset, output +10 over ikm
- public void Rfc5869ExtractOverlapsPrkOverKeyMaterial(int ikmOffset, int outputOffset)
+ public void ExtractOverlapsPrkOverKeyMaterial(int ikmOffset, int outputOffset)
{
ReadOnlySpan ikm = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b".HexToByteArray();
ReadOnlySpan salt = "000102030405060708090a0b0c".HexToByteArray();
@@ -637,7 +708,7 @@ public void Rfc5869ExtractOverlapsPrkOverKeyMaterial(int ikmOffset, int outputOf
[InlineData(0, 10)] // Output +10 offset over salt
[InlineData(10, 0)] // salt +10 offset over output
[InlineData(10, 20)] // Both offset, output +10 over salt
- public void Rfc5869ExtractOverlapsPrkOverSalt(int saltOffset, int outputOffset)
+ public void ExtractOverlapsPrkOverSalt(int saltOffset, int outputOffset)
{
ReadOnlySpan ikm = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b".HexToByteArray();
ReadOnlySpan salt = "000102030405060708090a0b0c".HexToByteArray();
@@ -658,7 +729,7 @@ public void Rfc5869ExtractOverlapsPrkOverSalt(int saltOffset, int outputOffset)
[InlineData(0, 10)] // Output +10 offset over info
[InlineData(10, 0)] // Info +10 offset over output
[InlineData(10, 20)] // Both offset, output +10 over info
- public void Rfc5869ExpandOverlapsOutputOverInfo(int infoOffset, int outputOffset)
+ public void ExpandOverlapsOutputOverInfo(int infoOffset, int outputOffset)
{
ReadOnlySpan info = (
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
@@ -686,7 +757,7 @@ public void Rfc5869ExpandOverlapsOutputOverInfo(int infoOffset, int outputOffset
[InlineData(0, 10)] // Output +10 offset over info
[InlineData(10, 0)] // Info +10 offset over output
[InlineData(10, 20)] // Both offset, output +10 over info
- public void Rfc5869ExpandOverlapsOutputOverInfoShortOkm(int infoOffset, int outputOffset)
+ public void ExpandOverlapsOutputOverInfoShortOkm(int infoOffset, int outputOffset)
{
ReadOnlySpan info = (
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
@@ -712,7 +783,7 @@ public void Rfc5869ExpandOverlapsOutputOverInfoShortOkm(int infoOffset, int outp
[InlineData(0, 10)] // Output +10 offset over prk
[InlineData(10, 0)] // Prk +10 offset over output
[InlineData(10, 20)] // Both offset, output +10 over prk
- public void Rfc5869ExpandOverlapsOutputOverPrk(int prkOffset, int outputOffset)
+ public void ExpandOverlapsOutputOverPrk(int prkOffset, int outputOffset)
{
ReadOnlySpan info = (
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmNameTests.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmNameTests.cs
index e4d78699bfdd1c..70d1056a9abf22 100644
--- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmNameTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmNameTests.cs
@@ -60,6 +60,9 @@ public static IEnumerable ValidInputs
yield return new object[] { "2.16.840.1.101.3.4.2.1", HashAlgorithmName.SHA256 };
yield return new object[] { "2.16.840.1.101.3.4.2.2", HashAlgorithmName.SHA384 };
yield return new object[] { "2.16.840.1.101.3.4.2.3", HashAlgorithmName.SHA512 };
+ yield return new object[] { "2.16.840.1.101.3.4.2.8", HashAlgorithmName.SHA3_256 };
+ yield return new object[] { "2.16.840.1.101.3.4.2.9", HashAlgorithmName.SHA3_384 };
+ yield return new object[] { "2.16.840.1.101.3.4.2.10", HashAlgorithmName.SHA3_512 };
}
}
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs
index 8890808c6a0cca..8443c222edaa6b 100644
--- a/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HashAlgorithmTestDriver.cs
@@ -10,8 +10,10 @@
namespace System.Security.Cryptography.Tests
{
- public abstract class HashAlgorithmTestDriver
+ public abstract class HashAlgorithmTestDriver where THashTrait : IHashTrait
{
+ public static bool IsSupported => THashTrait.IsSupported;
+ public static bool IsNotSupported => !IsSupported;
protected abstract HashAlgorithm Create();
protected abstract bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten);
protected abstract byte[] HashData(byte[] source);
@@ -191,19 +193,19 @@ private void VerifyTransformBlockComputeHashInteraction(byte[] block1, byte[] bl
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashData_ByteArray_Null()
{
AssertExtensions.Throws("source", () => HashData((byte[])null));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashData_BufferTooSmall()
{
AssertExtensions.Throws("destination", () => HashData(Span.Empty, default));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void VerifyObjectDisposedException()
{
HashAlgorithm hash = Create();
@@ -216,7 +218,7 @@ public void VerifyObjectDisposedException()
Assert.Throws(() => hash.TransformFinalBlock(Array.Empty(), 0, 0));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void VerifyHashNotYetFinalized()
{
using (HashAlgorithm hash = Create())
@@ -226,7 +228,7 @@ public void VerifyHashNotYetFinalized()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_ComputeHash()
{
using (HashAlgorithm hash = Create())
@@ -236,7 +238,7 @@ public void InvalidInput_ComputeHash()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_TransformBlock()
{
using (HashAlgorithm hash = Create())
@@ -248,7 +250,7 @@ public void InvalidInput_TransformBlock()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_TransformFinalBlock()
{
using (HashAlgorithm hash = Create())
@@ -404,20 +406,43 @@ protected async Task VerifyRepeatingAsync(string input, int repeatCount, string
}
}
- [Fact]
+ [ConditionalFact(nameof(IsNotSupported))]
+ public async Task HashData_NotSupported()
+ {
+ byte[] buffer = new byte[THashTrait.HashSizeInBytes];
+ Assert.Throws(() => HashData(Array.Empty()));
+ Assert.Throws(() => HashData(ReadOnlySpan.Empty));
+ Assert.Throws(() => HashData(ReadOnlySpan.Empty, buffer));
+ Assert.Throws(() => TryHashData(ReadOnlySpan.Empty, buffer, out _));
+
+ Assert.Throws(() => HashData(Stream.Null));
+ Assert.Throws(() => HashData(Stream.Null, buffer));
+ await Assert.ThrowsAsync(async () =>
+ await HashDataAsync(Stream.Null, default(CancellationToken)));
+ await Assert.ThrowsAsync(async () =>
+ await HashDataAsync(Stream.Null, buffer, default(CancellationToken)));
+ }
+
+ [ConditionalFact(nameof(IsNotSupported))]
+ public void Create_NotSupported()
+ {
+ Assert.Throws(() => Create());
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
public void HashData_Null_Stream_Throws()
{
AssertExtensions.Throws("source", () => HashData((Stream)null));
AssertExtensions.Throws("source", () => HashData((Stream)null, Span.Empty));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashData_ShortDestination_Throws()
{
AssertExtensions.Throws("destination", () => HashData(Stream.Null, Span.Empty));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashDataAsync_Null_Stream_Throws()
{
AssertExtensions.Throws(
@@ -429,7 +454,7 @@ public void HashDataAsync_Null_Stream_Throws()
() => HashDataAsync((Stream)null, Memory.Empty, cancellationToken: default));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashDataAsync_ShortDestination_Throws()
{
AssertExtensions.Throws(
@@ -437,7 +462,7 @@ public void HashDataAsync_ShortDestination_Throws()
() => HashDataAsync(Stream.Null, Memory.Empty, cancellationToken: default));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashDataAsync_Buffer_CancelledToken()
{
Memory buffer = new byte[512 / 8];
@@ -447,7 +472,7 @@ public void HashDataAsync_Buffer_CancelledToken()
AssertExtensions.FilledWith(0, buffer.Span);
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void HashDataAsync_Allocating_CancelledToken()
{
CancellationToken cancelledToken = new CancellationToken(canceled: true);
@@ -455,7 +480,7 @@ public void HashDataAsync_Allocating_CancelledToken()
Assert.True(waitable.IsCanceled, nameof(waitable.IsCanceled));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_Null()
{
using (HashAlgorithm hash = Create())
@@ -466,7 +491,7 @@ public void InvalidInput_Null()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_NegativeOffset()
{
using (HashAlgorithm hash = Create())
@@ -475,7 +500,7 @@ public void InvalidInput_NegativeOffset()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_NegativeCount()
{
using (HashAlgorithm hash = Create())
@@ -484,7 +509,7 @@ public void InvalidInput_NegativeCount()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_TooBigOffset()
{
using (HashAlgorithm hash = Create())
@@ -493,7 +518,7 @@ public void InvalidInput_TooBigOffset()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_TooBigCount()
{
byte[] nonEmpty = new byte[53];
@@ -507,7 +532,7 @@ public void InvalidInput_TooBigCount()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void BoundaryCondition_Count0()
{
byte[] nonEmpty = new byte[53];
@@ -533,7 +558,7 @@ public void BoundaryCondition_Count0()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void OffsetAndCountRespected()
{
byte[] dataA = { 1, 1, 2, 3, 5, 8 };
@@ -550,7 +575,7 @@ public void OffsetAndCountRespected()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void ComputeHash_TryComputeHash_HashSetExplicitlyByBoth()
{
using (HashAlgorithm hash = Create())
@@ -569,7 +594,7 @@ public void ComputeHash_TryComputeHash_HashSetExplicitlyByBoth()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void Dispose_TryComputeHash_ThrowsException()
{
HashAlgorithm hash = Create();
@@ -578,7 +603,7 @@ public void Dispose_TryComputeHash_ThrowsException()
Assert.Throws(() => hash.TryComputeHash(new byte[1], new byte[1], out int bytesWritten));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void Initialize_TransformBlock()
{
byte[] hashInput = new byte[] { 1, 2, 3, 4, 5 };
@@ -600,7 +625,7 @@ public void Initialize_TransformBlock()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void Initialize_TransformBlock_Unused()
{
byte[] hashInput = new byte[] { 1, 2, 3, 4, 5 };
@@ -621,7 +646,7 @@ public void Initialize_TransformBlock_Unused()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void Initialize_DoubleInitialize_Works()
{
byte[] hashInput = new byte[] { 1, 2, 3, 4, 5 };
@@ -645,4 +670,10 @@ public void Initialize_DoubleInitialize_Works()
}
}
}
+
+ public interface IHashTrait
+ {
+ static abstract bool IsSupported { get; }
+ static abstract int HashSizeInBytes { get; }
+ }
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HashDerivedTests.cs b/src/libraries/System.Security.Cryptography/tests/HashDerivedTests.cs
index 6734bca6bb5a53..1c58b8758eef7f 100644
--- a/src/libraries/System.Security.Cryptography/tests/HashDerivedTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HashDerivedTests.cs
@@ -11,28 +11,28 @@ public static class HashDerivedTests
public static void HashSize_SetForDerived_SHA1()
{
using DerivedSHA1 sha = new DerivedSHA1();
- Assert.Equal(160, sha.HashSize);
+ Assert.Equal(SHA1.HashSizeInBits, sha.HashSize);
}
[Fact]
public static void HashSize_SetForDerived_SHA256()
{
using DerivedSHA256 sha = new DerivedSHA256();
- Assert.Equal(256, sha.HashSize);
+ Assert.Equal(SHA256.HashSizeInBits, sha.HashSize);
}
[Fact]
public static void HashSize_SetForDerived_SHA384()
{
using DerivedSHA384 sha = new DerivedSHA384();
- Assert.Equal(384, sha.HashSize);
+ Assert.Equal(SHA384.HashSizeInBits, sha.HashSize);
}
[Fact]
public static void HashSize_SetForDerived_SHA512()
{
using DerivedSHA512 sha = new DerivedSHA512();
- Assert.Equal(512, sha.HashSize);
+ Assert.Equal(SHA512.HashSizeInBits, sha.HashSize);
}
[Fact]
@@ -40,7 +40,28 @@ public static void HashSize_SetForDerived_SHA512()
public static void HashSize_SetForDerived_MD5()
{
using DerivedMD5 sha = new DerivedMD5();
- Assert.Equal(128, sha.HashSize);
+ Assert.Equal(MD5.HashSizeInBits, sha.HashSize);
+ }
+
+ [Fact]
+ public static void HashSize_SetForDerived_SHA3_256()
+ {
+ using DerivedSHA3_256 sha = new DerivedSHA3_256();
+ Assert.Equal(SHA3_256.HashSizeInBits, sha.HashSize);
+ }
+
+ [Fact]
+ public static void HashSize_SetForDerived_SHA3_384()
+ {
+ using DerivedSHA3_384 sha = new DerivedSHA3_384();
+ Assert.Equal(SHA3_384.HashSizeInBits, sha.HashSize);
+ }
+
+ [Fact]
+ public static void HashSize_SetForDerived_SHA3_512()
+ {
+ using DerivedSHA3_512 sha = new DerivedSHA3_512();
+ Assert.Equal(SHA3_512.HashSizeInBits, sha.HashSize);
}
private class DerivedSHA1 : SHA1
@@ -71,14 +92,28 @@ private class DerivedSHA512 : SHA512
protected override void HashCore(byte[] array, int ibStart, int cbSize) => throw null;
}
- private class DerivedMD5 : MD5
+ private class DerivedSHA3_256 : SHA3_256
{
public override void Initialize() => throw null;
protected override byte[] HashFinal() => throw null;
protected override void HashCore(byte[] array, int ibStart, int cbSize) => throw null;
}
- private class DerivedHMACMD5 : HMACMD5
+ private class DerivedSHA3_384 : SHA3_384
+ {
+ public override void Initialize() => throw null;
+ protected override byte[] HashFinal() => throw null;
+ protected override void HashCore(byte[] array, int ibStart, int cbSize) => throw null;
+ }
+
+ private class DerivedSHA3_512 : SHA3_512
+ {
+ public override void Initialize() => throw null;
+ protected override byte[] HashFinal() => throw null;
+ protected override void HashCore(byte[] array, int ibStart, int cbSize) => throw null;
+ }
+
+ private class DerivedMD5 : MD5
{
public override void Initialize() => throw null;
protected override byte[] HashFinal() => throw null;
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs
index d657f9627b2942..2adf417aec8458 100644
--- a/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HmacMD5Tests.cs
@@ -10,8 +10,14 @@
namespace System.Security.Cryptography.Tests
{
[SkipOnPlatform(TestPlatforms.Browser, "Not supported on Browser")]
- public class HmacMD5Tests : Rfc2202HmacTests
+ public class HmacMD5Tests : Rfc2202HmacTests
{
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => true;
+ public static int HashSizeInBytes => HMACSHA1.HashSizeInBytes;
+ }
+
private static readonly byte[][] s_testKeys2202 =
{
null,
@@ -45,6 +51,7 @@ public HmacMD5Tests()
protected override int MacSize => HMACMD5.HashSizeInBytes;
protected override HMAC Create() => new HMACMD5();
+ protected override HMAC Create(byte[] key) => new HMACMD5(key);
protected override HashAlgorithm CreateHashAlgorithm() => MD5.Create();
protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
HMACMD5.HashData(key, source);
@@ -218,5 +225,12 @@ await VerifyRepeatingAsync(
hexKey: "000102030405060708090A0B0C0D0E0F",
output: "C91E40247251F39BDFE6A7B72A5857F9");
}
+
+ [Fact]
+ public void HmacMD5_HashSizes()
+ {
+ Assert.Equal(128, HMACMD5.HashSizeInBits);
+ Assert.Equal(16, HMACMD5.HashSizeInBytes);
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs
index 9b5aa3effca47b..6b3b1eed43d8cf 100644
--- a/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha1Tests.cs
@@ -9,8 +9,14 @@
namespace System.Security.Cryptography.Tests
{
- public class HmacSha1Tests : Rfc2202HmacTests
+ public class HmacSha1Tests : Rfc2202HmacTests
{
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => true;
+ public static int HashSizeInBytes => HMACSHA1.HashSizeInBytes;
+ }
+
private static readonly byte[][] s_testKeys2202 =
{
null,
@@ -44,6 +50,7 @@ public HmacSha1Tests()
protected override int MacSize => HMACSHA1.HashSizeInBytes;
protected override HMAC Create() => new HMACSHA1();
+ protected override HMAC Create(byte[] key) => new HMACSHA1(key);
protected override HashAlgorithm CreateHashAlgorithm() => SHA1.Create();
protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
HMACSHA1.HashData(key, source);
@@ -241,5 +248,12 @@ await VerifyRepeatingAsync(
hexKey: "000102030405060708090A0B0C0D0E0F",
output: "5433122F77BCF8A4D9B874B4149823EF5B7C207E");
}
+
+ [Fact]
+ public void HmacSha1_HashSizes()
+ {
+ Assert.Equal(160, HMACSHA1.HashSizeInBits);
+ Assert.Equal(20, HMACSHA1.HashSizeInBytes);
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs
index dea079824ff1fc..6abef3de5a2a2f 100644
--- a/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha256Tests.cs
@@ -9,12 +9,19 @@
namespace System.Security.Cryptography.Tests
{
- public class HmacSha256Tests : Rfc4231HmacTests
+ public class HmacSha256Tests : Rfc4231HmacTests
{
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => true;
+ public static int HashSizeInBytes => HMACSHA256.HashSizeInBytes;
+ }
+
protected override int BlockSize => 64;
protected override int MacSize => HMACSHA256.HashSizeInBytes;
protected override HMAC Create() => new HMACSHA256();
+ protected override HMAC Create(byte[] key) => new HMACSHA256(key);
protected override HashAlgorithm CreateHashAlgorithm() => SHA256.Create();
protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
HMACSHA256.HashData(key, source);
@@ -205,5 +212,12 @@ await VerifyRepeatingAsync(
hexKey: "000102030405060708090A0B0C0D0E0F",
output: "07EFF8B326B7798C9CCFCBDBE579489AC785A7995A04618B1A2813C26744777D");
}
+
+ [Fact]
+ public void HmacSha256_HashSizes()
+ {
+ Assert.Equal(256, HMACSHA256.HashSizeInBits);
+ Assert.Equal(32, HMACSHA256.HashSizeInBytes);
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs
index d026442de4bb4a..d17b08a69925ee 100644
--- a/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha384Tests.cs
@@ -9,12 +9,19 @@
namespace System.Security.Cryptography.Tests
{
- public class HmacSha384Tests : Rfc4231HmacTests
+ public class HmacSha384Tests : Rfc4231HmacTests
{
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => true;
+ public static int HashSizeInBytes => HMACSHA384.HashSizeInBytes;
+ }
+
protected override int BlockSize => 128;
protected override int MacSize => HMACSHA384.HashSizeInBytes;
protected override HMAC Create() => new HMACSHA384();
+ protected override HMAC Create(byte[] key) => new HMACSHA384(key);
protected override HashAlgorithm CreateHashAlgorithm() => SHA384.Create();
protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
HMACSHA384.HashData(key, source);
@@ -218,5 +225,12 @@ await VerifyRepeatingAsync(
hexKey: "000102030405060708090A0B0C0D0E0F",
output: "6A0FDC1C54C664AD91C7C157D2670C5D44E4D44EBAD2359A0206974C7088B1A867F76971E6C240C33B33A66BA295BB56");
}
+
+ [Fact]
+ public void HmacSha384_HashSizes()
+ {
+ Assert.Equal(384, HMACSHA384.HashSizeInBits);
+ Assert.Equal(48, HMACSHA384.HashSizeInBytes);
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha3_256Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha3_256Tests.cs
new file mode 100644
index 00000000000000..fb5b540ac506d0
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha3_256Tests.cs
@@ -0,0 +1,233 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Tests
+{
+ public class HmacSha3_256Tests : HmacTests
+ {
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => HMACSHA3_256.IsSupported;
+ public static int HashSizeInBytes => HMACSHA3_256.HashSizeInBytes;
+ }
+
+ protected override int BlockSize => 136;
+ protected override int MacSize => HMACSHA3_256.HashSizeInBytes;
+
+ protected override HMAC Create() => new HMACSHA3_256();
+ protected override HMAC Create(byte[] key) => new HMACSHA3_256(key);
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA3_256.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA3_256.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source) =>
+ HMACSHA3_256.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination) =>
+ HMACSHA3_256.HashData(key, source, destination);
+
+ protected override bool TryHashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) =>
+ HMACSHA3_256.TryHashData(key, source, destination, out written);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) =>
+ HMACSHA3_256.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(byte[] key, Stream source) =>
+ HMACSHA3_256.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) =>
+ HMACSHA3_256.HashData(key, source, destination);
+
+ protected override ValueTask HashDataOneShotAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken) => HMACSHA3_256.HashDataAsync(key, source, destination, cancellationToken);
+
+ protected override ValueTask HashDataOneShotAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ CancellationToken cancellationToken) => HMACSHA3_256.HashDataAsync(key, source, cancellationToken);
+
+ protected override ValueTask HashDataOneShotAsync(
+ byte[] key,
+ Stream source,
+ CancellationToken cancellationToken) => HMACSHA3_256.HashDataAsync(key, source, cancellationToken);
+
+ private static readonly byte[][] s_testKeys = new byte[][]
+ {
+ // From: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-256.pdf
+ null,
+ ByteUtils.HexToByteArray("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" +
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
+ "8081828384858687"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" +
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
+ "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" +
+ "a0a1a2a3a4a5a6a7"),
+ ByteUtils.HexToByteArray("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
+ };
+
+ private static readonly byte[][] s_testData = new byte[][]
+ {
+ null,
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3e626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e2c2077697468207472756e636174656420746167"),
+ };
+
+ private static readonly byte[][] s_testMacs = new byte[][]
+ {
+ null,
+ ByteUtils.HexToByteArray("4fe8e202c4f058e8dddc23d8c34e467343e23555e24fc2f025d598f558f67205"),
+ ByteUtils.HexToByteArray("68b94e2e538a9be4103bebb5aa016d47961d4d1aa906061313b557f8af2c3faa"),
+ ByteUtils.HexToByteArray("9bcf2c238e235c3ce88404e813bd2f3a97185ac6f238c63d6229a00b07974258"),
+ ByteUtils.HexToByteArray("c8dc7148d8c1423aa549105dafdf9cad"), // Truncated test case.
+ };
+
+
+ public HmacSha3_256Tests() : base(s_testKeys, s_testData, s_testMacs)
+ {
+ }
+
+ [ConditionalTheory(nameof(IsSupported))]
+ [MemberData(nameof(TestCaseIds))]
+ public void HmacSha3_256_VerifyTestCases(int caseId)
+ {
+ VerifyHmac(caseId, s_testMacs[caseId]);
+ }
+
+ public static IEnumerable TestCaseIds
+ {
+ get
+ {
+ for (int i = 1; i < s_testKeys.Length; i++)
+ {
+ yield return new object[] { i };
+ }
+ }
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_256_Rfc2104_2()
+ {
+ VerifyHmacRfc2104_2();
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_256_ThrowsArgumentNullForNullConstructorKey()
+ {
+ AssertExtensions.Throws("key", () => new HMACSHA3_256(null));
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_256_EmptyKey()
+ {
+ VerifyRepeating(
+ input: "Crypto is fun!",
+ 1,
+ hexKey: "",
+ output: "c49c24ae6dce7e90d5e2853ad9e647d89ac3dd04eb71aa0912ab4b4b1068ba6a");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_256_Stream_MultipleOf4096()
+ {
+ // Verfied with:
+ // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha3-256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "0102030405060708",
+ 1024,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "F09DD1B814BF4A576FF8AEAFF69509E3093895426F441A428953221F3CB9E421");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_256_Stream_NotMultipleOf4096()
+ {
+ // Verfied with:
+ // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha3-256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "0102030405060708",
+ 1025,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "F1DB96FF2B53CBA0338FF519BFA10153731DB48A63C26EB66294895B220F72B5");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_256_Stream_Empty()
+ {
+ // Verfied with:
+ // echo -n "" | openssl sha3-256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "",
+ 0,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "72756291FF30F3E916BEF99EC9CF5938B25D90BBCAC1BDB1E1E6564E8EC6FDA5");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_256_Stream_MultipleOf4096_Async()
+ {
+ // Verfied with:
+ // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha3-256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "0102030405060708",
+ 1024,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "F09DD1B814BF4A576FF8AEAFF69509E3093895426F441A428953221F3CB9E421");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_256_Stream_NotMultipleOf4096_Async()
+ {
+ // Verfied with:
+ // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha3-256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "0102030405060708",
+ 1025,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "F1DB96FF2B53CBA0338FF519BFA10153731DB48A63C26EB66294895B220F72B5");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_256_Stream_Empty_Async()
+ {
+ // Verfied with:
+ // echo -n "" | openssl sha3-256 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "",
+ 0,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "72756291FF30F3E916BEF99EC9CF5938B25D90BBCAC1BDB1E1E6564E8EC6FDA5");
+ }
+
+ [Fact]
+ public void HmacSha3_256_HashSizes()
+ {
+ Assert.Equal(256, HMACSHA3_256.HashSizeInBits);
+ Assert.Equal(32, HMACSHA3_256.HashSizeInBytes);
+ }
+
+ [Fact]
+ public void HmacSha3_256_IsSupported_AgreesWithPlatformVersion()
+ {
+ Assert.Equal(PlatformDetection.SupportsSha3, HMACSHA3_256.IsSupported);
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha3_384Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha3_384Tests.cs
new file mode 100644
index 00000000000000..7dab4a444f5adb
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha3_384Tests.cs
@@ -0,0 +1,241 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Tests
+{
+ public class HmacSha3_384Tests : HmacTests
+ {
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => HMACSHA3_384.IsSupported;
+ public static int HashSizeInBytes => HMACSHA3_384.HashSizeInBytes;
+ }
+
+ protected override int BlockSize => 104;
+ protected override int MacSize => HMACSHA3_384.HashSizeInBytes;
+
+ protected override HMAC Create() => new HMACSHA3_384();
+ protected override HMAC Create(byte[] key) => new HMACSHA3_384(key);
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA3_384.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA3_384.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source) =>
+ HMACSHA3_384.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination) =>
+ HMACSHA3_384.HashData(key, source, destination);
+
+ protected override bool TryHashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) =>
+ HMACSHA3_384.TryHashData(key, source, destination, out written);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) =>
+ HMACSHA3_384.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(byte[] key, Stream source) =>
+ HMACSHA3_384.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) =>
+ HMACSHA3_384.HashData(key, source, destination);
+
+ protected override ValueTask HashDataOneShotAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken) => HMACSHA3_384.HashDataAsync(key, source, destination, cancellationToken);
+
+ protected override ValueTask HashDataOneShotAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ CancellationToken cancellationToken) => HMACSHA3_384.HashDataAsync(key, source, cancellationToken);
+
+ protected override ValueTask HashDataOneShotAsync(
+ byte[] key,
+ Stream source,
+ CancellationToken cancellationToken) => HMACSHA3_384.HashDataAsync(key, source, cancellationToken);
+
+ private static readonly byte[][] s_testKeys = new byte[][]
+ {
+ // From: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-384.pdf
+ null,
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f1011121314151617" +
+ "18191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" +
+ "6061626364656667"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" +
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
+ "808182838485868788898a8b8c8d8e8f9091929394959697"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f"),
+ };
+
+ private static readonly byte[][] s_testData = new byte[][]
+ {
+ null,
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3e626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e2c2077697468207472756e636174656420746167"),
+ };
+
+ private static readonly byte[][] s_testMacs = new byte[][]
+ {
+ null,
+ ByteUtils.HexToByteArray(
+ "d588a3c51f3f2d906e8298c1199aa8ff6296218127f6b38a" +
+ "90b6afe2c5617725bc99987f79b22a557b6520db710b7f42"),
+ ByteUtils.HexToByteArray(
+ "a27d24b592e8c8cbf6d4ce6fc5bf62d8fc98bf2d486640d9" +
+ "eb8099e24047837f5f3bffbe92dcce90b4ed5b1e7e44fa90"),
+ ByteUtils.HexToByteArray(
+ "e5ae4c739f455279368ebf36d4f5354c95aa184c899d3870" +
+ "e460ebc288ef1f9470053f73f7c6da2a71bcaec38ce7d6ac"),
+ ByteUtils.HexToByteArray("25f4bf53606e91af79d24a4bb1fd6aecd44414a30c8ebb0a"), // Truncated
+ };
+
+
+ public HmacSha3_384Tests() : base(s_testKeys, s_testData, s_testMacs)
+ {
+ }
+
+ [ConditionalTheory(nameof(IsSupported))]
+ [MemberData(nameof(TestCaseIds))]
+ public void HmacSha3_384_VerifyTestCases(int caseId)
+ {
+ VerifyHmac(caseId, s_testMacs[caseId]);
+ }
+
+ public static IEnumerable TestCaseIds
+ {
+ get
+ {
+ for (int i = 1; i < s_testKeys.Length; i++)
+ {
+ yield return new object[] { i };
+ }
+ }
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_384_Rfc2104_2()
+ {
+ VerifyHmacRfc2104_2();
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_384_ThrowsArgumentNullForNullConstructorKey()
+ {
+ AssertExtensions.Throws("key", () => new HMACSHA3_384(null));
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_384_EmptyKey()
+ {
+ VerifyRepeating(
+ input: "Crypto is fun!",
+ 1,
+ hexKey: "",
+ output: "16C079F7D15505E9E541421E63C432A063F39C1E3E953E6DC7B8A81FE5620AFFA430C3E6BE6A0F605755C7C5EE4E347E");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_384_Stream_MultipleOf4096()
+ {
+ // Verfied with:
+ // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha3-384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "0102030405060708",
+ 1024,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "17D03C8153AF1719F5829C8CBF328D4200900ED1AB038A399B4F256A490BD4D2AB311C71D2ED0C20ABA96E57768CCA6E");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_384_Stream_NotMultipleOf4096()
+ {
+ // Verfied with:
+ // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha3-384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "0102030405060708",
+ 1025,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "5360719A6A9DFEB1143C2866A7F72EA29404C3DBF37F244A0497F400DA126B2728118863454288F26E3796BE72238958");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_384_Stream_Empty()
+ {
+ // Verfied with:
+ // echo -n "" | openssl sha3-384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "",
+ 0,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "5B0196779BDAF859E99869A63C9FDF3821E9100A370B5E9B88F76B9DA87410F99846E7DBB4F8A69368C5C5A834B3128D");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_384_Stream_MultipleOf4096_Async()
+ {
+ // Verfied with:
+ // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha3-384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "0102030405060708",
+ 1024,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "17D03C8153AF1719F5829C8CBF328D4200900ED1AB038A399B4F256A490BD4D2AB311C71D2ED0C20ABA96E57768CCA6E");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_384_Stream_NotMultipleOf4096_Async()
+ {
+ // Verfied with:
+ // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha3-384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "0102030405060708",
+ 1025,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "5360719A6A9DFEB1143C2866A7F72EA29404C3DBF37F244A0497F400DA126B2728118863454288F26E3796BE72238958");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_384_Stream_Empty_Async()
+ {
+ // Verfied with:
+ // echo -n "" | openssl sha3-384 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "",
+ 0,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "5B0196779BDAF859E99869A63C9FDF3821E9100A370B5E9B88F76B9DA87410F99846E7DBB4F8A69368C5C5A834B3128D");
+ }
+
+ [Fact]
+ public void HmacSha3_384_HashSizes()
+ {
+ Assert.Equal(384, HMACSHA3_384.HashSizeInBits);
+ Assert.Equal(48, HMACSHA3_384.HashSizeInBytes);
+ }
+
+ [Fact]
+ public void HmacSha3_384_IsSupported_AgreesWithPlatformVersion()
+ {
+ Assert.Equal(PlatformDetection.SupportsSha3, HMACSHA3_384.IsSupported);
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha3_512Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha3_512Tests.cs
new file mode 100644
index 00000000000000..3359ba4e335680
--- /dev/null
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha3_512Tests.cs
@@ -0,0 +1,247 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Test.Cryptography;
+using Xunit;
+
+namespace System.Security.Cryptography.Tests
+{
+ public class HmacSha3_512Tests : HmacTests
+ {
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => HMACSHA3_512.IsSupported;
+ public static int HashSizeInBytes => HMACSHA3_512.HashSizeInBytes;
+ }
+
+ protected override int BlockSize => 72;
+ protected override int MacSize => HMACSHA3_512.HashSizeInBytes;
+
+ protected override HMAC Create() => new HMACSHA3_512();
+ protected override HMAC Create(byte[] key) => new HMACSHA3_512(key);
+ protected override HashAlgorithm CreateHashAlgorithm() => SHA3_512.Create();
+ protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
+ HMACSHA3_512.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source) =>
+ HMACSHA3_512.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination) =>
+ HMACSHA3_512.HashData(key, source, destination);
+
+ protected override bool TryHashDataOneShot(ReadOnlySpan key, ReadOnlySpan source, Span destination, out int written) =>
+ HMACSHA3_512.TryHashData(key, source, destination, out written);
+
+ protected override byte[] HashDataOneShot(ReadOnlySpan key, Stream source) =>
+ HMACSHA3_512.HashData(key, source);
+
+ protected override byte[] HashDataOneShot(byte[] key, Stream source) =>
+ HMACSHA3_512.HashData(key, source);
+
+ protected override int HashDataOneShot(ReadOnlySpan key, Stream source, Span destination) =>
+ HMACSHA3_512.HashData(key, source, destination);
+
+ protected override ValueTask HashDataOneShotAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ Memory destination,
+ CancellationToken cancellationToken) => HMACSHA3_512.HashDataAsync(key, source, destination, cancellationToken);
+
+ protected override ValueTask HashDataOneShotAsync(
+ ReadOnlyMemory key,
+ Stream source,
+ CancellationToken cancellationToken) => HMACSHA3_512.HashDataAsync(key, source, cancellationToken);
+
+ protected override ValueTask HashDataOneShotAsync(
+ byte[] key,
+ Stream source,
+ CancellationToken cancellationToken) => HMACSHA3_512.HashDataAsync(key, source, cancellationToken);
+
+ private static readonly byte[][] s_testKeys = new byte[][]
+ {
+ // From: https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-512.pdf
+ null,
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+ "4041424344454647"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" +
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
+ "8081828384858687"),
+ ByteUtils.HexToByteArray(
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"),
+ };
+
+ private static readonly byte[][] s_testData = new byte[][]
+ {
+ null,
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3d626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3e626c6f636b6c656e"),
+ ByteUtils.HexToByteArray("53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e2c2077697468207472756e636174656420746167"),
+ };
+
+ private static readonly byte[][] s_testMacs = new byte[][]
+ {
+ null,
+ ByteUtils.HexToByteArray(
+ "4efd629d6c71bf86162658f29943b1c308ce27cdfa6db0d9c3ce81763f9cbce5" +
+ "f7ebe9868031db1a8f8eb7b6b95e5c5e3f657a8996c86a2f6527e307f0213196"),
+ ByteUtils.HexToByteArray(
+ "544e257ea2a3e5ea19a590e6a24b724ce6327757723fe2751b75bf007d80f6b3" +
+ "60744bf1b7a88ea585f9765b47911976d3191cf83c039f5ffab0d29cc9d9b6da"),
+ ByteUtils.HexToByteArray(
+ "5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d4" +
+ "6b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915"),
+ ByteUtils.HexToByteArray("7bb06d859257b25ce73ca700df34c5cbef5c898bac91029e0b27975d4e526a08"), // Truncated
+ };
+
+
+ public HmacSha3_512Tests() : base(s_testKeys, s_testData, s_testMacs)
+ {
+ }
+
+ [ConditionalTheory(nameof(IsSupported))]
+ [MemberData(nameof(TestCaseIds))]
+ public void HmacSha3_512_VerifyTestCases(int caseId)
+ {
+ VerifyHmac(caseId, s_testMacs[caseId]);
+ }
+
+ public static IEnumerable TestCaseIds
+ {
+ get
+ {
+ for (int i = 1; i < s_testKeys.Length; i++)
+ {
+ yield return new object[] { i };
+ }
+ }
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_512_Rfc2104_2()
+ {
+ VerifyHmacRfc2104_2();
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_512_ThrowsArgumentNullForNullConstructorKey()
+ {
+ AssertExtensions.Throws("key", () => new HMACSHA3_512(null));
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_512_EmptyKey()
+ {
+ VerifyRepeating(
+ input: "Crypto is fun!",
+ 1,
+ hexKey: "",
+ output: "8F1658BB962C7048A50BEA174FA7697596F3F5F127228EEA64589DFFB0C1A07C" +
+ "98792648C97886B3DD9E63AB962581C67DA5EE04F2B15263555B1796782CB556");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_512_Stream_MultipleOf4096()
+ {
+ // Verfied with:
+ // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha3-512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "0102030405060708",
+ 1024,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "43A635D00606EFB4797B0B50B3C2CCAACDC8C2DA38D1369EA49CDD93EDE27824" +
+ "317D9014C429DB18E5A6BFD811F7B484922471085F17ED31F6A7EB4E07BFFA97");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_512_Stream_NotMultipleOf4096()
+ {
+ // Verfied with:
+ // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha3-512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "0102030405060708",
+ 1025,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "90D378A7546A66804E6C0ADF3203D3836244FD8CF628294E7F3AD95539EDF6D9" +
+ "E86DECE850D50DE76386CB293FA832778C7D6607A4F00AD666DA3EFFD6143E70");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public void HmacSha3_512_Stream_Empty()
+ {
+ // Verfied with:
+ // echo -n "" | openssl sha3-512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ VerifyRepeating(
+ input: "",
+ 0,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "908D1BE1A2CC5CC4B8C62E98D09AB6E967529FCB24F4177CB94CB072F5968D01" +
+ "CA58633748DC80D4615E3D21228BB3A5F535FA1CB963DF463CC28ABAF1A9B2D1");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_512_Stream_MultipleOf4096_Async()
+ {
+ // Verfied with:
+ // for _ in {1..1024}; do echo -n "0102030405060708"; done | openssl sha3-512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "0102030405060708",
+ 1024,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "43A635D00606EFB4797B0B50B3C2CCAACDC8C2DA38D1369EA49CDD93EDE27824" +
+ "317D9014C429DB18E5A6BFD811F7B484922471085F17ED31F6A7EB4E07BFFA97");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_512_Stream_NotMultipleOf4096_Async()
+ {
+ // Verfied with:
+ // for _ in {1..1025}; do echo -n "0102030405060708"; done | openssl sha3-512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "0102030405060708",
+ 1025,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "90D378A7546A66804E6C0ADF3203D3836244FD8CF628294E7F3AD95539EDF6D9" +
+ "E86DECE850D50DE76386CB293FA832778C7D6607A4F00AD666DA3EFFD6143E70");
+ }
+
+ [ConditionalFact(nameof(IsSupported))]
+ public async Task HmacSha3_512_Stream_Empty_Async()
+ {
+ // Verfied with:
+ // echo -n "" | openssl sha3-512 -hex -mac HMAC -macopt hexkey:000102030405060708090A0B0C0D0E0F
+ await VerifyRepeatingAsync(
+ input: "",
+ 0,
+ hexKey: "000102030405060708090A0B0C0D0E0F",
+ output: "908D1BE1A2CC5CC4B8C62E98D09AB6E967529FCB24F4177CB94CB072F5968D01" +
+ "CA58633748DC80D4615E3D21228BB3A5F535FA1CB963DF463CC28ABAF1A9B2D1");
+ }
+
+ [Fact]
+ public void HmacSha3_256_HashSizes()
+ {
+ Assert.Equal(512, HMACSHA3_512.HashSizeInBits);
+ Assert.Equal(64, HMACSHA3_512.HashSizeInBytes);
+ }
+
+ [Fact]
+ public void HmacSha3_512_IsSupported_AgreesWithPlatformVersion()
+ {
+ Assert.Equal(PlatformDetection.SupportsSha3, HMACSHA3_512.IsSupported);
+ }
+ }
+}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs b/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs
index 44aec88b8e1e2d..3568b40353af57 100644
--- a/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HmacSha512Tests.cs
@@ -9,12 +9,19 @@
namespace System.Security.Cryptography.Tests
{
- public class HmacSha512Tests : Rfc4231HmacTests
+ public class HmacSha512Tests : Rfc4231HmacTests
{
+ public sealed class Traits : IHmacTrait
+ {
+ public static bool IsSupported => true;
+ public static int HashSizeInBytes => HMACSHA512.HashSizeInBytes;
+ }
+
protected override int BlockSize => 128;
protected override int MacSize => HMACSHA512.HashSizeInBytes;
protected override HMAC Create() => new HMACSHA512();
+ protected override HMAC Create(byte[] key) => new HMACSHA512(key);
protected override HashAlgorithm CreateHashAlgorithm() => SHA512.Create();
protected override byte[] HashDataOneShot(byte[] key, byte[] source) =>
HMACSHA512.HashData(key, source);
@@ -218,5 +225,12 @@ await VerifyRepeatingAsync(
hexKey: "000102030405060708090A0B0C0D0E0F",
output: "2FEC800CA276C44985A35AEC92067E5E53A1BB80A6FDAB1D9C97D54068118F30AD4C33717466D372EA00BBF126E5B79C6F7143DD36C31F72028330E92AE3A359");
}
+
+ [Fact]
+ public void HmacSha512_HashSizes()
+ {
+ Assert.Equal(512, HMACSHA512.HashSizeInBits);
+ Assert.Equal(64, HMACSHA512.HashSizeInBytes);
+ }
}
}
diff --git a/src/libraries/System.Security.Cryptography/tests/HmacTests.cs b/src/libraries/System.Security.Cryptography/tests/HmacTests.cs
index 436f407c8b81b2..c6bd7ee994f3f5 100644
--- a/src/libraries/System.Security.Cryptography/tests/HmacTests.cs
+++ b/src/libraries/System.Security.Cryptography/tests/HmacTests.cs
@@ -9,8 +9,11 @@
namespace System.Security.Cryptography.Tests
{
- public abstract class HmacTests
+ public abstract class HmacTests where THmacTrait : IHmacTrait
{
+ public static bool IsSupported => THmacTrait.IsSupported;
+ public static bool IsNotSupported => !IsSupported;
+
// RFC2202 defines the test vectors for HMACMD5 and HMACSHA1
// RFC4231 defines the test vectors for HMACSHA{224,256,384,512}
// They share the same datasets for cases 1-5, but cases 6 and 7 differ.
@@ -26,6 +29,7 @@ protected HmacTests(byte[][] testKeys, byte[][] testData, byte[][] testMacs)
}
protected abstract HMAC Create();
+ protected abstract HMAC Create(byte[] key);
protected abstract HashAlgorithm CreateHashAlgorithm();
protected abstract byte[] HashDataOneShot(byte[] key, byte[] source);
@@ -254,7 +258,7 @@ protected void VerifyHmacRfc2104_2()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_Null()
{
using (HMAC hash = Create())
@@ -265,7 +269,7 @@ public void InvalidInput_Null()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_NegativeOffset()
{
using (HMAC hash = Create())
@@ -274,7 +278,7 @@ public void InvalidInput_NegativeOffset()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_NegativeCount()
{
using (HMAC hash = Create())
@@ -283,7 +287,7 @@ public void InvalidInput_NegativeCount()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_TooBigOffset()
{
using (HMAC hash = Create())
@@ -292,7 +296,7 @@ public void InvalidInput_TooBigOffset()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidInput_TooBigCount()
{
byte[] nonEmpty = new byte[53];
@@ -306,7 +310,7 @@ public void InvalidInput_TooBigCount()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void BoundaryCondition_Count0()
{
byte[] nonEmpty = new byte[53];
@@ -332,7 +336,7 @@ public void BoundaryCondition_Count0()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void OffsetAndCountRespected()
{
byte[] dataA = { 1, 1, 2, 3, 5, 8 };
@@ -349,7 +353,7 @@ public void OffsetAndCountRespected()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void InvalidKey_ThrowArgumentNullException()
{
using (HMAC hash = Create())
@@ -358,21 +362,21 @@ public void InvalidKey_ThrowArgumentNullException()
}
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void OneShot_NullKey_ArgumentNullException()
{
AssertExtensions.Throws("key", () =>
HashDataOneShot(key: (byte[])null, source: Array.Empty()));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void OneShot_NullSource_ArgumentNullException()
{
AssertExtensions.Throws("source", () =>
HashDataOneShot(key: Array.Empty(), source: (byte[])null));
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void OneShot_ExistingBuffer_TooSmall()
{
byte[] buffer = new byte[MacSize - 1];
@@ -385,7 +389,7 @@ public void OneShot_ExistingBuffer_TooSmall()
AssertExtensions.FilledWith(0, buffer);
}
- [Fact]
+ [ConditionalFact(nameof(IsSupported))]
public void OneShot_TryExistingBuffer_TooSmall()
{
byte[] buffer = new byte[MacSize - 1];
@@ -397,10 +401,10 @@ public void OneShot_TryExistingBuffer_TooSmall()
AssertExtensions.FilledWith