33
44using System ;
55using System . Buffers ;
6+ using System . Diagnostics ;
67using System . Security . Cryptography ;
78using Microsoft . AspNetCore . Cryptography ;
89using 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