@@ -145,11 +145,80 @@ public int GetEncryptedSize(int plainTextLength)
145145 => GetEncryptedSize ( plainTextLength , 0 , 0 ) ;
146146
147147 public int GetEncryptedSize ( int plainTextLength , uint preBufferSize , uint postBufferSize )
148- => checked ( ( int ) ( preBufferSize + KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES + plainTextLength + TAG_SIZE_IN_BYTES + postBufferSize ) ) ;
148+ {
149+ // A buffer to hold the key modifier, nonce, encrypted data, and tag.
150+ // In GCM, the encrypted output will be the same length as the plaintext input.
151+ return checked ( ( int ) ( preBufferSize + KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES + plainTextLength + TAG_SIZE_IN_BYTES + postBufferSize ) ) ;
152+ }
149153
150- public bool TryEncrypt ( ReadOnlySpan < byte > plainText , ReadOnlySpan < byte > additionalAuthenticatedData , Span < byte > destination , out int bytesWritten )
154+ public bool TryEncrypt ( ReadOnlySpan < byte > plaintext , ReadOnlySpan < byte > additionalAuthenticatedData , Span < byte > destination , out int bytesWritten )
151155 {
152- throw new NotImplementedException ( ) ;
156+ bytesWritten = 0 ;
157+
158+ try
159+ {
160+ // Generate random key modifier and nonce
161+ var keyModifier = _genRandom . GenRandom ( KEY_MODIFIER_SIZE_IN_BYTES ) ;
162+ var nonceBytes = _genRandom . GenRandom ( NONCE_SIZE_IN_BYTES ) ;
163+
164+ // KeyModifier and nonce to destination
165+ keyModifier . CopyTo ( destination . Slice ( bytesWritten , KEY_MODIFIER_SIZE_IN_BYTES ) ) ;
166+ bytesWritten += KEY_MODIFIER_SIZE_IN_BYTES ;
167+ nonceBytes . CopyTo ( destination . Slice ( bytesWritten , NONCE_SIZE_IN_BYTES ) ) ;
168+ bytesWritten += NONCE_SIZE_IN_BYTES ;
169+
170+ // At this point, destination := { keyModifier | nonce | _____ | _____ }
171+
172+ // Use the KDF to generate a new symmetric block cipher key
173+ // We'll need a temporary buffer to hold the symmetric encryption subkey
174+ Span < byte > decryptedKdk = _keyDerivationKey . Length <= 256
175+ ? stackalloc byte [ 256 ] . Slice ( 0 , _keyDerivationKey . Length )
176+ : new byte [ _keyDerivationKey . Length ] ;
177+ var derivedKey = _derivedkeySizeInBytes <= 256
178+ ? stackalloc byte [ 256 ] . Slice ( 0 , _derivedkeySizeInBytes )
179+ : new byte [ _derivedkeySizeInBytes ] ;
180+
181+ fixed ( byte * decryptedKdkUnsafe = decryptedKdk )
182+ fixed ( byte * __unused__2 = derivedKey )
183+ {
184+ try
185+ {
186+ _keyDerivationKey . WriteSecretIntoBuffer ( decryptedKdkUnsafe , decryptedKdk . Length ) ;
187+ ManagedSP800_108_CTR_HMACSHA512 . DeriveKeys (
188+ kdk : decryptedKdk ,
189+ label : additionalAuthenticatedData ,
190+ contextHeader : _contextHeader ,
191+ contextData : keyModifier ,
192+ operationSubkey : derivedKey ,
193+ validationSubkey : Span < byte > . Empty /* filling in derivedKey only */ ) ;
194+
195+ // Perform GCM encryption. Destination buffer expected structure:
196+ // { keyModifier | nonce | encryptedData | authenticationTag }
197+ var nonce = destination . Slice ( KEY_MODIFIER_SIZE_IN_BYTES , NONCE_SIZE_IN_BYTES ) ;
198+ var encrypted = destination . Slice ( bytesWritten , plaintext . Length ) ;
199+ var tag = destination . Slice ( bytesWritten + plaintext . Length , TAG_SIZE_IN_BYTES ) ;
200+
201+ using var aes = new AesGcm ( derivedKey , TAG_SIZE_IN_BYTES ) ;
202+ aes . Encrypt ( nonce , plaintext , encrypted , tag ) ;
203+
204+ // At this point, destination := { keyModifier | nonce | encryptedData | authenticationTag }
205+ // And we're done!
206+ bytesWritten += plaintext . Length + TAG_SIZE_IN_BYTES ;
207+ return true ;
208+ }
209+ finally
210+ {
211+ // delete since these contain secret material
212+ decryptedKdk . Clear ( ) ;
213+ derivedKey . Clear ( ) ;
214+ }
215+ }
216+ }
217+ catch ( Exception ex ) when ( ex . RequiresHomogenization ( ) )
218+ {
219+ // Homogenize all exceptions to CryptographicException.
220+ throw Error . CryptCommon_GenericError ( ex ) ;
221+ }
153222 }
154223
155224 public byte [ ] Encrypt ( ArraySegment < byte > plaintext , ArraySegment < byte > additionalAuthenticatedData , uint preBufferSize , uint postBufferSize )
0 commit comments