@@ -450,32 +450,63 @@ for (const test of TEST_CASES) {
450450// Test that the authentication tag can be set at any point before calling
451451// final() in GCM mode, OCB mode, and for ChaCha20-Poly1305.
452452{
453+ const aad = Buffer . from ( 'Shared' , 'utf8' ) ;
453454 const plain = Buffer . from ( 'Hello world' , 'utf8' ) ;
454455 const key = Buffer . from ( '0123456789abcdefghijklmnopqrstuv' , 'utf8' ) ;
455456 const iv = Buffer . from ( '0123456789ab' , 'utf8' ) ;
456457
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 , {
460473 authTagLength
461474 } ) ;
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+ }
464500
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 } ) ;
479510 }
480511 }
481512 }
0 commit comments