Skip to content

Commit 053cef7

Browse files
panvaaduh95
authored andcommitted
crypto: add optional callback to crypto.diffieHellman
PR-URL: #57274 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
1 parent 2a5fcb2 commit 053cef7

File tree

5 files changed

+337
-59
lines changed

5 files changed

+337
-59
lines changed

doc/api/crypto.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -3527,23 +3527,32 @@ the corresponding digest algorithm. This does not work for all signature
35273527
algorithms, such as `'ecdsa-with-SHA256'`, so it is best to always use digest
35283528
algorithm names.
35293529

3530-
### `crypto.diffieHellman(options)`
3530+
### `crypto.diffieHellman(options[, callback])`
35313531

35323532
<!-- YAML
35333533
added:
35343534
- v13.9.0
35353535
- v12.17.0
3536+
changes:
3537+
- version: REPLACEME
3538+
pr-url: https://github.com/nodejs/node/pull/57274
3539+
description: Optional callback argument added.
35363540
-->
35373541

35383542
* `options`: {Object}
35393543
* `privateKey`: {KeyObject}
35403544
* `publicKey`: {KeyObject}
3541-
* Returns: {Buffer}
3545+
* `callback` {Function}
3546+
* `err` {Error}
3547+
* `secret` {Buffer}
3548+
* Returns: {Buffer} if the `callback` function is not provided.
35423549

35433550
Computes the Diffie-Hellman secret based on a `privateKey` and a `publicKey`.
35443551
Both keys must have the same `asymmetricKeyType`, which must be one of `'dh'`
35453552
(for Diffie-Hellman), `'ec'`, `'x448'`, or `'x25519'` (for ECDH).
35463553

3554+
If the `callback` function is provided this function uses libuv's threadpool.
3555+
35473556
### `crypto.fips`
35483557

35493558
<!-- YAML

lib/internal/crypto/diffiehellman.js

