Skip to content

Commit 934d88a

Browse files
committed
crypto: introduce crypto/promises
Refs: #36181
1 parent 03380bc commit 934d88a

File tree

7 files changed

+822
-2
lines changed

7 files changed

+822
-2
lines changed

doc/api/crypto.md

+126-2
Original file line numberDiff line numberDiff line change
@@ -2551,8 +2551,8 @@ added:
25512551
* Returns: {Buffer}
25522552

25532553
Computes the Diffie-Hellman secret based on a `privateKey` and a `publicKey`.
2554-
Both keys must have the same `asymmetricKeyType`, which must be one of `'dh'`
2555-
(for Diffie-Hellman), `'ec'` (for ECDH), `'x448'`, or `'x25519'` (for ECDH-ES).
2554+
Both keys must have the same `asymmetricKeyType`, which must be one of `'dh'`,
2555+
`'ec'`, `'x448'`, or `'x25519'`.
25562556

25572557
### `crypto.generateKey(type, options, callback)`
25582558
<!-- YAML
@@ -3895,6 +3895,130 @@ Type: {Crypto} An implementation of the Web Crypto API standard.
38953895

38963896
See the [Web Crypto API documentation][] for details.
38973897

3898+
## `crypto` Promises API
3899+
<!-- YAML
3900+
added: REPLACEME
3901+
-->
3902+
3903+
> Stability: 1 - Experimental
3904+
3905+
The `crypto.promises` API provides an alternative set of asynchronous crypto
3906+
methods that return `Promise` objects and execute operations in libuv's
3907+
threadpool.
3908+
The API is accessible via `require('crypto').promises` or `require('crypto/promises')`.
3909+
3910+
### `cryptoPromises.diffieHellman(options)`
3911+
<!-- YAML
3912+
added: REPLACEME
3913+
-->
3914+
3915+
* `options`: {Object}
3916+
* `privateKey`: {KeyObject|CryptoKey}
3917+
* `publicKey`: {KeyObject|CryptoKey}
3918+
* Returns: {Promise} containing {Buffer}
3919+
3920+
Computes the Diffie-Hellman secret based on a `privateKey` and a `publicKey`.
3921+
Both keys must have the same `asymmetricKeyType`, which must be one of `'dh'`,
3922+
`'ec'`, `'x448'`, or `'x25519'`.
3923+
3924+
### `cryptoPromises.digest(algorithm, data[, options])`
3925+
<!-- YAML
3926+
added: REPLACEME
3927+
-->
3928+
3929+
* `algorithm` {string}
3930+
* `data` {ArrayBuffer|TypedArray|DataView|Buffer}
3931+
* `options` {Object}
3932+
* `outputLength` {number} Used to specify the desired output length in bytes
3933+
for XOF hash functions such as `'shake256'`.
3934+
* Returns: {Promise} containing {Buffer}
3935+
3936+
Calculates the digest for the `data` using the given `algorithm`.
3937+
3938+
The `algorithm` is dependent on the available algorithms supported by the
3939+
version of OpenSSL on the platform. Examples are `'sha256'`, `'sha512'`, etc.
3940+
On recent releases of OpenSSL, `openssl list -digest-algorithms`
3941+
(`openssl list-message-digest-algorithms` for older versions of OpenSSL) will
3942+
display the available digest algorithms.
3943+
3944+
### `cryptoPromises.hmac(algorithm, data, key)`
3945+
<!-- YAML
3946+
added: REPLACEME
3947+
-->
3948+
3949+
* `algorithm` {string}
3950+
* `data` {ArrayBuffer|TypedArray|DataView|Buffer}
3951+
* `key` {KeyObject|CryptoKey}
3952+
* Returns: {Promise} containing {Buffer}
3953+
3954+
Calculates the HMAC digest for the `data` using the given `algorithm`.
3955+
3956+
The `algorithm` is dependent on the available algorithms supported by the
3957+
version of OpenSSL on the platform. Examples are `'sha256'`, `'sha512'`, etc.
3958+
On recent releases of OpenSSL, `openssl list -digest-algorithms`
3959+
(`openssl list-message-digest-algorithms` for older versions of OpenSSL) will
3960+
display the available digest algorithms.
3961+
3962+
### `cryptoPromises.sign(algorithm, data, key[, options])`
3963+
<!-- YAML
3964+
added: REPLACEME
3965+
-->
3966+
3967+
* `algorithm` {string|null|undefined}
3968+
* `data` {ArrayBuffer|TypedArray|DataView|Buffer}
3969+
* `key` {KeyObject|CryptoKey}
3970+
* `options` {Object}
3971+
* `dsaEncoding` {string} For DSA and ECDSA, this option specifies the
3972+
format of the generated signature. It can be one of the following:
3973+
* `'der'` (default): DER-encoded ASN.1 signature structure encoding `(r, s)`.
3974+
* `'ieee-p1363'`: Signature format `r || s` as proposed in IEEE-P1363.
3975+
* `padding` {integer} Optional padding value for RSA, one of the following:
3976+
* `crypto.constants.RSA_PKCS1_PADDING` (default)
3977+
* `crypto.constants.RSA_PKCS1_PSS_PADDING`
3978+
* `saltLength` {integer} Salt length for when padding is
3979+
`RSA_PKCS1_PSS_PADDING`. The special value
3980+
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest
3981+
size, `crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN` (default) sets it to the
3982+
maximum permissible value.
3983+
* Returns: {Promise} containing {Buffer}
3984+
3985+
Calculates the signature for `data` using the given private key and
3986+
algorithm. If `algorithm` is `null` or `undefined`, then the algorithm is
3987+
dependent upon the key type (especially Ed25519 and Ed448).
3988+
3989+
### `cryptoPromises.verify(algorithm, data, key, signature[, options])`
3990+
<!-- YAML
3991+
added: REPLACEME
3992+
-->
3993+
3994+
* `algorithm` {string|null|undefined}
3995+
* `data` {ArrayBuffer|TypedArray|DataView|Buffer}
3996+
* `key` {KeyObject|CryptoKey}
3997+
* `signature` {ArrayBuffer|TypedArray|DataView|Buffer}
3998+
* `options` {Object}
3999+
* `dsaEncoding` {string} For DSA and ECDSA, this option specifies the
4000+
format of the generated signature. It can be one of the following:
4001+
* `'der'` (default): DER-encoded ASN.1 signature structure encoding `(r, s)`.
4002+
* `'ieee-p1363'`: Signature format `r || s` as proposed in IEEE-P1363.
4003+
* `padding` {integer} Optional padding value for RSA, one of the following:
4004+
* `crypto.constants.RSA_PKCS1_PADDING` (default)
4005+
* `crypto.constants.RSA_PKCS1_PSS_PADDING`
4006+
* `saltLength` {integer} Salt length for when padding is
4007+
`RSA_PKCS1_PSS_PADDING`. The special value
4008+
`crypto.constants.RSA_PSS_SALTLEN_DIGEST` sets the salt length to the digest
4009+
size, `crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN` (default) sets it to the
4010+
maximum permissible value.
4011+
* Returns: {Promise} containing {boolean}
4012+
4013+
Verifies the given signature for `data` using the given key and algorithm. If
4014+
`algorithm` is `null` or `undefined`, then the algorithm is dependent upon the
4015+
key type (especially Ed25519 and Ed448).
4016+
4017+
The `signature` argument is the previously calculated signature for the `data`.
4018+
4019+
Because public keys can be derived from private keys, a private key or a public
4020+
key may be passed for `key`.
4021+
38984022
## Notes
38994023

