Skip to content

Commit 125b216

Browse files
authored
Add support for SHA-3
This adds API to interact with the SHA-3 algorithm to the framework. Like all other cryptographic algorithms in .NET, this only functions on OSes where the underlying system exposes the algorithm.
1 parent ac5febd commit 125b216

File tree

103 files changed

+6462
-450
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+6462
-450
lines changed

src/libraries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Evp.DigestAlgs.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,33 @@ internal static IntPtr EvpSha512() =>
4747

4848
internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId) => hashAlgorithmId switch
4949
{
50-
nameof(HashAlgorithmName.SHA1) => EvpSha1(),
51-
nameof(HashAlgorithmName.SHA256) => EvpSha256(),
52-
nameof(HashAlgorithmName.SHA384) => EvpSha384(),
53-
nameof(HashAlgorithmName.SHA512) => EvpSha512(),
54-
nameof(HashAlgorithmName.MD5) => EvpMd5(),
50+
HashAlgorithmNames.SHA1 => EvpSha1(),
51+
HashAlgorithmNames.SHA256 => EvpSha256(),
52+
HashAlgorithmNames.SHA384 => EvpSha384(),
53+
HashAlgorithmNames.SHA512 => EvpSha512(),
54+
HashAlgorithmNames.MD5 => EvpMd5(),
55+
HashAlgorithmNames.SHA3_256 or HashAlgorithmNames.SHA3_384 or HashAlgorithmNames.SHA3_512 =>
56+
throw new PlatformNotSupportedException(),
5557
_ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId))
5658
};
59+
60+
internal static bool HashAlgorithmSupported(string hashAlgorithmId)
61+
{
62+
switch (hashAlgorithmId)
63+
{
64+
case HashAlgorithmNames.SHA1:
65+
case HashAlgorithmNames.SHA256:
66+
case HashAlgorithmNames.SHA384:
67+
case HashAlgorithmNames.SHA512:
68+
case HashAlgorithmNames.MD5:
69+
return true;
70+
case HashAlgorithmNames.SHA3_256:
71+
case HashAlgorithmNames.SHA3_384:
72+
case HashAlgorithmNames.SHA3_512:
73+
return false;
74+
default:
75+
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
76+
}
77+
}
5778
}
5879
}

src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs

Lines changed: 100 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,45 +14,128 @@ internal static partial class Crypto
1414
private static volatile IntPtr s_evpSha256;
1515
private static volatile IntPtr s_evpSha384;
1616
private static volatile IntPtr s_evpSha512;
17+
private static volatile IntPtr s_evpSha3_256;
18+
private static volatile IntPtr s_evpSha3_384;
19+
private static volatile IntPtr s_evpSha3_512;
20+
private static volatile bool s_evpSha3_256Cached;
21+
private static volatile bool s_evpSha3_384Cached;
22+
private static volatile bool s_evpSha3_512Cached;
1723

1824
[LibraryImport(Libraries.CryptoNative)]
1925
private static partial IntPtr CryptoNative_EvpMd5();
2026

21-
internal static IntPtr EvpMd5() =>
27+
private static IntPtr EvpMd5() =>
2228
s_evpMd5 != IntPtr.Zero ? s_evpMd5 : (s_evpMd5 = CryptoNative_EvpMd5());
2329

2430
[LibraryImport(Libraries.CryptoNative)]
25-
internal static partial IntPtr CryptoNative_EvpSha1();
31+
private static partial IntPtr CryptoNative_EvpSha1();
2632

27-
internal static IntPtr EvpSha1() =>
33+
private static IntPtr EvpSha1() =>
2834
s_evpSha1 != IntPtr.Zero ? s_evpSha1 : (s_evpSha1 = CryptoNative_EvpSha1());
2935

3036
[LibraryImport(Libraries.CryptoNative)]
31-
internal static partial IntPtr CryptoNative_EvpSha256();
37+
private static partial IntPtr CryptoNative_EvpSha256();
3238

33-
internal static IntPtr EvpSha256() =>
39+
private static IntPtr EvpSha256() =>
3440
s_evpSha256 != IntPtr.Zero ? s_evpSha256 : (s_evpSha256 = CryptoNative_EvpSha256());
3541

