Skip to content

Commit 26ee6ad

Browse files
committed
address ManagedSP800_108_CTR_HMACSHA512
1 parent 489c5cd commit 26ee6ad

File tree

2 files changed

+33
-38
lines changed

2 files changed

+33
-38
lines changed

src/DataProtection/DataProtection/src/Managed/ManagedAuthenticatedEncryptor.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ public byte[] Decrypt(ArraySegment<byte> protectedPayload, ArraySegment<byte> ad
197197

198198
// Step 2: Decrypt the KDK and use it to restore the original encryption and MAC keys.
199199
#if NET10_0_OR_GREATER
200-
Span<byte> decryptedKdk = _keyDerivationKey.Length <= 128
201-
? stackalloc byte[128].Slice(0, _keyDerivationKey.Length)
200+
Span<byte> decryptedKdk = _keyDerivationKey.Length <= 256
201+
? stackalloc byte[256].Slice(0, _keyDerivationKey.Length)
202202
: new byte[_keyDerivationKey.Length];
203203
#else
204204
var decryptedKdk = new byte[_keyDerivationKey.Length];
@@ -211,8 +211,8 @@ public byte[] Decrypt(ArraySegment<byte> protectedPayload, ArraySegment<byte> ad
211211

212212
#if NET10_0_OR_GREATER
213213
Span<byte> decryptionSubkey =
214-
_symmetricAlgorithmSubkeyLengthInBytes <= 256
215-
? stackalloc byte[256].Slice(0, _symmetricAlgorithmSubkeyLengthInBytes)
214+
_symmetricAlgorithmSubkeyLengthInBytes <= 128
215+
? stackalloc byte[128].Slice(0, _symmetricAlgorithmSubkeyLengthInBytes)
216216
: new byte[_symmetricAlgorithmBlockSizeInBytes];
217217
#else
218218
byte[] decryptionSubkey = new byte[_symmetricAlgorithmSubkeyLengthInBytes];
@@ -307,8 +307,8 @@ public byte[] Encrypt(ArraySegment<byte> plaintext, ArraySegment<byte> additiona
307307
var ivLength = _symmetricAlgorithmBlockSizeInBytes;
308308

309309
#if NET10_0_OR_GREATER
310-
Span<byte> decryptedKdk = _keyDerivationKey.Length <= 128
311-
? stackalloc byte[128].Slice(0, _keyDerivationKey.Length)
310+
Span<byte> decryptedKdk = _keyDerivationKey.Length <= 256
311+
? stackalloc byte[256].Slice(0, _keyDerivationKey.Length)
312312
: new byte[_keyDerivationKey.Length];
313313
#else
314314
var decryptedKdk = new byte[_keyDerivationKey.Length];

src/DataProtection/DataProtection/src/SP800_108/ManagedSP800_108_CTR_HMACSHA512.cs

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Buffers;
6+
using System.Diagnostics;
67
using System.Security.Cryptography;
78
using Microsoft.AspNetCore.Cryptography;
89
using Microsoft.AspNetCore.DataProtection.Internal;
@@ -51,15 +52,26 @@ private static void DeriveKeys(
5152
var validationSubKeyIndex = 0;
5253
var outputCount = operationSubkey.Length + validationSubkey.Length;
5354

54-
byte[]? prfOutput = null;
55+
int prfOutputSizeInBytes =
56+
#if NET10_0_OR_GREATER
57+
HMACSHA512.HashSizeInBytes;
58+
#else
59+
prf.GetDigestSizeInBytes();
60+
#endif
61+
62+
#if NET10_0_OR_GREATER
63+
Span<byte> prfOutput = prfOutputSizeInBytes <= 128
64+
? stackalloc byte[128].Slice(0, prfOutputSizeInBytes)
65+
: new byte[prfOutputSizeInBytes];
66+
#endif
5567

5668
// See SP800-108, Sec. 5.1 for the format of the input to the PRF routine.
5769
var prfInputLength = checked(sizeof(uint) /* [i]_2 */ + label.Length + 1 /* 0x00 */ + (contextHeader.Length + contextData.Length) + sizeof(uint) /* [K]_2 */);
5870

5971
#if NET10_0_OR_GREATER
6072
byte[]? prfInputArray = null;
6173
Span<byte> prfInput = prfInputLength <= 128
62-
? stackalloc byte[prfInputLength]
74+
? stackalloc byte[128].Slice(0, prfInputLength)
6375
: (prfInputArray = new byte[prfInputLength]);
6476
#else
6577
var prfInputArray = new byte[prfInputLength];
@@ -80,12 +92,6 @@ private static void DeriveKeys(
8092
contextHeader.CopyTo(prfInput.Slice(sizeof(uint) + label.Length + 1));
8193
contextData.CopyTo(prfInput.Slice(sizeof(uint) + label.Length + 1 + contextHeader.Length));
8294

83-
int prfOutputSizeInBytes =
84-
#if NET10_0_OR_GREATER
85-
HMACSHA512.HashSizeInBytes;
86-
#else
87-
prf.GetDigestSizeInBytes();
88-
#endif
8995
for (uint i = 1; outputCount > 0; i++)
9096
{
9197
// Copy [i]_2 to prfInput since it mutates with each iteration
@@ -95,12 +101,12 @@ private static void DeriveKeys(
95101
prfInput[3] = (byte)(i);
96102

97103
#if NET10_0_OR_GREATER
98-
// not using stackalloc here, because we are in a loop
99-
// and potentially can exhaust the stack memory: https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2014
100-
prfOutput = new byte[prfOutputSizeInBytes];
101-
HMACSHA512.TryHashData(kdk, prfInput, prfOutput, out _);
104+
var success = HMACSHA512.TryHashData(kdk, prfInput, prfOutput, out var bytesWritten);
105+
Debug.Assert(success);
106+
Debug.Assert(bytesWritten == prfOutputSizeInBytes);
102107
#else
103-
prfOutput = prf.ComputeHash(prfInputArray);
108+
var prfOutputArray = prf.ComputeHash(prfInputArray);
109+
var prfOutput = prfOutputArray.AsSpan();
104110
#endif
105111
CryptoUtil.Assert(prfOutputSizeInBytes == prfOutput.Length, "prfOutputSizeInBytes == prfOutput.Length");
106112
var numBytesToCopyThisIteration = Math.Min(prfOutputSizeInBytes, outputCount);
@@ -113,17 +119,21 @@ private static void DeriveKeys(
113119
if (operationSubKeyIndex < operationSubkey.Length) // meaning we need to write to operationSubKey
114120
{
115121
var destination = operationSubkey.Slice(operationSubKeyIndex, bytesToWrite);
116-
prfOutput.AsSpan(0, bytesToWrite).CopyTo(destination);
122+
prfOutput.Slice(0, bytesToWrite).CopyTo(destination);
117123
operationSubKeyIndex += bytesToWrite;
118124
}
119125
if (operationSubKeyIndex == operationSubkey.Length && leftOverBytes != 0) // we have filled the operationSubKey. It's time for the validationSubKey
120126
{
121127
var destination = validationSubkey.Slice(validationSubKeyIndex, leftOverBytes);
122-
prfOutput.AsSpan(bytesToWrite, leftOverBytes).CopyTo(destination);
128+
prfOutput.Slice(bytesToWrite, leftOverBytes).CopyTo(destination);
123129
validationSubKeyIndex += leftOverBytes;
124130
}
125131

126132
outputCount -= numBytesToCopyThisIteration;
133+
134+
#if !NET10_0_OR_GREATER
135+
prfOutput.Clear();
136+
#endif
127137
}
128138
}
129139
finally
@@ -133,24 +143,9 @@ private static void DeriveKeys(
133143
disposablePrf.Dispose();
134144
}
135145

146+
prfInput.Clear();
136147
#if NET10_0_OR_GREATER
137-
if (prfOutput is not null)
138-
{
139-
Array.Clear(prfOutput, 0, prfOutput.Length); // contains key material, so delete it
140-
}
141-
142-
if (prfInputArray is not null)
143-
{
144-
Array.Clear(prfInputArray, 0, prfInputArray.Length); // contains key material, so delete it
145-
}
146-
else
147-
{
148-
// to be extra careful - clear the stackalloc memory
149-
prfInput.Clear();
150-
}
151-
#else
152-
Array.Clear(prfInputArray, 0, prfInputArray.Length); // contains key material, so delete it
153-
Array.Clear(prfOutput, 0, prfOutput.Length); // contains key material, so delete it
148+
prfOutput.Clear();
154149
#endif
155150
}
156151
}

0 commit comments

Comments
 (0)