39004024
### Legacy streams API (prior to Node.js 0.10)

lib/crypto.js

+12
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ function createVerify(algorithm, options) {
172172
return new Verify(algorithm, options);
173173
}
174174

175+
// Lazy loaded
176+
let promises = null;
177+
175178
module.exports = {
176179
// Methods
177180
checkPrime,
@@ -327,5 +330,14 @@ ObjectDefineProperties(module.exports, {
327330
value: pendingDeprecation ?
328331
deprecate(randomBytes, 'crypto.rng is deprecated.', 'DEP0115') :
329332
randomBytes
333+
},
334+
promises: {
335+
configurable: true,
336+
enumerable: true,
337+
get() {
338+
if (promises === null)
339+
promises = require('internal/crypto/promises').exports;
340+
return promises;
341+
}
330342
}
331343
});

lib/crypto/promises.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
'use strict';
2+
3+
module.exports = require('internal/crypto/promises').exports;

lib/internal/crypto/diffiehellman.js

+42
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,46 @@ function deriveBitsDH(publicKey, privateKey, callback) {
346346
job.run();
347347
}
348348

349+
async function asyncDiffieHellman(publicKey, privateKey) {
350+
const { asymmetricKeyType } = privateKey;
351+
352+
if (asymmetricKeyType === 'dh') {
353+
return new Promise((resolve, reject) => {
354+
deriveBitsDH(
355+
publicKey[kHandle],
356+
privateKey[kHandle],
357+
(err, bits) => {
358+
if (err) reject(err);
359+
else resolve(bits);
360+
});
361+
});
362+
}
363+
364+
if (asymmetricKeyType === 'x25519' || asymmetricKeyType === 'x448') {
365+
return new Promise((resolve, reject) => {
366+
deriveBitsECDH(
367+
`NODE-${asymmetricKeyType.toUpperCase()}`,
368+
publicKey[kHandle],
369+
privateKey[kHandle],
370+
(err, bits) => {
371+
if (err) reject(err);
372+
else resolve(bits);
373+
});
374+
});
375+
}
376+
377+
return new Promise((resolve, reject) => {
378+
deriveBitsECDH(
379+
privateKey.asymmetricKeyDetails.namedCurve,
380+
publicKey[kHandle],
381+
privateKey[kHandle],
382+
(err, bits) => {
383+
if (err) reject(err);
384+
else resolve(bits);
385+
});
386+
});
387+
}
388+
349389
function verifyAcceptableDhKeyUse(name, type, usages) {
350390
let checkSet;
351391
switch (type) {
@@ -601,9 +641,11 @@ module.exports = {
601641
DiffieHellman,
602642
DiffieHellmanGroup,
603643
ECDH,
644+
asyncDiffieHellman,
604645
diffieHellman,
605646
deriveBitsECDH,
606647
deriveBitsDH,
648+
dhEnabledKeyTypes,
607649
dhGenerateKey,
608650
asyncDeriveBitsECDH,
609651
asyncDeriveBitsDH,

0 commit comments

Comments
 (0)