3642
[LibraryImport(Libraries.CryptoNative)]
37-
internal static partial IntPtr CryptoNative_EvpSha384();
43+
private static partial IntPtr CryptoNative_EvpSha384();
3844

39-
internal static IntPtr EvpSha384() =>
45+
private static IntPtr EvpSha384() =>
4046
s_evpSha384 != IntPtr.Zero ? s_evpSha384 : (s_evpSha384 = CryptoNative_EvpSha384());
4147

4248
[LibraryImport(Libraries.CryptoNative)]
43-
internal static partial IntPtr CryptoNative_EvpSha512();
49+
private static partial IntPtr CryptoNative_EvpSha512();
4450

45-
internal static IntPtr EvpSha512() =>
51+
private static IntPtr EvpSha512() =>
4652
s_evpSha512 != IntPtr.Zero ? s_evpSha512 : (s_evpSha512 = CryptoNative_EvpSha512());
4753

48-
internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId) => hashAlgorithmId switch
54+
[LibraryImport(Libraries.CryptoNative)]
55+
private static partial IntPtr CryptoNative_EvpSha3_256();
56+
57+
private static IntPtr EvpSha3_256()
58+
{
59+
if (!s_evpSha3_256Cached)
60+
{
61+
s_evpSha3_256 = CryptoNative_EvpSha3_256();
62+
s_evpSha3_256Cached = true;
63+
}
64+
65+
return s_evpSha3_256;
66+
}
67+
68+
[LibraryImport(Libraries.CryptoNative)]
69+
private static partial IntPtr CryptoNative_EvpSha3_384();
70+
71+
private static IntPtr EvpSha3_384()
72+
{
73+
if (!s_evpSha3_384Cached)
74+
{
75+
s_evpSha3_384 = CryptoNative_EvpSha3_384();
76+
s_evpSha3_384Cached = true;
77+
}
78+
79+
return s_evpSha3_384;
80+
}
81+
82+
[LibraryImport(Libraries.CryptoNative)]
83+
private static partial IntPtr CryptoNative_EvpSha3_512();
84+
85+
private static IntPtr EvpSha3_512()
86+
{
87+
if (!s_evpSha3_512Cached)
88+
{
89+
s_evpSha3_512 = CryptoNative_EvpSha3_512();
90+
s_evpSha3_512Cached = true;
91+
}
92+
93+
return s_evpSha3_512;
94+
}
95+
96+
97+
internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId)
98+
{
99+
switch (hashAlgorithmId)
100+
{
101+
case HashAlgorithmNames.SHA1: return EvpSha1();
102+
case HashAlgorithmNames.SHA256: return EvpSha256();
103+
case HashAlgorithmNames.SHA384: return EvpSha384();
104+
case HashAlgorithmNames.SHA512: return EvpSha512();
105+
case HashAlgorithmNames.SHA3_256:
106+
IntPtr sha3_256 = EvpSha3_256();
107+
return sha3_256 != 0 ? sha3_256 : throw new PlatformNotSupportedException();
108+
case HashAlgorithmNames.SHA3_384:
109+
IntPtr sha3_384 = EvpSha3_384();
110+
return sha3_384 != 0 ? sha3_384 : throw new PlatformNotSupportedException();
111+
case HashAlgorithmNames.SHA3_512:
112+
IntPtr sha3_512 = EvpSha3_512();
113+
return sha3_512 != 0 ? sha3_512 : throw new PlatformNotSupportedException();
114+
case nameof(HashAlgorithmName.MD5): return EvpMd5();
115+
default:
116+
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
117+
};
118+
}
119+
120+
internal static bool HashAlgorithmSupported(string hashAlgorithmId)
49121
{
50-
nameof(HashAlgorithmName.SHA1) => EvpSha1(),
51-
nameof(HashAlgorithmName.SHA256) => EvpSha256(),
52-
nameof(HashAlgorithmName.SHA384) => EvpSha384(),
53-
nameof(HashAlgorithmName.SHA512) => EvpSha512(),
54-
nameof(HashAlgorithmName.MD5) => EvpMd5(),
55-
_ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId))
56-
};
122+
switch (hashAlgorithmId)
123+
{
124+
case HashAlgorithmNames.SHA1:
125+
case HashAlgorithmNames.SHA256:
126+
case HashAlgorithmNames.SHA384:
127+
case HashAlgorithmNames.SHA512:
128+
case HashAlgorithmNames.MD5:
129+
return true;
130+
case HashAlgorithmNames.SHA3_256:
131+
return EvpSha3_256() != 0;
132+
case HashAlgorithmNames.SHA3_384:
133+
return EvpSha3_384() != 0;
134+
case HashAlgorithmNames.SHA3_512:
135+
return EvpSha3_512() != 0;
136+
default:
137+
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId));
138+
}
139+
}
57140
}
58141
}

