@@ -450,32 +450,63 @@ for (const test of TEST_CASES) {
450
450
// Test that the authentication tag can be set at any point before calling
451
451
// final() in GCM mode, OCB mode, and for ChaCha20-Poly1305.
452
452
{
453
+ const aad = Buffer . from ( 'Shared' , 'utf8' ) ;
453
454
const plain = Buffer . from ( 'Hello world' , 'utf8' ) ;
454
455
const key = Buffer . from ( '0123456789abcdefghijklmnopqrstuv' , 'utf8' ) ;
455
456
const iv = Buffer . from ( '0123456789ab' , 'utf8' ) ;
456
457
457
- for ( const alg of [ 'aes-256-gcm' , 'aes-256-ocb' , 'chacha20-poly1305' ] ) {
458
- for ( const authTagLength of alg === 'aes-256-gcm' ? [ undefined , 8 ] : [ 8 ] ) {
459
- const cipher = crypto . createCipheriv ( alg , key , iv , {
458
+ function testAllOrders ( { alg, authTagLength, useAAD, useMessage } ) {
459
+ // Encrypt the message first to obtain ciphertext and authTag.
460
+ const cipher = crypto . createCipheriv ( alg , key , iv , {
461
+ authTagLength
462
+ } ) ;
463
+ if ( useAAD ) {
464
+ cipher . setAAD ( aad ) ;
465
+ }
466
+ const ciphertext = useMessage ? Buffer . concat ( [ cipher . update ( plain ) , cipher . final ( ) ] ) : cipher . final ( ) ;
467
+ const authTag = cipher . getAuthTag ( ) ;
468
+ assert . strictEqual ( authTag . length , authTagLength ?? 16 ) ;
469
+
470
+ // Test decryption with each possible order of operations.
471
+ for ( const authTagTime of [ 'beforeAAD' , 'beforeUpdate' , 'afterUpdate' ] ) {
472
+ const decipher = crypto . createDecipheriv ( alg , key , iv , {
460
473
authTagLength
461
474
} ) ;
462
- const ciphertext = Buffer . concat ( [ cipher . update ( plain ) , cipher . final ( ) ] ) ;
463
- const authTag = cipher . getAuthTag ( ) ;
475
+ if ( authTagTime === 'beforeAAD' ) {
476
+ decipher . setAuthTag ( authTag ) ;
477
+ }
478
+ if ( useAAD ) {
479
+ decipher . setAAD ( aad ) ;
480
+ }
481
+ if ( authTagTime === 'beforeUpdate' ) {
482
+ decipher . setAuthTag ( authTag ) ;
483
+ }
484
+ const resultBuffers = [ ] ;
485
+ if ( useMessage ) {
486
+ resultBuffers . push ( decipher . update ( ciphertext ) ) ;
487
+ }
488
+ if ( authTagTime === 'afterUpdate' ) {
489
+ decipher . setAuthTag ( authTag ) ;
490
+ }
491
+ resultBuffers . push ( decipher . final ( ) ) ;
492
+ const result = Buffer . concat ( resultBuffers ) ;
493
+ if ( useMessage ) {
494
+ assert . deepStrictEqual ( result , plain ) ;
495
+ } else {
496
+ assert . strictEqual ( result . length , 0 ) ;
497
+ }
498
+ }
499
+ }
464
500
465
- for ( const authTagBeforeUpdate of [ true , false ] ) {
466
- const decipher = crypto . createDecipheriv ( alg , key , iv , {
467
- authTagLength
468
- } ) ;
469
- if ( authTagBeforeUpdate ) {
470
- decipher . setAuthTag ( authTag ) ;
471
- }
472
- const resultUpdate = decipher . update ( ciphertext ) ;
473
- if ( ! authTagBeforeUpdate ) {
474
- decipher . setAuthTag ( authTag ) ;
475
- }
476
- const resultFinal = decipher . final ( ) ;
477
- const result = Buffer . concat ( [ resultUpdate , resultFinal ] ) ;
478
- assert ( result . equals ( plain ) ) ;
501
+ for ( const alg of [ 'aes-256-gcm' , 'aes-256-ocb' , 'chacha20-poly1305' ] ) {
502
+ for ( const authTagLength of alg === 'aes-256-gcm' ? [ undefined , 8 ] : [ 8 ] ) {
503
+ for ( const [ useAAD , useMessage ] of [
504
+ [ false , false ] , // No AAD, no update.
505
+ [ true , false ] , // Only AAD (e.g., GMAC).
506
+ [ false , true ] , // No AAD, only message.
507
+ [ true , true ] , // Both AAD and message.
508
+ ] ) {
509
+ testAllOrders ( { alg, authTagLength, useAAD, useMessage } ) ;
479
510
}
480
511
}
481
512
}
0 commit comments