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