@@ -23,6 +23,7 @@ using v8::MaybeLocal;
23
23
using v8::Name;
24
24
using v8::Nothing;
25
25
using v8::Object;
26
+ using v8::String;
26
27
using v8::Uint32;
27
28
using v8::Value;
28
29
@@ -202,6 +203,71 @@ const EVP_MD* GetDigestImplementation(Environment* env,
202
203
#endif
203
204
}
204
205
206
+ // crypto.digest(algorithm, algorithmId, algorithmCache,
207
+ // input, outputEncoding, outputEncodingId)
208
+ void Hash::OneShotDigest (const FunctionCallbackInfo<Value>& args) {
209
+ Environment* env = Environment::GetCurrent (args);
210
+ Isolate* isolate = env->isolate ();
211
+ CHECK_EQ (args.Length (), 6 );
212
+ CHECK (args[0 ]->IsString ()); // algorithm
213
+ CHECK (args[1 ]->IsInt32 ()); // algorithmId
214
+ CHECK (args[2 ]->IsObject ()); // algorithmCache
215
+ CHECK (args[3 ]->IsString () || args[3 ]->IsArrayBufferView ()); // input
216
+ CHECK (args[4 ]->IsString ()); // outputEncoding
217
+ CHECK (args[5 ]->IsUint32 () || args[5 ]->IsUndefined ()); // outputEncodingId
218
+
219
+ const EVP_MD* md = GetDigestImplementation (env, args[0 ], args[1 ], args[2 ]);
220
+ if (md == nullptr ) {
221
+ Utf8Value method (isolate, args[0 ]);
222
+ std::string message =
223
+ " Digest method " + method.ToString () + " is not supported" ;
224
+ return ThrowCryptoError (env, ERR_get_error (), message.c_str ());
225
+ }
226
+
227
+ enum encoding output_enc = ParseEncoding (isolate, args[4 ], args[5 ], HEX);
228
+
229
+ int md_len = EVP_MD_size (md);
230
+ unsigned int result_size;
231
+ ByteSource::Builder output (md_len);
232
+ int success;
233
+ // On smaller inputs, EVP_Digest() can be slower than the
234
+ // deprecated helpers e.g SHA256_XXX. The speedup may not
235
+ // be worth using deprecated APIs, however, so we use
236
+ // EVP_Digest(), unless there's a better alternative
237
+ // in the future.
238
+ // https://github.com/openssl/openssl/issues/19612
239
+ if (args[3 ]->IsString ()) {
240
+ Utf8Value utf8 (isolate, args[3 ]);
241
+ success = EVP_Digest (utf8.out (),
242
+ utf8.length (),
243
+ output.data <unsigned char >(),
244
+ &result_size,
245
+ md,
246
+ nullptr );
247
+ } else {
248
+ ArrayBufferViewContents<unsigned char > input (args[3 ]);
249
+ success = EVP_Digest (input.data (),
250
+ input.length (),
251
+ output.data <unsigned char >(),
252
+ &result_size,
253
+ md,
254
+ nullptr );
255
+ }
256
+ if (!success) {
257
+ return ThrowCryptoError (env, ERR_get_error ());
258
+ }
259
+
260
+ Local<Value> error;
261
+ MaybeLocal<Value> rc = StringBytes::Encode (
262
+ env->isolate (), output.data <char >(), md_len, output_enc, &error);
263
+ if (rc.IsEmpty ()) {
264
+ CHECK (!error.IsEmpty ());
265
+ env->isolate ()->ThrowException (error);
266
+ return ;
267
+ }
268
+ args.GetReturnValue ().Set (rc.FromMaybe (Local<Value>()));
269
+ }
270
+
205
271
void Hash::Initialize (Environment* env, Local<Object> target) {
206
272
Isolate* isolate = env->isolate ();
207
273
Local<Context> context = env->context ();
@@ -216,6 +282,7 @@ void Hash::Initialize(Environment* env, Local<Object> target) {
216
282
217
283
SetMethodNoSideEffect (context, target, " getHashes" , GetHashes);
218
284
SetMethodNoSideEffect (context, target, " getCachedAliases" , GetCachedAliases);
285
+ SetMethodNoSideEffect (context, target, " oneShotDigest" , OneShotDigest);
219
286
220
287
HashJob::Initialize (env, target);
221
288
@@ -229,6 +296,7 @@ void Hash::RegisterExternalReferences(ExternalReferenceRegistry* registry) {
229
296
registry->Register (HashDigest);
230
297
registry->Register (GetHashes);
231
298
registry->Register (GetCachedAliases);
299
+ registry->Register (OneShotDigest);
232
300
233
301
HashJob::RegisterExternalReferences (registry);
234
302
@@ -294,14 +362,17 @@ bool Hash::HashUpdate(const char* data, size_t len) {
294
362
}
295
363
296
364
void Hash::HashUpdate (const FunctionCallbackInfo<Value>& args) {
297
- Decode<Hash>(args, [](Hash* hash, const FunctionCallbackInfo<Value>& args,
298
- const char * data, size_t size) {
299
- Environment* env = Environment::GetCurrent (args);
300
- if (UNLIKELY (size > INT_MAX))
301
- return THROW_ERR_OUT_OF_RANGE (env, " data is too long" );
302
- bool r = hash->HashUpdate (data, size);
303
- args.GetReturnValue ().Set (r);
304
- });
365
+ Decode<Hash>(args,
366
+ [](Hash* hash,
367
+ const FunctionCallbackInfo<Value>& args,
368
+ const char * data,
369
+ size_t size) {
370
+ Environment* env = Environment::GetCurrent (args);
371
+ if (UNLIKELY (size > INT_MAX))
372
+ return THROW_ERR_OUT_OF_RANGE (env, " data is too long" );
373
+ bool r = hash->HashUpdate (data, size);
374
+ args.GetReturnValue ().Set (r);
375
+ });
305
376
}
306
377
307
378
void Hash::HashDigest (const FunctionCallbackInfo<Value>& args) {
0 commit comments