/src/node/src/crypto/crypto_kmac.cc
Line  | Count  | Source  | 
1  |  | #include "crypto/crypto_kmac.h"  | 
2  |  | #include "async_wrap-inl.h"  | 
3  |  | #include "node_internals.h"  | 
4  |  | #include "threadpoolwork-inl.h"  | 
5  |  |  | 
6  |  | #if OPENSSL_VERSION_MAJOR >= 3  | 
7  |  | #include <openssl/core_names.h>  | 
8  |  | #include <openssl/params.h>  | 
9  |  | #include "crypto/crypto_keys.h"  | 
10  |  | #include "crypto/crypto_sig.h"  | 
11  |  | #include "ncrypto.h"  | 
12  |  |  | 
13  |  | namespace node::crypto { | 
14  |  |  | 
15  |  | using ncrypto::EVPMacCtxPointer;  | 
16  |  | using ncrypto::EVPMacPointer;  | 
17  |  | using node::Utf8Value;  | 
18  |  | using v8::Boolean;  | 
19  |  | using v8::FunctionCallbackInfo;  | 
20  |  | using v8::JustVoid;  | 
21  |  | using v8::Local;  | 
22  |  | using v8::Maybe;  | 
23  |  | using v8::MaybeLocal;  | 
24  |  | using v8::Nothing;  | 
25  |  | using v8::Object;  | 
26  |  | using v8::Uint32;  | 
27  |  | using v8::Value;  | 
28  |  |  | 
29  |  | KmacConfig::KmacConfig(KmacConfig&& other) noexcept  | 
30  | 0  |     : job_mode(other.job_mode),  | 
31  | 0  |       mode(other.mode),  | 
32  | 0  |       key(std::move(other.key)),  | 
33  | 0  |       data(std::move(other.data)),  | 
34  | 0  |       signature(std::move(other.signature)),  | 
35  | 0  |       customization(std::move(other.customization)),  | 
36  | 0  |       variant(other.variant),  | 
37  | 0  |       length(other.length) {} | 
38  |  |  | 
39  | 0  | KmacConfig& KmacConfig::operator=(KmacConfig&& other) noexcept { | 
40  | 0  |   if (&other == this) return *this;  | 
41  | 0  |   this->~KmacConfig();  | 
42  | 0  |   return *new (this) KmacConfig(std::move(other));  | 
43  | 0  | }  | 
44  |  |  | 
45  | 0  | void KmacConfig::MemoryInfo(MemoryTracker* tracker) const { | 
46  | 0  |   tracker->TrackField("key", key); | 
47  |  |   // If the job is sync, then the KmacConfig does not own the data.  | 
48  | 0  |   if (job_mode == kCryptoJobAsync) { | 
49  | 0  |     tracker->TrackFieldWithSize("data", data.size()); | 
50  | 0  |     tracker->TrackFieldWithSize("signature", signature.size()); | 
51  | 0  |     tracker->TrackFieldWithSize("customization", customization.size()); | 
52  | 0  |   }  | 
53  | 0  | }  | 
54  |  |  | 
55  |  | Maybe<void> KmacTraits::AdditionalConfig(  | 
56  |  |     CryptoJobMode mode,  | 
57  |  |     const FunctionCallbackInfo<Value>& args,  | 
58  |  |     unsigned int offset,  | 
59  | 0  |     KmacConfig* params) { | 
60  | 0  |   Environment* env = Environment::GetCurrent(args);  | 
61  |  | 
  | 
62  | 0  |   params->job_mode = mode;  | 
63  |  | 
  | 
64  | 0  |   CHECK(args[offset]->IsUint32());  // SignConfiguration::Mode  | 
65  | 0  |   params->mode =  | 
66  | 0  |       static_cast<SignConfiguration::Mode>(args[offset].As<Uint32>()->Value());  | 
67  |  | 
  | 
68  | 0  |   CHECK(args[offset + 1]->IsObject());  // Key  | 
69  | 0  |   KeyObjectHandle* key;  | 
70  | 0  |   ASSIGN_OR_RETURN_UNWRAP(&key, args[offset + 1], Nothing<void>());  | 
71  | 0  |   params->key = key->Data().addRef();  | 
72  |  | 
  | 
73  | 0  |   CHECK(args[offset + 2]->IsString());  // Algorithm name  | 
74  | 0  |   Utf8Value algorithm_name(env->isolate(), args[offset + 2]);  | 
75  | 0  |   std::string_view algorithm_str = algorithm_name.ToStringView();  | 
76  |  |  | 
77  |  |   // Convert string to enum and validate  | 
78  | 0  |   if (algorithm_str == OSSL_MAC_NAME_KMAC128) { | 
79  | 0  |     params->variant = KmacVariant::KMAC128;  | 
80  | 0  |   } else if (algorithm_str == OSSL_MAC_NAME_KMAC256) { | 
81  | 0  |     params->variant = KmacVariant::KMAC256;  | 
82  | 0  |   } else { | 
83  | 0  |     UNREACHABLE();  | 
84  | 0  |   }  | 
85  |  |  | 
86  |  |   // Customization string (may be empty or undefined).  | 
87  | 0  |   if (!args[offset + 3]->IsUndefined()) { | 
88  | 0  |     ArrayBufferOrViewContents<char> customization(args[offset + 3]);  | 
89  | 0  |     if (!customization.CheckSizeInt32()) [[unlikely]] { | 
90  | 0  |       THROW_ERR_OUT_OF_RANGE(env, "customization is too big");  | 
91  | 0  |       return Nothing<void>();  | 
92  | 0  |     }  | 
93  | 0  |     params->customization = mode == kCryptoJobAsync  | 
94  | 0  |                                 ? customization.ToCopy()  | 
95  | 0  |                                 : customization.ToByteSource();  | 
96  | 0  |   }  | 
97  |  |   // If undefined, params->customization remains uninitialized (size 0).  | 
98  |  |  | 
99  | 0  |   CHECK(args[offset + 4]->IsUint32());  // Length  | 
100  | 0  |   params->length = args[offset + 4].As<Uint32>()->Value();  | 
101  |  | 
  | 
102  | 0  |   ArrayBufferOrViewContents<char> data(args[offset + 5]);  | 
103  | 0  |   if (!data.CheckSizeInt32()) [[unlikely]] { | 
104  | 0  |     THROW_ERR_OUT_OF_RANGE(env, "data is too big");  | 
105  | 0  |     return Nothing<void>();  | 
106  | 0  |   }  | 
107  | 0  |   params->data = mode == kCryptoJobAsync ? data.ToCopy() : data.ToByteSource();  | 
108  |  | 
  | 
109  | 0  |   if (!args[offset + 6]->IsUndefined()) { | 
110  | 0  |     ArrayBufferOrViewContents<char> signature(args[offset + 6]);  | 
111  | 0  |     if (!signature.CheckSizeInt32()) [[unlikely]] { | 
112  | 0  |       THROW_ERR_OUT_OF_RANGE(env, "signature is too big");  | 
113  | 0  |       return Nothing<void>();  | 
114  | 0  |     }  | 
115  | 0  |     params->signature =  | 
116  | 0  |         mode == kCryptoJobAsync ? signature.ToCopy() : signature.ToByteSource();  | 
117  | 0  |   }  | 
118  |  |  | 
119  | 0  |   return JustVoid();  | 
120  | 0  | }  | 
121  |  |  | 
122  |  | bool KmacTraits::DeriveBits(Environment* env,  | 
123  |  |                             const KmacConfig& params,  | 
124  |  |                             ByteSource* out,  | 
125  | 0  |                             CryptoJobMode mode) { | 
126  | 0  |   if (params.length == 0) { | 
127  | 0  |     *out = ByteSource();  | 
128  | 0  |     return true;  | 
129  | 0  |   }  | 
130  |  |  | 
131  |  |   // Get the key data.  | 
132  | 0  |   const void* key_data = params.key.GetSymmetricKey();  | 
133  | 0  |   size_t key_size = params.key.GetSymmetricKeySize();  | 
134  |  | 
  | 
135  | 0  |   if (key_size == 0) { | 
136  | 0  |     return false;  | 
137  | 0  |   }  | 
138  |  |  | 
139  |  |   // Fetch the KMAC algorithm  | 
140  | 0  |   auto mac = EVPMacPointer::Fetch((params.variant == KmacVariant::KMAC128)  | 
141  | 0  |                                       ? OSSL_MAC_NAME_KMAC128  | 
142  | 0  |                                       : OSSL_MAC_NAME_KMAC256);  | 
143  | 0  |   if (!mac) { | 
144  | 0  |     return false;  | 
145  | 0  |   }  | 
146  |  |  | 
147  |  |   // Create MAC context  | 
148  | 0  |   auto mac_ctx = EVPMacCtxPointer::New(mac.get());  | 
149  | 0  |   if (!mac_ctx) { | 
150  | 0  |     return false;  | 
151  | 0  |   }  | 
152  |  |  | 
153  |  |   // Set up parameters.  | 
154  | 0  |   OSSL_PARAM params_array[3];  // Max 3: size + customization + end  | 
155  | 0  |   size_t params_count = 0;  | 
156  |  |  | 
157  |  |   // Set output length (always required for KMAC).  | 
158  | 0  |   size_t outlen = params.length;  | 
159  | 0  |   params_array[params_count++] =  | 
160  | 0  |       OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_SIZE, &outlen);  | 
161  |  |  | 
162  |  |   // Set customization if provided.  | 
163  | 0  |   if (params.customization.size() > 0) { | 
164  | 0  |     params_array[params_count++] = OSSL_PARAM_construct_octet_string(  | 
165  | 0  |         OSSL_MAC_PARAM_CUSTOM,  | 
166  | 0  |         const_cast<void*>(params.customization.data()),  | 
167  | 0  |         params.customization.size());  | 
168  | 0  |   }  | 
169  |  | 
  | 
170  | 0  |   params_array[params_count] = OSSL_PARAM_construct_end();  | 
171  |  |  | 
172  |  |   // Initialize the MAC context.  | 
173  | 0  |   if (!mac_ctx.init(ncrypto::Buffer<const void>(key_data, key_size),  | 
174  | 0  |                     params_array)) { | 
175  | 0  |     return false;  | 
176  | 0  |   }  | 
177  |  |  | 
178  |  |   // Update with data.  | 
179  | 0  |   if (!mac_ctx.update(ncrypto::Buffer<const void>(params.data.data(),  | 
180  | 0  |                                                   params.data.size()))) { | 
181  | 0  |     return false;  | 
182  | 0  |   }  | 
183  |  |  | 
184  |  |   // Finalize and get the result.  | 
185  | 0  |   auto result = mac_ctx.final(params.length);  | 
186  | 0  |   if (!result) { | 
187  | 0  |     return false;  | 
188  | 0  |   }  | 
189  |  |  | 
190  | 0  |   auto buffer = result.release();  | 
191  | 0  |   *out = ByteSource::Allocated(buffer.data, buffer.len);  | 
192  | 0  |   return true;  | 
193  | 0  | }  | 
194  |  |  | 
195  |  | MaybeLocal<Value> KmacTraits::EncodeOutput(Environment* env,  | 
196  |  |                                            const KmacConfig& params,  | 
197  | 0  |                                            ByteSource* out) { | 
198  | 0  |   switch (params.mode) { | 
199  | 0  |     case SignConfiguration::Mode::Sign:  | 
200  | 0  |       return out->ToArrayBuffer(env);  | 
201  | 0  |     case SignConfiguration::Mode::Verify:  | 
202  | 0  |       return Boolean::New(  | 
203  | 0  |           env->isolate(),  | 
204  | 0  |           out->size() > 0 && out->size() == params.signature.size() &&  | 
205  | 0  |               memcmp(out->data(), params.signature.data(), out->size()) == 0);  | 
206  | 0  |   }  | 
207  | 0  |   UNREACHABLE();  | 
208  | 0  | }  | 
209  |  |  | 
210  | 0  | void Kmac::Initialize(Environment* env, Local<Object> target) { | 
211  | 0  |   KmacJob::Initialize(env, target);  | 
212  | 0  | }  | 
213  |  |  | 
214  | 0  | void Kmac::RegisterExternalReferences(ExternalReferenceRegistry* registry) { | 
215  | 0  |   KmacJob::RegisterExternalReferences(registry);  | 
216  | 0  | }  | 
217  |  |  | 
218  |  | }  // namespace node::crypto  | 
219  |  |  | 
220  |  | #endif  |