88#include " crypto/crypto_util.h"
99#include " env-inl.h"
1010#include " memory_tracker-inl.h"
11- #include " node_buffer.h"
1211#include " threadpoolwork-inl.h"
1312#include " v8.h"
1413
1514namespace node {
1615
1716using ncrypto::EVPKeyPointer;
1817using v8::Array;
19- using v8::ArrayBufferView;
2018using v8::FunctionCallbackInfo;
2119using v8::Local;
2220using v8::Maybe;
2321using v8::MaybeLocal;
2422using v8::Nothing;
2523using v8::Object;
24+ using v8::Uint8Array;
2625using v8::Value;
2726
2827namespace crypto {
@@ -49,51 +48,6 @@ void KEMConfiguration::MemoryInfo(MemoryTracker* tracker) const {
4948
5049namespace {
5150
52- bool DoKEMEncapsulate (Environment* env,
53- const EVPKeyPointer& public_key,
54- ByteSource* out,
55- CryptoJobMode mode) {
56- auto result = ncrypto::KEM::Encapsulate (public_key);
57- if (!result) {
58- if (mode == kCryptoJobSync ) {
59- THROW_ERR_CRYPTO_OPERATION_FAILED (env, " Failed to perform encapsulation" );
60- }
61- return false ;
62- }
63-
64- // Pack the result: [ciphertext_len][shared_key_len][ciphertext][shared_key]
65- size_t ciphertext_len = result->ciphertext .size ();
66- size_t shared_key_len = result->shared_key .size ();
67- size_t total_len =
68- sizeof (uint32_t ) + sizeof (uint32_t ) + ciphertext_len + shared_key_len;
69-
70- auto data = ncrypto::DataPointer::Alloc (total_len);
71- if (!data) {
72- if (mode == kCryptoJobSync ) {
73- THROW_ERR_CRYPTO_OPERATION_FAILED (env,
74- " Failed to allocate output buffer" );
75- }
76- return false ;
77- }
78-
79- unsigned char * ptr = static_cast <unsigned char *>(data.get ());
80-
81- // Write size headers
82- *reinterpret_cast <uint32_t *>(ptr) = static_cast <uint32_t >(ciphertext_len);
83- *reinterpret_cast <uint32_t *>(ptr + sizeof (uint32_t )) =
84- static_cast <uint32_t >(shared_key_len);
85-
86- // Write ciphertext and shared key data
87- unsigned char * ciphertext_ptr = ptr + 2 * sizeof (uint32_t );
88- unsigned char * shared_key_ptr = ciphertext_ptr + ciphertext_len;
89-
90- std::memcpy (ciphertext_ptr, result->ciphertext .get (), ciphertext_len);
91- std::memcpy (shared_key_ptr, result->shared_key .get (), shared_key_len);
92-
93- *out = ByteSource::Allocated (data.release ());
94- return true ;
95- }
96-
9751bool DoKEMDecapsulate (Environment* env,
9852 const EVPKeyPointer& private_key,
9953 const ByteSource& ciphertext,
@@ -135,71 +89,115 @@ Maybe<void> KEMEncapsulateTraits::AdditionalConfig(
13589 return v8::JustVoid ();
13690}
13791
138- bool KEMEncapsulateTraits::DeriveBits (Environment* env,
139- const KEMConfiguration& params,
140- ByteSource* out,
141- CryptoJobMode mode) {
142- Mutex::ScopedLock lock (params.key .mutex ());
143- const auto & public_key = params.key .GetAsymmetricKey ();
92+ void KEMEncapsulateJob::New (const FunctionCallbackInfo<Value>& args) {
93+ Environment* env = Environment::GetCurrent (args);
94+ CHECK (args.IsConstructCall ());
95+
96+ CryptoJobMode mode = GetCryptoJobMode (args[0 ]);
97+ AdditionalParams params;
98+ if (KEMEncapsulateTraits::AdditionalConfig (mode, args, 1 , ¶ms)
99+ .IsNothing ()) {
100+ return ;
101+ }
144102
145- return DoKEMEncapsulate (env, public_key, out, mode );
103+ new KEMEncapsulateJob (env, args. This (), mode, std::move (params) );
146104}
147105
148- MaybeLocal<Value> KEMEncapsulateTraits::EncodeOutput (
149- Environment* env, const KEMConfiguration& params, ByteSource* out) {
150- // The output contains:
151- // [ciphertext_len][shared_key_len][ciphertext][shared_key]
152- const unsigned char * data = out->data <unsigned char >();
153-
154- uint32_t ciphertext_len = *reinterpret_cast <const uint32_t *>(data);
155- uint32_t shared_key_len =
156- *reinterpret_cast <const uint32_t *>(data + sizeof (uint32_t ));
157-
158- const unsigned char * ciphertext_ptr = data + 2 * sizeof (uint32_t );
159- const unsigned char * shared_key_ptr = ciphertext_ptr + ciphertext_len;
160-
161- MaybeLocal<Object> ciphertext_buf =
162- node::Buffer::Copy (env->isolate (),
163- reinterpret_cast <const char *>(ciphertext_ptr),
164- ciphertext_len);
165-
166- MaybeLocal<Object> shared_key_buf =
167- node::Buffer::Copy (env->isolate (),
168- reinterpret_cast <const char *>(shared_key_ptr),
169- shared_key_len);
170-
171- Local<Object> ciphertext_obj;
172- Local<Object> shared_key_obj;
173- if (!ciphertext_buf.ToLocal (&ciphertext_obj) ||
174- !shared_key_buf.ToLocal (&shared_key_obj)) {
175- return MaybeLocal<Value>();
106+ void KEMEncapsulateJob::Initialize (Environment* env, Local<Object> target) {
107+ CryptoJob<KEMEncapsulateTraits>::Initialize (New, env, target);
108+ }
109+
110+ void KEMEncapsulateJob::RegisterExternalReferences (
111+ ExternalReferenceRegistry* registry) {
112+ CryptoJob<KEMEncapsulateTraits>::RegisterExternalReferences (New, registry);
113+ }
114+
115+ KEMEncapsulateJob::KEMEncapsulateJob (Environment* env,
116+ Local<Object> object,
117+ CryptoJobMode mode,
118+ AdditionalParams&& params)
119+ : CryptoJob<KEMEncapsulateTraits>(env,
120+ object,
121+ KEMEncapsulateTraits::Provider,
122+ mode,
123+ std::move (params)) {}
124+
125+ void KEMEncapsulateJob::DoThreadPoolWork () {
126+ ncrypto::ClearErrorOnReturn clear_error_on_return;
127+ AdditionalParams* params = CryptoJob<KEMEncapsulateTraits>::params ();
128+ Mutex::ScopedLock lock (params->key .mutex ());
129+ out_ = ncrypto::KEM::Encapsulate (params->key .GetAsymmetricKey ());
130+ if (!out_) {
131+ if (mode () == kCryptoJobSync ) {
132+ THROW_ERR_CRYPTO_OPERATION_FAILED (AsyncWrap::env (),
133+ " Failed to perform encapsulation" );
134+ }
135+ CryptoErrorStore* errors = CryptoJob<KEMEncapsulateTraits>::errors ();
136+ errors->Capture ();
137+ if (errors->Empty ()) {
138+ errors->Insert (NodeCryptoError::DERIVING_BITS_FAILED );
139+ }
176140 }
141+ }
177142
178- if (params.job_mode == kCryptoJobWebCrypto ) {
179- Local<Object> result = Object::New (env->isolate ());
180- if (!result
143+ Maybe<void > KEMEncapsulateJob::ToResult (Local<Value>* err,
144+ Local<Value>* result) {
145+ Environment* env = AsyncWrap::env ();
146+ CryptoErrorStore* errors = CryptoJob<KEMEncapsulateTraits>::errors ();
147+ if (!out_) {
148+ if (errors->Empty ()) errors->Capture ();
149+ CHECK (!errors->Empty ());
150+ *result = v8::Undefined (env->isolate ());
151+ if (!errors->ToException (env).ToLocal (err)) return Nothing<void >();
152+ return v8::JustVoid ();
153+ }
154+
155+ CHECK (errors->Empty ());
156+ *err = v8::Undefined (env->isolate ());
157+
158+ ByteSource ciphertext = ByteSource::Allocated (out_->ciphertext .release ());
159+ ByteSource shared_key = ByteSource::Allocated (out_->shared_key .release ());
160+
161+ if (mode () == kCryptoJobWebCrypto ) {
162+ Local<Object> output = Object::New (env->isolate ());
163+ if (!output
181164 ->DefineOwnProperty (env->context (),
182165 OneByteString (env->isolate (), " sharedKey" ),
183- shared_key_obj. As <ArrayBufferView>()-> Buffer ( ))
166+ shared_key. ToArrayBuffer (env ))
184167 .FromMaybe (false ) ||
185- !result
168+ !output
186169 ->DefineOwnProperty (env->context (),
187170 OneByteString (env->isolate (), " ciphertext" ),
188- ciphertext_obj. As <ArrayBufferView>()-> Buffer ( ))
171+ ciphertext. ToArrayBuffer (env ))
189172 .FromMaybe (false )) {
190- return MaybeLocal<Value >();
173+ return Nothing< void >();
191174 }
192- return result;
175+ *result = output;
176+ return v8::JustVoid ();
193177 }
194178
195- // Return an array [sharedKey, ciphertext].
196- Local<Array> result = Array::New (env-> isolate (), 2 ) ;
197- if (result-> Set (env-> context (), 0 , shared_key_obj). IsNothing ( ) ||
198- result-> Set (env-> context (), 1 , ciphertext_obj). IsNothing ( )) {
199- return MaybeLocal<Value >();
179+ Local<Uint8Array> shared_key_buf;
180+ Local<Uint8Array> ciphertext_buf ;
181+ if (!shared_key. ToBuffer (env). ToLocal (&shared_key_buf ) ||
182+ !ciphertext. ToBuffer (env). ToLocal (&ciphertext_buf )) {
183+ return Nothing< void >();
200184 }
201185
202- return result;
186+ Local<Array> output = Array::New (env->isolate (), 2 );
187+ if (output->Set (env->context (), 0 , shared_key_buf).IsNothing () ||
188+ output->Set (env->context (), 1 , ciphertext_buf).IsNothing ()) {
189+ return Nothing<void >();
190+ }
191+ *result = output;
192+ return v8::JustVoid ();
193+ }
194+
195+ void KEMEncapsulateJob::MemoryInfo (MemoryTracker* tracker) const {
196+ if (out_) {
197+ tracker->TrackFieldWithSize (" ciphertext" , out_->ciphertext .size ());
198+ tracker->TrackFieldWithSize (" shared_key" , out_->shared_key .size ());
199+ }
200+ CryptoJob<KEMEncapsulateTraits>::MemoryInfo (tracker);
203201}
204202
205203// KEMDecapsulateTraits implementation
0 commit comments