/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 |