Coverage Report

Created: 2025-12-10 07:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/crypto/crypto_hkdf.cc
Line
Count
Source
1
#include "crypto/crypto_hkdf.h"
2
#include "async_wrap-inl.h"
3
#include "base_object-inl.h"
4
#include "crypto/crypto_keys.h"
5
#include "env-inl.h"
6
#include "memory_tracker-inl.h"
7
#include "threadpoolwork-inl.h"
8
#include "v8.h"
9
10
namespace node {
11
12
using ncrypto::Digest;
13
using v8::FunctionCallbackInfo;
14
using v8::JustVoid;
15
using v8::Maybe;
16
using v8::MaybeLocal;
17
using v8::Nothing;
18
using v8::Uint32;
19
using v8::Value;
20
21
namespace crypto {
22
HKDFConfig::HKDFConfig(HKDFConfig&& other) noexcept
23
0
    : mode(other.mode),
24
0
      length(other.length),
25
0
      digest(other.digest),
26
0
      key(std::move(other.key)),
27
0
      salt(std::move(other.salt)),
28
0
      info(std::move(other.info)) {}
29
30
0
HKDFConfig& HKDFConfig::operator=(HKDFConfig&& other) noexcept {
31
0
  if (&other == this) return *this;
32
0
  this->~HKDFConfig();
33
0
  return *new (this) HKDFConfig(std::move(other));
34
0
}
35
36
MaybeLocal<Value> HKDFTraits::EncodeOutput(Environment* env,
37
                                           const HKDFConfig& params,
38
0
                                           ByteSource* out) {
39
0
  return out->ToArrayBuffer(env);
40
0
}
41
42
Maybe<void> HKDFTraits::AdditionalConfig(
43
    CryptoJobMode mode,
44
    const FunctionCallbackInfo<Value>& args,
45
    unsigned int offset,
46
0
    HKDFConfig* params) {
47
0
  Environment* env = Environment::GetCurrent(args);
48
49
0
  params->mode = mode;
50
51
0
  CHECK(args[offset]->IsString());  // Hash
52
0
  CHECK(args[offset + 1]->IsObject());  // Key
53
0
  CHECK(IsAnyBufferSource(args[offset + 2]));  // Salt
54
0
  CHECK(IsAnyBufferSource(args[offset + 3]));  // Info
55
0
  CHECK(args[offset + 4]->IsUint32());  // Length
56
57
0
  Utf8Value hash(env->isolate(), args[offset]);
58
0
  params->digest = Digest::FromName(*hash);
59
0
  if (!params->digest) [[unlikely]] {
60
0
    THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", hash);
61
0
    return Nothing<void>();
62
0
  }
63
64
0
  KeyObjectHandle* key;
65
0
  ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing<void>());
66
0
  params->key = key->Data().addRef();
67
68
0
  ArrayBufferOrViewContents<char> salt(args[offset + 2]);
69
0
  ArrayBufferOrViewContents<char> info(args[offset + 3]);
70
71
0
  if (!salt.CheckSizeInt32()) [[unlikely]] {
72
0
    THROW_ERR_OUT_OF_RANGE(env, "salt is too big");
73
0
    return Nothing<void>();
74
0
  }
75
0
  if (!info.CheckSizeInt32()) [[unlikely]] {
76
0
    THROW_ERR_OUT_OF_RANGE(env, "info is too big");
77
0
    return Nothing<void>();
78
0
  }
79
80
0
  params->salt = mode == kCryptoJobAsync
81
0
      ? salt.ToCopy()
82
0
      : salt.ToByteSource();
83
84
0
  params->info = mode == kCryptoJobAsync
85
0
      ? info.ToCopy()
86
0
      : info.ToByteSource();
87
88
0
  params->length = args[offset + 4].As<Uint32>()->Value();
89
  // HKDF-Expand computes up to 255 HMAC blocks, each having as many bits as the
90
  // output of the hash function. 255 is a hard limit because HKDF appends an
91
  // 8-bit counter to each HMAC'd message, starting at 1.
92
0
  if (!ncrypto::checkHkdfLength(params->digest, params->length)) [[unlikely]] {
93
0
    THROW_ERR_CRYPTO_INVALID_KEYLEN(env);
94
0
    return Nothing<void>();
95
0
  }
96
97
0
  return JustVoid();
98
0
}
99
100
bool HKDFTraits::DeriveBits(Environment* env,
101
                            const HKDFConfig& params,
102
                            ByteSource* out,
103
0
                            CryptoJobMode mode) {
104
0
  auto dp = ncrypto::hkdf(params.digest,
105
0
                          ncrypto::Buffer<const unsigned char>{
106
0
                              .data = reinterpret_cast<const unsigned char*>(
107
0
                                  params.key.GetSymmetricKey()),
108
0
                              .len = params.key.GetSymmetricKeySize(),
109
0
                          },
110
0
                          ncrypto::Buffer<const unsigned char>{
111
0
                              .data = params.info.data<const unsigned char>(),
112
0
                              .len = params.info.size(),
113
0
                          },
114
0
                          ncrypto::Buffer<const unsigned char>{
115
0
                              .data = params.salt.data<const unsigned char>(),
116
0
                              .len = params.salt.size(),
117
0
                          },
118
0
                          params.length);
119
0
  if (!dp) return false;
120
121
0
  DCHECK(!dp.isSecure());
122
0
  *out = ByteSource::Allocated(dp.release());
123
0
  return true;
124
0
}
125
126
0
void HKDFConfig::MemoryInfo(MemoryTracker* tracker) const {
127
0
  tracker->TrackField("key", key);
128
  // If the job is sync, then the HKDFConfig does not own the data
129
0
  if (mode == kCryptoJobAsync) {
130
0
    tracker->TrackFieldWithSize("salt", salt.size());
131
0
    tracker->TrackFieldWithSize("info", info.size());
132
0
  }
133
0
}
134
135
}  // namespace crypto
136
}  // namespace node