Skip to content

Commit fc80d87

Browse files
committed
crypto: add optional callback to crypto.diffieHellman
1 parent 4644853 commit fc80d87

File tree

5 files changed

+264
-52
lines changed

5 files changed

+264
-52
lines changed

doc/api/crypto.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3533,23 +3533,32 @@ the corresponding digest algorithm. This does not work for all signature
35333533
algorithms, such as `'ecdsa-with-SHA256'`, so it is best to always use digest
35343534
algorithm names.
35353535

3536-
### `crypto.diffieHellman(options)`
3536+
### `crypto.diffieHellman(options[, callback])`
35373537

35383538
<!-- YAML
35393539
added:
35403540
- v13.9.0
35413541
- v12.17.0
3542+
changes:
3543+
- version: REPLACEME
3544+
pr-url: https://github.com/nodejs/node/pull/57274
3545+
description: Optional callback argument added.
35423546
-->
35433547

35443548
* `options`: {Object}
35453549
* `privateKey`: {KeyObject}
35463550
* `publicKey`: {KeyObject}
3547-
* Returns: {Buffer}
3551+
* `callback` {Function}
3552+
* `err` {Error}
3553+
* `secret` {Buffer}
3554+
* Returns: {Buffer} if the `callback` function is not provided.
35483555

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

3560+
If the `callback` function is provided this function uses libuv's threadpool.
3561+
35533562
### `crypto.fips`
35543563

35553564
<!-- YAML

lib/internal/crypto/diffiehellman.js

Lines changed: 26 additions & 3 deletions
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

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -477,41 +477,6 @@ WebCryptoKeyExportStatus DHKeyExportTraits::DoExport(
477477
}
478478
}
479479

480-
namespace {
481-
ByteSource StatelessDiffieHellmanThreadsafe(const EVPKeyPointer& our_key,
482-
const EVPKeyPointer& their_key) {
483-
auto dp = DHPointer::stateless(our_key, their_key);
484-
if (!dp) return {};
485-
486-
return ByteSource::Allocated(dp.release());
487-
}
488-
489-
void Stateless(const FunctionCallbackInfo<Value>& args) {
490-
Environment* env = Environment::GetCurrent(args);
491-
492-
CHECK(args[0]->IsObject() && args[1]->IsObject());
493-
KeyObjectHandle* our_key_object;
494-
ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As<Object>());
495-
CHECK_EQ(our_key_object->Data().GetKeyType(), kKeyTypePrivate);
496-
KeyObjectHandle* their_key_object;
497-
ASSIGN_OR_RETURN_UNWRAP(&their_key_object, args[1].As<Object>());
498-
CHECK_NE(their_key_object->Data().GetKeyType(), kKeyTypeSecret);
499-
500-
const auto& our_key = our_key_object->Data().GetAsymmetricKey();
501-
const auto& their_key = their_key_object->Data().GetAsymmetricKey();
502-
503-
Local<Value> out;
504-
if (!StatelessDiffieHellmanThreadsafe(our_key, their_key)
505-
.ToBuffer(env)
506-
.ToLocal(&out)) return;
507-
508-
if (Buffer::Length(out) == 0)
509-
return ThrowCryptoError(env, ERR_get_error(), "diffieHellman failed");
510-
511-
args.GetReturnValue().Set(out);
512-
}
513-
} // namespace
514-
515480
Maybe<void> DHBitsTraits::AdditionalConfig(
516481
CryptoJobMode mode,
517482
const FunctionCallbackInfo<Value>& args,
@@ -529,7 +494,7 @@ Maybe<void> DHBitsTraits::AdditionalConfig(
529494
ASSIGN_OR_RETURN_UNWRAP(&private_key, args[offset + 1], Nothing<void>());
530495

531496
if (private_key->Data().GetKeyType() != kKeyTypePrivate ||
532-
public_key->Data().GetKeyType() != kKeyTypePublic) {
497+
public_key->Data().GetKeyType() == kKeyTypeSecret) {
533498
THROW_ERR_CRYPTO_INVALID_KEYTYPE(env);
534499
return Nothing<void>();
535500
}
@@ -550,8 +515,20 @@ bool DHBitsTraits::DeriveBits(
550515
Environment* env,
551516
const DHBitsConfig& params,
552517
ByteSource* out) {
553-
*out = StatelessDiffieHellmanThreadsafe(params.private_key.GetAsymmetricKey(),
554-
params.public_key.GetAsymmetricKey());
518+
auto dp = DHPointer::stateless(params.private_key.GetAsymmetricKey(),
519+
params.public_key.GetAsymmetricKey());
520+
if (!dp) {
521+
bool can_throw =
522+
per_process::v8_initialized && Isolate::TryGetCurrent() != nullptr;
523+
if (can_throw) {
524+
unsigned long err = ERR_get_error(); // NOLINT(runtime/int)
525+
if (err) ThrowCryptoError(env, err, "diffieHellman failed");
526+
}
527+
return false;
528+
}
529+
530+
*out = ByteSource::Allocated(dp.release());
531+
CHECK(!out->empty());
555532
return true;
556533
}
557534

@@ -604,7 +581,6 @@ void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
604581
make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
605582
DiffieHellmanGroup);
606583

607-
SetMethodNoSideEffect(context, target, "statelessDH", Stateless);
608584
DHKeyPairGenJob::Initialize(env, target);
609585
DHKeyExportJob::Initialize(env, target);
610586
DHBitsJob::Initialize(env, target);
@@ -625,7 +601,6 @@ void DiffieHellman::RegisterExternalReferences(
625601
registry->Register(SetPrivateKey);
626602

627603
registry->Register(Check);
628-
registry->Register(Stateless);
629604

630605
DHKeyPairGenJob::RegisterExternalReferences(registry);
631606
DHKeyExportJob::RegisterExternalReferences(registry);

0 commit comments

Comments
 (0)