+26-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const {
44
ArrayBufferPrototypeSlice,
5+
FunctionPrototypeCall,
56
MathCeil,
67
ObjectDefineProperty,
78
SafeSet,
@@ -11,13 +12,14 @@ const {
1112
const { Buffer } = require('buffer');
1213

1314
const {
15+
DHBitsJob,
1416
DiffieHellman: _DiffieHellman,
1517
DiffieHellmanGroup: _DiffieHellmanGroup,
1618
ECDH: _ECDH,
1719
ECDHBitsJob,
1820
ECDHConvertKey: _ECDHConvertKey,
19-
statelessDH,
2021
kCryptoJobAsync,
22+
kCryptoJobSync,
2123
} = internalBinding('crypto');
2224

2325
const {
@@ -32,6 +34,7 @@ const {
3234
} = require('internal/errors');
3335

3436
const {
37+
validateFunction,
3538
validateInt32,
3639
validateObject,
3740
validateString,
@@ -268,9 +271,12 @@ function getFormat(format) {
268271

269272
const dhEnabledKeyTypes = new SafeSet(['dh', 'ec', 'x448', 'x25519']);
270273

271-
function diffieHellman(options) {
274+
function diffieHellman(options, callback) {
272275
validateObject(options, 'options');
273276

277+
if (callback !== undefined)
278+
validateFunction(callback, 'callback');
279+
274280
const { privateKey, publicKey } = options;
275281
if (!(privateKey instanceof KeyObject))
276282
throw new ERR_INVALID_ARG_VALUE('options.privateKey', privateKey);
@@ -293,7 +299,24 @@ function diffieHellman(options) {
293299
`${privateType} and ${publicType}`);
294300
}
295301

296-
return statelessDH(privateKey[kHandle], publicKey[kHandle]);
302+
const job = new DHBitsJob(
303+
callback ? kCryptoJobAsync : kCryptoJobSync,
304+
publicKey[kHandle],
305+
privateKey[kHandle]);
306+
307+
if (!callback) {
308+
const { 0: err, 1: secret } = job.run();
309+
if (err !== undefined)
310+
throw err;
311+
312+
return Buffer.from(secret);
313+
}
314+
315+
job.ondone = (error, secret) => {
316+
if (error) return FunctionPrototypeCall(callback, job, error);
317+
FunctionPrototypeCall(callback, job, null, Buffer.from(secret));
318+
};
319+
job.run();
297320
}
298321

299322
let masks;

src/crypto/crypto_dh.cc

+16-47
Original file line numberDiff line numberDiff line change
@@ -483,49 +483,11 @@ WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(
483483
}
484484
}
485485

486-
namespace {
487-
ByteSource StatelessDiffieHellmanThreadsafe(const EVPKeyPointer& our_key,
488-
const EVPKeyPointer& their_key) {
489-
auto dp = DHPointer::stateless(our_key, their_key);
490-
if (!dp) return {};
491-
DCHECK(!dp.isSecure());
492-
493-
return ByteSource::Allocated(dp.release());
494-
}
495-
496-
void Stateless(const FunctionCallbackInfo<Value>& args) {
497-
Environment* env = Environment::GetCurrent(args);
498-
499-
CHECK(args[0]->IsObject() && args[1]->IsObject());
500-
KeyObjectHandle* our_key_object;
501-
ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As<Object>());
502-
CHECK_EQ(our_key_object->Data().GetKeyType(), kKeyTypePrivate);
503-
KeyObjectHandle* their_key_object;
504-
ASSIGN_OR_RETURN_UNWRAP(&their_key_object, args[1].As<Object>());
505-
CHECK_NE(their_key_object->Data().GetKeyType(), kKeyTypeSecret);
506-
507-
const auto& our_key = our_key_object->Data().GetAsymmetricKey();
508-
const auto& their_key = their_key_object->Data().GetAsymmetricKey();
509-
510-
Local<Value> out;
511-
if (!StatelessDiffieHellmanThreadsafe(our_key, their_key)
512-
.ToBuffer(env)
513-
.ToLocal(&out)) return;
514-
515-
if (Buffer::Length(out) == 0)
516-
return ThrowCryptoError(env, ERR_get_error(), "diffieHellman failed");
517-
518-
args.GetReturnValue().Set(out);
519-
}
520-
} // namespace
521-
522486
Maybe<void> DHBitsTraits::AdditionalConfig(
523487
CryptoJobMode mode,
524488
const FunctionCallbackInfo<Value>& args,
525489
unsigned int offset,
526490
DHBitsConfig* params) {
527-
Environment* env = Environment::GetCurrent(args);
528-
529491
CHECK(args[offset]->IsObject()); // public key
530492
CHECK(args[offset + 1]->IsObject()); // private key
531493

@@ -535,11 +497,8 @@ Maybe<void> DHBitsTraits::AdditionalConfig(
535497
ASSIGN_OR_RETURN_UNWRAP(&public_key, args[offset], Nothing<void>());
536498
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<void>());
537499

538-
if (private_key->Data().GetKeyType() != kKeyTypePrivate ||
539-
public_key->Data().GetKeyType() != kKeyTypePublic) {
540-
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
541-
return Nothing<void>();
542-
}
500+
CHECK(private_key->Data().GetKeyType() == kKeyTypePrivate);
501+
CHECK(public_key->Data().GetKeyType() != kKeyTypeSecret);
543502

544503
params->public_key = public_key->Data().addRef();
545504
params->private_key = private_key->Data().addRef();
@@ -557,8 +516,20 @@ bool DHBitsTraits::DeriveBits(
557516
Environment* env,
558517
const DHBitsConfig& params,
559518
ByteSource* out) {
560-
*out = StatelessDiffieHellmanThreadsafe(params.private_key.GetAsymmetricKey(),
561-
params.public_key.GetAsymmetricKey());
519+
auto dp = DHPointer::stateless(params.private_key.GetAsymmetricKey(),
520+
params.public_key.GetAsymmetricKey());
521+
if (!dp) {
522+
bool can_throw =
523+
per_process::v8_initialized && Isolate::TryGetCurrent() != nullptr;
524+
if (can_throw) {
525+
unsigned long err = ERR_get_error(); // NOLINT(runtime/int)
526+
if (err) ThrowCryptoError(env, err, "diffieHellman failed");
527+
}
528+
return false;
529+
}
530+
531+
*out = ByteSource::Allocated(dp.release());
532+
CHECK(!out->empty());
562533
return true;
563534
}
564535

@@ -611,7 +582,6 @@ void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
611582
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
612583
DiffieHellmanGroup);
613584

614-
SetMethodNoSideEffect(context, target, "statelessDH", Stateless);
615585
DHKeyPairGenJob::Initialize(env, target);
616586
DHKeyExportJob::Initialize(env, target);
617587
DHBitsJob::Initialize(env, target);
@@ -632,7 +602,6 @@ void DiffieHellman::RegisterExternalReferences(
632602
registry->Register(SetPrivateKey);
633603

634604
registry->Register(Check);
635-
registry->Register(Stateless);
636605

637606
DHKeyPairGenJob::RegisterExternalReferences(registry);
638607
DHKeyExportJob::RegisterExternalReferences(registry);

0 commit comments

Comments
 (0)