src/libraries/Common/src/Interop/Windows/BCrypt/BCryptAlgorithmCache.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ internal static partial class BCrypt
1313
internal static class BCryptAlgorithmCache
1414
{
1515
private static readonly ConcurrentDictionary<(string HashAlgorithmId, BCryptOpenAlgorithmProviderFlags Flags), (SafeBCryptAlgorithmHandle Handle, int HashSizeInBytes)> s_handles = new();
16+
private static readonly ConcurrentDictionary<(string HashAlgorithmId, BCryptOpenAlgorithmProviderFlags Flags), bool> s_supported = new();
1617

1718
/// <summary>
1819
/// 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
4344
}
4445
}
4546
}
47+
48+
public static unsafe bool IsBCryptAlgorithmSupported(string hashAlgorithmId, BCryptOpenAlgorithmProviderFlags flags)
49+
{
50+
var key = (hashAlgorithmId, flags);
51+
52+
if (s_supported.TryGetValue(key, out bool supported))
53+
{
54+
return supported;
55+
}
56+
57+
NTSTATUS status = BCryptOpenAlgorithmProvider(
58+
out SafeBCryptAlgorithmHandle handle,
59+
key.hashAlgorithmId,
60+
null,
61+
key.flags);
62+
63+
bool isSupported = status == NTSTATUS.STATUS_SUCCESS;
64+
65+
if (s_supported.TryAdd(key, isSupported) && isSupported)
66+
{
67+
// It's a valid algorithm. Let's prime the handle cache while we are here. Presumably it's
68+
// going to get used if we're asking if it's supported.
69+
int hashSize = BCryptGetDWordProperty(handle, BCryptPropertyStrings.BCRYPT_HASH_LENGTH);
70+
Debug.Assert(hashSize > 0);
71+
72+
if (s_handles.TryAdd(key, (handle, hashSize)))
73+
{
74+
// If we added the handle to the cache, don't dispose of it and return our answer.
75+
return isSupported;
76+
}
77+
}
78+
79+
// Either the algorithm isn't supported or we don't need it for priming the cache, so Dispose.
80+
handle.Dispose();
81+
return isSupported;
82+
}
4683
}
4784
}
4885
}

src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptAlgPseudoHandle.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public enum BCryptAlgPseudoHandle : uint
2323
BCRYPT_HMAC_SHA384_ALG_HANDLE = 0x000000c1,
2424
BCRYPT_HMAC_SHA512_ALG_HANDLE = 0x000000d1,
2525
BCRYPT_PBKDF2_ALG_HANDLE = 0x00000331,
26+
BCRYPT_SHA3_256_ALG_HANDLE = 0x000003B1,
27+
BCRYPT_SHA3_384_ALG_HANDLE = 0x000003C1,
28+
BCRYPT_SHA3_512_ALG_HANDLE = 0x000003D1,
29+
BCRYPT_HMAC_SHA3_256_ALG_HANDLE = 0x000003E1,
30+
BCRYPT_HMAC_SHA3_384_ALG_HANDLE = 0x000003F1,
31+
BCRYPT_HMAC_SHA3_512_ALG_HANDLE = 0x00000401,
2632
}
2733

2834
internal static bool PseudoHandlesSupported { get; } =

0 commit comments

Comments
 (0)