Skip to content

Commit 0b04dfd

Browse files
authored
Implement Micrososoft.Bcl.Cryptography without System.Security.Cryptography.Algorithms (#85683)
* Implement Micrososoft.Bcl.Cryptography without System.Security.Cryptography.Algorithms * Assert data written * Call Initialize on the right thing
1 parent d9030cb commit 0b04dfd

File tree

3 files changed

+59
-15
lines changed

3 files changed

+59
-15
lines changed

src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,4 @@ System.Security.Cryptography.SP800108HmacCounterKdf</PackageDescription>
7272
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
7373
<PackageReference Include="System.Memory" Version="$(SystemMemoryVersion)" />
7474
</ItemGroup>
75-
76-
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
77-
<PackageReference Include="System.Security.Cryptography.Algorithms" Version="$(SystemSecurityCryptographyAlgorithmsVersion)" />
78-
</ItemGroup>
7975
</Project>

src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationCng.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,28 @@ internal unsafe SP800108HmacCounterKdfImplementationCng(byte[] key, HashAlgorith
103103

104104
private static byte[] HashOneShot(HashAlgorithmName hashAlgorithm, byte[] data)
105105
{
106-
using (IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm))
106+
using (HashAlgorithm hash = CreateHash(hashAlgorithm))
107107
{
108-
hash.AppendData(data);
109-
return hash.GetHashAndReset();
108+
return hash.ComputeHash(data);
109+
}
110+
}
111+
112+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "Weak algorithms are used as instructed by the caller")]
113+
private static HashAlgorithm CreateHash(HashAlgorithmName hashAlgorithm)
114+
{
115+
switch (hashAlgorithm.Name)
116+
{
117+
case HashAlgorithmNames.SHA1:
118+
return SHA1.Create();
119+
case HashAlgorithmNames.SHA256:
120+
return SHA256.Create();
121+
case HashAlgorithmNames.SHA384:
122+
return SHA384.Create();
123+
case HashAlgorithmNames.SHA512:
124+
return SHA512.Create();
125+
default:
126+
Debug.Fail($"Unexpected hash algorithm '{hashAlgorithm.Name}'.");
127+
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
110128
}
111129
}
112130
}

src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationManaged.cs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ private static void DeriveBytesOneShot(
139139
// The KDF is defined as K(i) := PRF (KI, [i]2 || Label || 0x00 || Context || [L]2)
140140
// We know L is already less than 0x1FFFFFFF. h = ceil(L / h) where H is the hash length in bits.
141141
// So we don't expect i to overflow.
142-
using (IncrementalHash hash = IncrementalHash.CreateHMAC(hashAlgorithm, key))
142+
using (HMAC hash = CreateHMAC(hashAlgorithm, key))
143143
{
144144
// We use this rented buffer for three things. The first two uints for i and L, and last byte
145145
// for the zero separator. So this is
@@ -165,19 +165,30 @@ private static void DeriveBytesOneShot(
165165
for (uint i = 1; !destination.IsEmpty; i++)
166166
{
167167
WriteUInt32BigEndian(i, rentedBuffer.AsSpan(IOffset, ILength));
168-
hash.AppendData(rentedBuffer, IOffset, ILength);
169-
hash.AppendData(label, 0, labelLength);
170-
hash.AppendData(rentedBuffer, ZeroOffset, ZeroLength);
171-
hash.AppendData(context, 0, contextLength);
172-
hash.AppendData(rentedBuffer, LOffset, LLength);
173-
174-
byte[] hmac = hash.GetHashAndReset();
168+
int written;
169+
written = hash.TransformBlock(rentedBuffer, IOffset, ILength, null, 0);
170+
Debug.Assert(written == ILength);
171+
written = hash.TransformBlock(label, 0, labelLength, null, 0);
172+
Debug.Assert(written == labelLength);
173+
written = hash.TransformBlock(rentedBuffer, ZeroOffset, ZeroLength, null, 0);
174+
Debug.Assert(written == ZeroLength);
175+
written = hash.TransformBlock(context, 0, contextLength, null, 0);
176+
Debug.Assert(written == contextLength);
177+
written = hash.TransformBlock(rentedBuffer, LOffset, LLength, null, 0);
178+
Debug.Assert(written == LLength);
179+
180+
// Use an empty input for the final transform so that the returned value isn't something
181+
// we need to clear since the return value is the same as the input.
182+
hash.TransformFinalBlock(Array.Empty<byte>(), 0, 0);
183+
184+
byte[] hmac = hash.Hash;
175185
int needed = Math.Min(destination.Length, hmac.Length);
176186
hmac.AsSpan(0, needed).CopyTo(destination);
177187
destination = destination.Slice(needed);
178188

179189
// Best effort to zero out the key material.
180190
CryptographicOperations.ZeroMemory(hmac);
191+
hash.Initialize();
181192
}
182193
}
183194
finally
@@ -199,5 +210,24 @@ private static void WriteUInt32BigEndian(uint value, Span<byte> destination)
199210
destination[2] = (byte)(value >> 8);
200211
destination[3] = (byte)(value);
201212
}
213+
214+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5350", Justification = "Weak algorithms are used as instructed by the caller")]
215+
private static HMAC CreateHMAC(HashAlgorithmName hashAlgorithm, byte[] key)
216+
{
217+
switch (hashAlgorithm.Name)
218+
{
219+
case HashAlgorithmNames.SHA1:
220+
return new HMACSHA1(key);
221+
case HashAlgorithmNames.SHA256:
222+
return new HMACSHA256(key);
223+
case HashAlgorithmNames.SHA384:
224+
return new HMACSHA384(key);
225+
case HashAlgorithmNames.SHA512:
226+
return new HMACSHA512(key);
227+
default:
228+
Debug.Fail($"Unexpected HMAC algorithm '{hashAlgorithm.Name}'.");
229+
throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name));
230+
}
231+
}
202232
}
203233
}

0 commit comments

Comments
 (0)