@@ -234,12 +234,77 @@ private void DoGcmEncrypt(byte* pbKey, uint cbKey, byte* pbNonce, byte* pbPlaint
234234#if NET10_0_OR_GREATER
235235 public override int GetEncryptedSize( int plainTextLength , uint preBufferSize , uint postBufferSize )
236236 {
237+ // A buffer to hold the key modifier, nonce, encrypted data, and tag.
238+ // In GCM, the encrypted output will be the same length as the plaintext input.
237239 return checked ( ( int ) ( preBufferSize + KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES + plainTextLength + TAG_SIZE_IN_BYTES + postBufferSize ) ) ;
238240 }
239241
240242 public override bool TryEncrypt( ReadOnlySpan < byte > plainText , ReadOnlySpan < byte > additionalAuthenticatedData , Span < byte > destination , out int bytesWritten)
241243 {
242- throw new NotImplementedException ( ) ;
244+ bytesWritten = 0 ;
245+
246+ try
247+ {
248+ fixed ( byte * pbDestination = destination)
249+ {
250+ // Calculate offsets
251+ byte * pbKeyModifier = pbDestination;
252+ byte * pbNonce = & pbKeyModifier[ KEY_MODIFIER_SIZE_IN_BYTES] ;
253+ byte * pbEncryptedData = & pbNonce[ NONCE_SIZE_IN_BYTES] ;
254+ byte * pbAuthTag = & pbEncryptedData[ plainText. Length] ;
255+
256+ // Randomly generate the key modifier and nonce
257+ _genRandom . GenRandom( pbKeyModifier , KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES ) ;
258+ bytesWritten += checked ( ( int ) ( KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES ) ) ;
259+
260+ // At this point, retVal := { preBuffer | keyModifier | nonce | _____ | _____ | postBuffer }
261+
262+ // Use the KDF to generate a new symmetric block cipher key
263+ // We'll need a temporary buffer to hold the symmetric encryption subkey
264+ byte * pbSymmetricEncryptionSubkey = stackalloc byte [ checked ( ( int ) _symmetricAlgorithmSubkeyLengthInBytes ) ] ;
265+ try
266+ {
267+ fixed ( byte * pbAdditionalAuthenticatedData = additionalAuthenticatedData)
268+ {
269+ _sp800_108_ctr_hmac_provider. DeriveKeyWithContextHeader(
270+ pbLabel : pbAdditionalAuthenticatedData ,
271+ cbLabel : ( uint ) additionalAuthenticatedData . Length,
272+ contextHeader : _contextHeader ,
273+ pbContext : pbKeyModifier ,
274+ cbContext : KEY_MODIFIER_SIZE_IN_BYTES ,
275+ pbDerivedKey : pbSymmetricEncryptionSubkey ,
276+ cbDerivedKey : _symmetricAlgorithmSubkeyLengthInBytes ) ;
277+ }
278+
279+ // Perform the encryption operation
280+ fixed ( byte * pbPlainText = plainText )
281+ {
282+ DoGcmEncrypt(
283+ pbKey: pbSymmetricEncryptionSubkey,
284+ cbKey : _symmetricAlgorithmSubkeyLengthInBytes ,
285+ pbNonce : pbNonce ,
286+ pbPlaintextData : pbPlainText ,
287+ cbPlaintextData : ( uint ) plainText . Length,
288+ pbEncryptedData : pbEncryptedData ,
289+ pbTag : pbAuthTag ) ;
290+ }
291+
292+ // At this point, retVal := { preBuffer | keyModifier | nonce | encryptedData | authenticationTag | postBuffer }
293+ // And we're done!
294+ bytesWritten += plainText. Length + checked ( ( int ) TAG_SIZE_IN_BYTES) ;
295+ return true;
296+ }
297+ finally
298+ {
299+ // The buffer contains key material, so delete it.
300+ UnsafeBufferUtil . SecureZeroMemory( pbSymmetricEncryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes ) ;
301+ }
302+ }
303+ }
304+ catch ( Exception ex) when ( ex . RequiresHomogenization ( ) )
305+ {
306+ throw Error . CryptCommon_GenericError ( ex ) ;
307+ }
243308 }
244309#endif
245310
0 commit comments