Coverage Report

Created: 2025-08-03 10:06

/src/node/src/crypto/crypto_aes.cc
Line
Count
Source (jump to first uncovered line)
1
#include "crypto/crypto_aes.h"
2
#include "async_wrap-inl.h"
3
#include "base_object-inl.h"
4
#include "crypto/crypto_cipher.h"
5
#include "crypto/crypto_keys.h"
6
#include "crypto/crypto_util.h"
7
#include "env-inl.h"
8
#include "memory_tracker-inl.h"
9
#include "threadpoolwork-inl.h"
10
#include "v8.h"
11
12
#include <openssl/bn.h>
13
#include <openssl/aes.h>
14
15
#include <vector>
16
17
namespace node {
18
19
using v8::FunctionCallbackInfo;
20
using v8::Just;
21
using v8::Local;
22
using v8::Maybe;
23
using v8::Nothing;
24
using v8::Object;
25
using v8::Uint32;
26
using v8::Value;
27
28
namespace crypto {
29
namespace {
30
// Implements general AES encryption and decryption for CBC
31
// The key_data must be a secret key.
32
// On success, this function sets out to a new ByteSource
33
// instance containing the results and returns WebCryptoCipherStatus::OK.
34
WebCryptoCipherStatus AES_Cipher(
35
    Environment* env,
36
    KeyObjectData* key_data,
37
    WebCryptoCipherMode cipher_mode,
38
    const AESCipherConfig& params,
39
    const ByteSource& in,
40
0
    ByteSource* out) {
41
0
  CHECK_NOT_NULL(key_data);
42
0
  CHECK_EQ(key_data->GetKeyType(), kKeyTypeSecret);
43
44
0
  const int mode = EVP_CIPHER_mode(params.cipher);
45
46
0
  CipherCtxPointer ctx(EVP_CIPHER_CTX_new());
47
0
  EVP_CIPHER_CTX_init(ctx.get());
48
0
  if (mode == EVP_CIPH_WRAP_MODE)
49
0
    EVP_CIPHER_CTX_set_flags(ctx.get(), EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
50
51
0
  const bool encrypt = cipher_mode == kWebCryptoCipherEncrypt;
52
53
0
  if (!EVP_CipherInit_ex(
54
0
          ctx.get(),
55
0
          params.cipher,
56
0
          nullptr,
57
0
          nullptr,
58
0
          nullptr,
59
0
          encrypt)) {
60
    // Cipher init failed
61
0
    return WebCryptoCipherStatus::FAILED;
62
0
  }
63
64
0
  if (mode == EVP_CIPH_GCM_MODE && !EVP_CIPHER_CTX_ctrl(
65
0
        ctx.get(),
66
0
        EVP_CTRL_AEAD_SET_IVLEN,
67
0
        params.iv.size(),
68
0
        nullptr)) {
69
0
    return WebCryptoCipherStatus::FAILED;
70
0
  }
71
72
0
  if (!EVP_CIPHER_CTX_set_key_length(
73
0
          ctx.get(),
74
0
          key_data->GetSymmetricKeySize()) ||
75
0
      !EVP_CipherInit_ex(
76
0
          ctx.get(),
77
0
          nullptr,
78
0
          nullptr,
79
0
          reinterpret_cast<const unsigned char*>(key_data->GetSymmetricKey()),
80
0
          params.iv.data<unsigned char>(),
81
0
          encrypt)) {
82
0
    return WebCryptoCipherStatus::FAILED;
83
0
  }
84
85
0
  size_t tag_len = 0;
86
87
0
  if (mode == EVP_CIPH_GCM_MODE) {
88
0
    switch (cipher_mode) {
89
0
      case kWebCryptoCipherDecrypt:
90
        // If in decrypt mode, the auth tag must be set in the params.tag.
91
0
        CHECK(params.tag);
92
0
        if (!EVP_CIPHER_CTX_ctrl(ctx.get(),
93
0
                                 EVP_CTRL_AEAD_SET_TAG,
94
0
                                 params.tag.size(),
95
0
                                 const_cast<char*>(params.tag.data<char>()))) {
96
0
          return WebCryptoCipherStatus::FAILED;
97
0
        }
98
0
        break;
99
0
      case kWebCryptoCipherEncrypt:
100
        // In decrypt mode, we grab the tag length here. We'll use it to
101
        // ensure that that allocated buffer has enough room for both the
102
        // final block and the auth tag. Unlike our other AES-GCM implementation
103
        // in CipherBase, in WebCrypto, the auth tag is concatenated to the end
104
        // of the generated ciphertext and returned in the same ArrayBuffer.
105
0
        tag_len = params.length;
106
0
        break;
107
0
      default:
108
0
        UNREACHABLE();
109
0
    }
110
0
  }
111
112
0
  size_t total = 0;
113
0
  int buf_len = in.size() + EVP_CIPHER_CTX_block_size(ctx.get()) + tag_len;
114
0
  int out_len;
115
116
0
  if (mode == EVP_CIPH_GCM_MODE &&
117
0
      params.additional_data.size() &&
118
0
      !EVP_CipherUpdate(
119
0
            ctx.get(),
120
0
            nullptr,
121
0
            &out_len,
122
0
            params.additional_data.data<unsigned char>(),
123
0
            params.additional_data.size())) {
124
0
    return WebCryptoCipherStatus::FAILED;
125
0
  }
126
127
0
  ByteSource::Builder buf(buf_len);
128
129
  // In some outdated version of OpenSSL (e.g.
130
  // ubi81_sharedlibs_openssl111fips_x64) may be used in sharedlib mode, the
131
  // logic will be failed when input size is zero. The newly OpenSSL has fixed
132
  // it up. But we still have to regard zero as special in Node.js code to
133
  // prevent old OpenSSL failure.
134
  //
135
  // Refs: https://github.com/openssl/openssl/commit/420cb707b880e4fb649094241371701013eeb15f
136
  // Refs: https://github.com/nodejs/node/pull/38913#issuecomment-866505244
137
0
  if (in.size() == 0) {
138
0
    out_len = 0;
139
0
  } else if (!EVP_CipherUpdate(ctx.get(),
140
0
                               buf.data<unsigned char>(),
141
0
                               &out_len,
142
0
                               in.data<unsigned char>(),
143
0
                               in.size())) {
144
0
    return WebCryptoCipherStatus::FAILED;
145
0
  }
146
147
0
  total += out_len;
148
0
  CHECK_LE(out_len, buf_len);
149
0
  out_len = EVP_CIPHER_CTX_block_size(ctx.get());
150
0
  if (!EVP_CipherFinal_ex(
151
0
          ctx.get(), buf.data<unsigned char>() + total, &out_len)) {
152
0
    return WebCryptoCipherStatus::FAILED;
153
0
  }
154
0
  total += out_len;
155
156
  // If using AES_GCM, grab the generated auth tag and append
157
  // it to the end of the ciphertext.
158
0
  if (cipher_mode == kWebCryptoCipherEncrypt && mode == EVP_CIPH_GCM_MODE) {
159
0
    if (!EVP_CIPHER_CTX_ctrl(ctx.get(),
160
0
                             EVP_CTRL_AEAD_GET_TAG,
161
0
                             tag_len,
162
0
                             buf.data<unsigned char>() + total))
163
0
      return WebCryptoCipherStatus::FAILED;
164
0
    total += tag_len;
165
0
  }
166
167
  // It's possible that we haven't used the full allocated space. Size down.
168
0
  *out = std::move(buf).release(total);
169
170
0
  return WebCryptoCipherStatus::OK;
171
0
}
172
173
// The AES_CTR implementation here takes it's inspiration from the chromium
174
// implementation here:
175
// https://github.com/chromium/chromium/blob/7af6cfd/components/webcrypto/algorithms/aes_ctr.cc
176
177
template <typename T>
178
0
T CeilDiv(T a, T b) {
179
0
  return a == 0 ? 0 : 1 + (a - 1) / b;
180
0
}
181
182
0
BignumPointer GetCounter(const AESCipherConfig& params) {
183
0
  unsigned int remainder = (params.length % CHAR_BIT);
184
0
  const unsigned char* data = params.iv.data<unsigned char>();
185
186
0
  if (remainder == 0) {
187
0
    unsigned int byte_length = params.length / CHAR_BIT;
188
0
    return BignumPointer(BN_bin2bn(
189
0
        data + params.iv.size() - byte_length,
190
0
        byte_length,
191
0
        nullptr));
192
0
  }
193
194
0
  unsigned int byte_length =
195
0
      CeilDiv(params.length, static_cast<size_t>(CHAR_BIT));
196
197
0
  std::vector<unsigned char> counter(
198
0
      data + params.iv.size() - byte_length,
199
0
      data + params.iv.size());
200
0
  counter[0] &= ~(0xFF << remainder);
201
202
0
  return BignumPointer(BN_bin2bn(counter.data(), counter.size(), nullptr));
203
0
}
204
205
std::vector<unsigned char> BlockWithZeroedCounter(
206
0
    const AESCipherConfig& params) {
207
0
  unsigned int length_bytes = params.length / CHAR_BIT;
208
0
  unsigned int remainder = params.length % CHAR_BIT;
209
210
0
  const unsigned char* data = params.iv.data<unsigned char>();
211
212
0
  std::vector<unsigned char> new_counter_block(data, data + params.iv.size());
213
214
0
  size_t index = new_counter_block.size() - length_bytes;
215
0
  memset(&new_counter_block.front() + index, 0, length_bytes);
216
217
0
  if (remainder)
218
0
    new_counter_block[index - 1] &= 0xFF << remainder;
219
220
0
  return new_counter_block;
221
0
}
222
223
WebCryptoCipherStatus AES_CTR_Cipher2(
224
    KeyObjectData* key_data,
225
    WebCryptoCipherMode cipher_mode,
226
    const AESCipherConfig& params,
227
    const ByteSource& in,
228
    unsigned const char* counter,
229
0
    unsigned char* out) {
230
0
  CipherCtxPointer ctx(EVP_CIPHER_CTX_new());
231
0
  const bool encrypt = cipher_mode == kWebCryptoCipherEncrypt;
232
233
0
  if (!EVP_CipherInit_ex(
234
0
          ctx.get(),
235
0
          params.cipher,
236
0
          nullptr,
237
0
          reinterpret_cast<const unsigned char*>(key_data->GetSymmetricKey()),
238
0
          counter,
239
0
          encrypt)) {
240
    // Cipher init failed
241
0
    return WebCryptoCipherStatus::FAILED;
242
0
  }
243
244
0
  int out_len = 0;
245
0
  int final_len = 0;
246
0
  if (!EVP_CipherUpdate(
247
0
          ctx.get(),
248
0
          out,
249
0
          &out_len,
250
0
          in.data<unsigned char>(),
251
0
          in.size())) {
252
0
    return WebCryptoCipherStatus::FAILED;
253
0
  }
254
255
0
  if (!EVP_CipherFinal_ex(ctx.get(), out + out_len, &final_len))
256
0
    return WebCryptoCipherStatus::FAILED;
257
258
0
  out_len += final_len;
259
0
  if (static_cast<unsigned>(out_len) != in.size())
260
0
    return WebCryptoCipherStatus::FAILED;
261
262
0
  return WebCryptoCipherStatus::OK;
263
0
}
264
265
WebCryptoCipherStatus AES_CTR_Cipher(
266
    Environment* env,
267
    KeyObjectData* key_data,
268
    WebCryptoCipherMode cipher_mode,
269
    const AESCipherConfig& params,
270
    const ByteSource& in,
271
0
    ByteSource* out) {
272
0
  BignumPointer num_counters(BN_new());
273
0
  if (!BN_lshift(num_counters.get(), BN_value_one(), params.length))
274
0
    return WebCryptoCipherStatus::FAILED;
275
276
0
  BignumPointer current_counter = GetCounter(params);
277
278
0
  BignumPointer num_output(BN_new());
279
280
0
  if (!BN_set_word(num_output.get(), CeilDiv(in.size(), kAesBlockSize)))
281
0
    return WebCryptoCipherStatus::FAILED;
282
283
  // Just like in chromium's implementation, if the counter will
284
  // be incremented more than there are counter values, we fail.
285
0
  if (BN_cmp(num_output.get(), num_counters.get()) > 0)
286
0
    return WebCryptoCipherStatus::FAILED;
287
288
0
  BignumPointer remaining_until_reset(BN_new());
289
0
  if (!BN_sub(remaining_until_reset.get(),
290
0
              num_counters.get(),
291
0
              current_counter.get())) {
292
0
    return WebCryptoCipherStatus::FAILED;
293
0
  }
294
295
  // Output size is identical to the input size.
296
0
  ByteSource::Builder buf(in.size());
297
298
  // Also just like in chromium's implementation, if we can process
299
  // the input without wrapping the counter, we'll do it as a single
300
  // call here. If we can't, we'll fallback to the a two-step approach
301
0
  if (BN_cmp(remaining_until_reset.get(), num_output.get()) >= 0) {
302
0
    auto status = AES_CTR_Cipher2(key_data,
303
0
                                  cipher_mode,
304
0
                                  params,
305
0
                                  in,
306
0
                                  params.iv.data<unsigned char>(),
307
0
                                  buf.data<unsigned char>());
308
0
    if (status == WebCryptoCipherStatus::OK) *out = std::move(buf).release();
309
0
    return status;
310
0
  }
311
312
0
  BN_ULONG blocks_part1 = BN_get_word(remaining_until_reset.get());
313
0
  BN_ULONG input_size_part1 = blocks_part1 * kAesBlockSize;
314
315
  // Encrypt the first part...
316
0
  auto status =
317
0
      AES_CTR_Cipher2(key_data,
318
0
                      cipher_mode,
319
0
                      params,
320
0
                      ByteSource::Foreign(in.data<char>(), input_size_part1),
321
0
                      params.iv.data<unsigned char>(),
322
0
                      buf.data<unsigned char>());
323
324
0
  if (status != WebCryptoCipherStatus::OK)
325
0
    return status;
326
327
  // Wrap the counter around to zero
328
0
  std::vector<unsigned char> new_counter_block = BlockWithZeroedCounter(params);
329
330
  // Encrypt the second part...
331
0
  status =
332
0
      AES_CTR_Cipher2(key_data,
333
0
                      cipher_mode,
334
0
                      params,
335
0
                      ByteSource::Foreign(in.data<char>() + input_size_part1,
336
0
                                          in.size() - input_size_part1),
337
0
                      new_counter_block.data(),
338
0
                      buf.data<unsigned char>() + input_size_part1);
339
340
0
  if (status == WebCryptoCipherStatus::OK) *out = std::move(buf).release();
341
342
0
  return status;
343
0
}
344
345
bool ValidateIV(
346
    Environment* env,
347
    CryptoJobMode mode,
348
    Local<Value> value,
349
0
    AESCipherConfig* params) {
350
0
  ArrayBufferOrViewContents<char> iv(value);
351
0
  if (UNLIKELY(!iv.CheckSizeInt32())) {
352
0
    THROW_ERR_OUT_OF_RANGE(env, "iv is too big");
353
0
    return false;
354
0
  }
355
0
  params->iv = (mode == kCryptoJobAsync)
356
0
      ? iv.ToCopy()
357
0
      : iv.ToByteSource();
358
0
  return true;
359
0
}
360
361
bool ValidateCounter(
362
  Environment* env,
363
  Local<Value> value,
364
0
  AESCipherConfig* params) {
365
0
  CHECK(value->IsUint32());  // Length
366
0
  params->length = value.As<Uint32>()->Value();
367
0
  if (params->iv.size() != 16 ||
368
0
      params->length == 0 ||
369
0
      params->length > 128) {
370
0
    THROW_ERR_CRYPTO_INVALID_COUNTER(env);
371
0
    return false;
372
0
  }
373
0
  return true;
374
0
}
375
376
bool ValidateAuthTag(
377
    Environment* env,
378
    CryptoJobMode mode,
379
    WebCryptoCipherMode cipher_mode,
380
    Local<Value> value,
381
0
    AESCipherConfig* params) {
382
0
  switch (cipher_mode) {
383
0
    case kWebCryptoCipherDecrypt: {
384
0
      if (!IsAnyBufferSource(value)) {
385
0
        THROW_ERR_CRYPTO_INVALID_TAG_LENGTH(env);
386
0
        return false;
387
0
      }
388
0
      ArrayBufferOrViewContents<char> tag_contents(value);
389
0
      if (UNLIKELY(!tag_contents.CheckSizeInt32())) {
390
0
        THROW_ERR_OUT_OF_RANGE(env, "tagLength is too big");
391
0
        return false;
392
0
      }
393
0
      params->tag = mode == kCryptoJobAsync
394
0
          ? tag_contents.ToCopy()
395
0
          : tag_contents.ToByteSource();
396
0
      break;
397
0
    }
398
0
    case kWebCryptoCipherEncrypt: {
399
0
      if (!value->IsUint32()) {
400
0
        THROW_ERR_CRYPTO_INVALID_TAG_LENGTH(env);
401
0
        return false;
402
0
      }
403
0
      params->length = value.As<Uint32>()->Value();
404
0
      if (params->length > 128) {
405
0
        THROW_ERR_CRYPTO_INVALID_TAG_LENGTH(env);
406
0
        return false;
407
0
      }
408
0
      break;
409
0
    }
410
0
    default:
411
0
      UNREACHABLE();
412
0
  }
413
0
  return true;
414
0
}
415
416
bool ValidateAdditionalData(
417
    Environment* env,
418
    CryptoJobMode mode,
419
    Local<Value> value,
420
0
    AESCipherConfig* params) {
421
  // Additional Data
422
0
  if (IsAnyBufferSource(value)) {
423
0
    ArrayBufferOrViewContents<char> additional(value);
424
0
    if (UNLIKELY(!additional.CheckSizeInt32())) {
425
0
      THROW_ERR_OUT_OF_RANGE(env, "additionalData is too big");
426
0
      return false;
427
0
    }
428
0
    params->additional_data = mode == kCryptoJobAsync
429
0
        ? additional.ToCopy()
430
0
        : additional.ToByteSource();
431
0
  }
432
0
  return true;
433
0
}
434
435
0
void UseDefaultIV(AESCipherConfig* params) {
436
0
  params->iv = ByteSource::Foreign(kDefaultWrapIV, strlen(kDefaultWrapIV));
437
0
}
438
}  // namespace
439
440
AESCipherConfig::AESCipherConfig(AESCipherConfig&& other) noexcept
441
0
    : mode(other.mode),
442
0
      variant(other.variant),
443
0
      cipher(other.cipher),
444
0
      length(other.length),
445
0
      iv(std::move(other.iv)),
446
0
      additional_data(std::move(other.additional_data)),
447
0
      tag(std::move(other.tag)) {}
448
449
0
AESCipherConfig& AESCipherConfig::operator=(AESCipherConfig&& other) noexcept {
450
0
  if (&other == this) return *this;
451
0
  this->~AESCipherConfig();
452
0
  return *new (this) AESCipherConfig(std::move(other));
453
0
}
454
455
0
void AESCipherConfig::MemoryInfo(MemoryTracker* tracker) const {
456
  // If mode is sync, then the data in each of these properties
457
  // is not owned by the AESCipherConfig, so we ignore it.
458
0
  if (mode == kCryptoJobAsync) {
459
0
    tracker->TrackFieldWithSize("iv", iv.size());
460
0
    tracker->TrackFieldWithSize("additional_data", additional_data.size());
461
0
    tracker->TrackFieldWithSize("tag", tag.size());
462
0
  }
463
0
}
464
465
Maybe<bool> AESCipherTraits::AdditionalConfig(
466
    CryptoJobMode mode,
467
    const FunctionCallbackInfo<Value>& args,
468
    unsigned int offset,
469
    WebCryptoCipherMode cipher_mode,
470
0
    AESCipherConfig* params) {
471
0
  Environment* env = Environment::GetCurrent(args);
472
473
0
  params->mode = mode;
474
475
0
  CHECK(args[offset]->IsUint32());  // Key Variant
476
0
  params->variant =
477
0
      static_cast<AESKeyVariant>(args[offset].As<Uint32>()->Value());
478
479
0
  int cipher_nid;
480
481
0
  switch (params->variant) {
482
0
    case kKeyVariantAES_CTR_128:
483
0
      if (!ValidateIV(env, mode, args[offset + 1], params) ||
484
0
          !ValidateCounter(env, args[offset + 2], params)) {
485
0
        return Nothing<bool>();
486
0
      }
487
0
      cipher_nid = NID_aes_128_ctr;
488
0
      break;
489
0
    case kKeyVariantAES_CTR_192:
490
0
      if (!ValidateIV(env, mode, args[offset + 1], params) ||
491
0
          !ValidateCounter(env, args[offset + 2], params)) {
492
0
        return Nothing<bool>();
493
0
      }
494
0
      cipher_nid = NID_aes_192_ctr;
495
0
      break;
496
0
    case kKeyVariantAES_CTR_256:
497
0
      if (!ValidateIV(env, mode, args[offset + 1], params) ||
498
0
          !ValidateCounter(env, args[offset + 2], params)) {
499
0
        return Nothing<bool>();
500
0
      }
501
0
      cipher_nid = NID_aes_256_ctr;
502
0
      break;
503
0
    case kKeyVariantAES_CBC_128:
504
0
      if (!ValidateIV(env, mode, args[offset + 1], params))
505
0
        return Nothing<bool>();
506
0
      cipher_nid = NID_aes_128_cbc;
507
0
      break;
508
0
    case kKeyVariantAES_CBC_192:
509
0
      if (!ValidateIV(env, mode, args[offset + 1], params))
510
0
        return Nothing<bool>();
511
0
      cipher_nid = NID_aes_192_cbc;
512
0
      break;
513
0
    case kKeyVariantAES_CBC_256:
514
0
      if (!ValidateIV(env, mode, args[offset + 1], params))
515
0
        return Nothing<bool>();
516
0
      cipher_nid = NID_aes_256_cbc;
517
0
      break;
518
0
    case kKeyVariantAES_KW_128:
519
0
      UseDefaultIV(params);
520
0
      cipher_nid = NID_id_aes128_wrap;
521
0
      break;
522
0
    case kKeyVariantAES_KW_192:
523
0
      UseDefaultIV(params);
524
0
      cipher_nid = NID_id_aes192_wrap;
525
0
      break;
526
0
    case kKeyVariantAES_KW_256:
527
0
      UseDefaultIV(params);
528
0
      cipher_nid = NID_id_aes256_wrap;
529
0
      break;
530
0
    case kKeyVariantAES_GCM_128:
531
0
      if (!ValidateIV(env, mode, args[offset + 1], params) ||
532
0
          !ValidateAuthTag(env, mode, cipher_mode, args[offset + 2], params) ||
533
0
          !ValidateAdditionalData(env, mode, args[offset + 3], params)) {
534
0
        return Nothing<bool>();
535
0
      }
536
0
      cipher_nid = NID_aes_128_gcm;
537
0
      break;
538
0
    case kKeyVariantAES_GCM_192:
539
0
      if (!ValidateIV(env, mode, args[offset + 1], params) ||
540
0
          !ValidateAuthTag(env, mode, cipher_mode, args[offset + 2], params) ||
541
0
          !ValidateAdditionalData(env, mode, args[offset + 3], params)) {
542
0
        return Nothing<bool>();
543
0
      }
544
0
      cipher_nid = NID_aes_192_gcm;
545
0
      break;
546
0
    case kKeyVariantAES_GCM_256:
547
0
      if (!ValidateIV(env, mode, args[offset + 1], params) ||
548
0
          !ValidateAuthTag(env, mode, cipher_mode, args[offset + 2], params) ||
549
0
          !ValidateAdditionalData(env, mode, args[offset + 3], params)) {
550
0
        return Nothing<bool>();
551
0
      }
552
0
      cipher_nid = NID_aes_256_gcm;
553
0
      break;
554
0
    default:
555
0
      UNREACHABLE();
556
0
  }
557
558
0
  params->cipher = EVP_get_cipherbynid(cipher_nid);
559
0
  if (params->cipher == nullptr) {
560
0
    THROW_ERR_CRYPTO_UNKNOWN_CIPHER(env);
561
0
    return Nothing<bool>();
562
0
  }
563
564
0
  if (params->iv.size() <
565
0
      static_cast<size_t>(EVP_CIPHER_iv_length(params->cipher))) {
566
0
    THROW_ERR_CRYPTO_INVALID_IV(env);
567
0
    return Nothing<bool>();
568
0
  }
569
570
0
  return Just(true);
571
0
}
572
573
WebCryptoCipherStatus AESCipherTraits::DoCipher(
574
    Environment* env,
575
    std::shared_ptr<KeyObjectData> key_data,
576
    WebCryptoCipherMode cipher_mode,
577
    const AESCipherConfig& params,
578
    const ByteSource& in,
579
0
    ByteSource* out) {
580
0
#define V(name, fn)                                                           \
581
0
  case kKeyVariantAES_ ## name:                                               \
582
0
    return fn(env, key_data.get(), cipher_mode, params, in, out);
583
0
  switch (params.variant) {
584
0
    VARIANTS(V)
585
0
    default:
586
0
      UNREACHABLE();
587
0
  }
588
0
#undef V
589
0
}
590
591
8.84k
void AES::Initialize(Environment* env, Local<Object> target) {
592
8.84k
  AESCryptoJob::Initialize(env, target);
593
594
106k
#define V(name, _) NODE_DEFINE_CONSTANT(target, kKeyVariantAES_ ## name);
595
106k
  VARIANTS(V)
596
8.84k
#undef V
597
8.84k
}
598
599
0
void AES::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
600
0
  AESCryptoJob::RegisterExternalReferences(registry);
601
0
}
602
603
}  // namespace crypto
604
}  // namespace node