@@ -76,39 +76,35 @@ WebCryptoCipherStatus AES_Cipher(Environment* env,
7676 }
7777
7878 size_t tag_len = 0 ;
79+ size_t data_len = in.size ();
7980
8081 if (params.cipher .isGcmMode () || params.cipher .isOcbMode ()) {
82+ tag_len = params.length ;
8183 switch (cipher_mode) {
8284 case kWebCryptoCipherDecrypt : {
83- // If in decrypt mode, the auth tag must be set in the params.tag.
84- CHECK (params.tag );
85+ // In decrypt mode, the auth tag is appended to the end of the
86+ // ciphertext. Split it off and set it on the cipher context.
87+ if (data_len < tag_len) {
88+ return WebCryptoCipherStatus::FAILED;
89+ }
90+ data_len -= tag_len;
8591
86- // For OCB mode, we need to set the auth tag length before setting the
87- // tag
8892 if (params.cipher .isOcbMode ()) {
89- if (!ctx.setAeadTagLength (params. tag . size () )) {
93+ if (!ctx.setAeadTagLength (tag_len )) {
9094 return WebCryptoCipherStatus::FAILED;
9195 }
9296 }
9397
9498 ncrypto::Buffer<const char > buffer = {
95- .data = params. tag . data <char >(),
96- .len = params. tag . size () ,
99+ .data = in. data <char >() + data_len ,
100+ .len = tag_len ,
97101 };
98102 if (!ctx.setAeadTag (buffer)) {
99103 return WebCryptoCipherStatus::FAILED;
100104 }
101105 break ;
102106 }
103107 case kWebCryptoCipherEncrypt : {
104- // In encrypt mode, we grab the tag length here. We'll use it to
105- // ensure that that allocated buffer has enough room for both the
106- // final block and the auth tag. Unlike our other AES-GCM implementation
107- // in CipherBase, in WebCrypto, the auth tag is concatenated to the end
108- // of the generated ciphertext and returned in the same ArrayBuffer.
109- tag_len = params.length ;
110-
111- // For OCB mode, we need to set the auth tag length
112108 if (params.cipher .isOcbMode ()) {
113109 if (!ctx.setAeadTagLength (tag_len)) {
114110 return WebCryptoCipherStatus::FAILED;
@@ -122,7 +118,7 @@ WebCryptoCipherStatus AES_Cipher(Environment* env,
122118 }
123119
124120 size_t total = 0 ;
125- int buf_len = in. size () + ctx.getBlockSize () + tag_len;
121+ int buf_len = data_len + ctx.getBlockSize () + (encrypt ? tag_len : 0 ) ;
126122 int out_len;
127123
128124 ncrypto::Buffer<const unsigned char > buffer = {
@@ -148,9 +144,9 @@ WebCryptoCipherStatus AES_Cipher(Environment* env,
148144 // Refs: https://github.com/nodejs/node/pull/38913#issuecomment-866505244
149145 buffer = {
150146 .data = in.data <unsigned char >(),
151- .len = in. size () ,
147+ .len = data_len ,
152148 };
153- if (in. empty () ) {
149+ if (data_len == 0 ) {
154150 out_len = 0 ;
155151 } else if (!ctx.update (buffer, ptr, &out_len)) {
156152 return WebCryptoCipherStatus::FAILED;
@@ -381,42 +377,17 @@ bool ValidateCounter(
381377 return true ;
382378}
383379
384- bool ValidateAuthTag (
385- Environment* env,
386- CryptoJobMode mode,
387- WebCryptoCipherMode cipher_mode,
388- Local<Value> value,
389- AESCipherConfig* params) {
390- switch (cipher_mode) {
391- case kWebCryptoCipherDecrypt : {
392- if (!IsAnyBufferSource (value)) {
393- THROW_ERR_CRYPTO_INVALID_TAG_LENGTH (env);
394- return false ;
395- }
396- ArrayBufferOrViewContents<char > tag_contents (value);
397- if (!tag_contents.CheckSizeInt32 ()) [[unlikely]] {
398- THROW_ERR_OUT_OF_RANGE (env, " tagLength is too big" );
399- return false ;
400- }
401- params->tag = mode == kCryptoJobAsync
402- ? tag_contents.ToCopy ()
403- : tag_contents.ToByteSource ();
404- break ;
405- }
406- case kWebCryptoCipherEncrypt : {
407- if (!value->IsUint32 ()) {
408- THROW_ERR_CRYPTO_INVALID_TAG_LENGTH (env);
409- return false ;
410- }
411- params->length = value.As <Uint32>()->Value ();
412- if (params->length > 128 ) {
413- THROW_ERR_CRYPTO_INVALID_TAG_LENGTH (env);
414- return false ;
415- }
416- break ;
417- }
418- default :
419- UNREACHABLE ();
380+ bool ValidateAuthTag (Environment* env,
381+ Local<Value> value,
382+ AESCipherConfig* params) {
383+ if (!value->IsUint32 ()) {
384+ THROW_ERR_CRYPTO_INVALID_TAG_LENGTH (env);
385+ return false ;
386+ }
387+ params->length = value.As <Uint32>()->Value ();
388+ if (params->length > 128 ) {
389+ THROW_ERR_CRYPTO_INVALID_TAG_LENGTH (env);
390+ return false ;
420391 }
421392 return true ;
422393}
@@ -451,8 +422,7 @@ AESCipherConfig::AESCipherConfig(AESCipherConfig&& other) noexcept
451422 cipher(other.cipher),
452423 length(other.length),
453424 iv(std::move(other.iv)),
454- additional_data(std::move(other.additional_data)),
455- tag(std::move(other.tag)) {}
425+ additional_data(std::move(other.additional_data)) {}
456426
457427AESCipherConfig& AESCipherConfig::operator =(AESCipherConfig&& other) noexcept {
458428 if (&other == this ) return *this ;
@@ -466,7 +436,6 @@ void AESCipherConfig::MemoryInfo(MemoryTracker* tracker) const {
466436 if (mode == kCryptoJobAsync ) {
467437 tracker->TrackFieldWithSize (" iv" , iv.size ());
468438 tracker->TrackFieldWithSize (" additional_data" , additional_data.size ());
469- tracker->TrackFieldWithSize (" tag" , tag.size ());
470439 }
471440}
472441
@@ -510,7 +479,7 @@ Maybe<void> AESCipherTraits::AdditionalConfig(
510479 return Nothing<void >();
511480 }
512481 } else if (params->cipher .isGcmMode () || params->cipher .isOcbMode ()) {
513- if (!ValidateAuthTag (env, mode, cipher_mode, args[offset + 2 ], params) ||
482+ if (!ValidateAuthTag (env, args[offset + 2 ], params) ||
514483 !ValidateAdditionalData (env, mode, args[offset + 3 ], params)) {
515484 return Nothing<void >();
516485 }
0 commit comments