crypto: add crypto.diffieHellman

Currently, Node.js has separate (stateful) APIs for DH/ECDH, and no
support for ECDH-ES. This commit adds a single stateless function to
compute the DH/ECDH/ECDH-ES secret based on two KeyObjects.

PR-URL: https://github.com/nodejs/node/pull/31178
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
This commit is contained in:
Tobias Nießen 2020-01-03 12:01:34 +01:00
parent c6f8ea8d65
commit b4f8537cdc
7 changed files with 345 additions and 14 deletions

View File

@ -2089,6 +2089,20 @@ the corresponding digest algorithm. This does not work for all signature
algorithms, such as `'ecdsa-with-SHA256'`, so it is best to always use digest
algorithm names.
### `crypto.diffieHellman(options)`
<!-- YAML
added: REPLACEME
-->
* `options`: {Object}
* `privateKey`: {KeyObject}
* `publicKey`: {KeyObject}
* Returns: {Buffer}
Computes the Diffie-Hellman secret based on a `privateKey` and a `publicKey`.
Both keys must have the same `asymmetricKeyType`, which must be one of `'dh'`
(for Diffie-Hellman), `'ec'` (for ECDH), `'x448'`, or `'x25519'` (for ECDH-ES).
### `crypto.generateKeyPair(type, options, callback)`
<!-- YAML
added: v10.12.0

View File

@ -776,6 +776,11 @@ be called no more than one time per instance of a `Hash` object.
[`hash.update()`][] failed for any reason. This should rarely, if ever, happen.
<a id="ERR_CRYPTO_INCOMPATIBLE_KEY"></a>
### `ERR_CRYPTO_INCOMPATIBLE_KEY`
The given crypto keys are incompatible with the attempted operation.
<a id="ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS"></a>
### `ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS`

View File

@ -70,7 +70,8 @@ const {
const {
DiffieHellman,
DiffieHellmanGroup,
ECDH
ECDH,
diffieHellman
} = require('internal/crypto/diffiehellman');
const {
Cipher,
@ -163,6 +164,7 @@ module.exports = {
createSecretKey,
createSign,
createVerify,
diffieHellman,
getCiphers,
getCurves,
getDiffieHellman: createDiffieHellmanGroup,

View File

@ -2,16 +2,21 @@
const {
ObjectDefineProperty,
Set
} = primordials;
const { Buffer } = require('buffer');
const {
ERR_CRYPTO_ECDH_INVALID_FORMAT,
ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY,
ERR_INVALID_ARG_TYPE
ERR_CRYPTO_INCOMPATIBLE_KEY,
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_OPT_VALUE
} = require('internal/errors').codes;
const { validateString } = require('internal/validators');
const { isArrayBufferView } = require('internal/util/types');
const { KeyObject } = require('internal/crypto/keys');
const {
getDefaultEncoding,
kHandle,
@ -21,7 +26,8 @@ const {
DiffieHellman: _DiffieHellman,
DiffieHellmanGroup: _DiffieHellmanGroup,
ECDH: _ECDH,
ECDHConvertKey: _ECDHConvertKey
ECDHConvertKey: _ECDHConvertKey,
statelessDH
} = internalBinding('crypto');
const {
POINT_CONVERSION_COMPRESSED,
@ -232,8 +238,40 @@ function getFormat(format) {
return POINT_CONVERSION_UNCOMPRESSED;
}
const dhEnabledKeyTypes = new Set(['dh', 'ec', 'x448', 'x25519']);
function diffieHellman(options) {
if (typeof options !== 'object')
throw new ERR_INVALID_ARG_TYPE('options', 'object', options);
const { privateKey, publicKey } = options;
if (!(privateKey instanceof KeyObject))
throw new ERR_INVALID_OPT_VALUE('privateKey', privateKey);
if (!(publicKey instanceof KeyObject))
throw new ERR_INVALID_OPT_VALUE('publicKey', publicKey);
if (privateKey.type !== 'private')
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(privateKey.type, 'private');
if (publicKey.type !== 'public' && publicKey.type !== 'private') {
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(publicKey.type,
'private or public');
}
const privateType = privateKey.asymmetricKeyType;
const publicType = publicKey.asymmetricKeyType;
if (privateType !== publicType || !dhEnabledKeyTypes.has(privateType)) {
throw new ERR_CRYPTO_INCOMPATIBLE_KEY('key types for Diffie-Hellman',
`${privateType} and ${publicType}`);
}
return statelessDH(privateKey[kHandle], publicKey[kHandle]);
}
module.exports = {
DiffieHellman,
DiffieHellmanGroup,
ECDH
ECDH,
diffieHellman
};

View File

@ -767,6 +767,7 @@ E('ERR_CRYPTO_FIPS_UNAVAILABLE', 'Cannot set FIPS mode in a non-FIPS build.',
Error);
E('ERR_CRYPTO_HASH_FINALIZED', 'Digest already called', Error);
E('ERR_CRYPTO_HASH_UPDATE_FAILED', 'Hash update failed', Error);
E('ERR_CRYPTO_INCOMPATIBLE_KEY', 'Incompatible %s: %s', Error);
E('ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS', 'The selected key encoding %s %s.',
Error);
E('ERR_CRYPTO_INVALID_DIGEST', 'Invalid digest: %s', TypeError);

View File

@ -5827,6 +5827,20 @@ void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
}, "No private key - did you forget to generate one?");
}
static void ZeroPadDiffieHellmanSecret(size_t remainder_size,
AllocatedBuffer* ret) {
// DH_size returns number of bytes in a prime number.
// DH_compute_key returns number of bytes in a remainder of exponent, which
// may have less bytes than a prime number. Therefore add 0-padding to the
// allocated buffer.
const size_t prime_size = ret->size();
if (remainder_size != prime_size) {
CHECK_LT(remainder_size, prime_size);
const size_t padding = prime_size - remainder_size;
memmove(ret->data() + padding, ret->data(), remainder_size);
memset(ret->data(), 0, padding);
}
}
void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@ -5877,16 +5891,7 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
}
CHECK_GE(size, 0);
// DH_size returns number of bytes in a prime number
// DH_compute_key returns number of bytes in a remainder of exponent, which
// may have less bytes than a prime number. Therefore add 0-padding to the
// allocated buffer.
if (static_cast<size_t>(size) != ret.size()) {
CHECK_GT(ret.size(), static_cast<size_t>(size));
memmove(ret.data() + ret.size() - size, ret.data(), size);
memset(ret.data(), 0, ret.size() - size);
}
ZeroPadDiffieHellmanSecret(static_cast<size_t>(size), &ret);
args.GetReturnValue().Set(ret.ToBuffer().ToLocalChecked());
}
@ -7197,6 +7202,49 @@ void ConvertKey(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(buf);
}
AllocatedBuffer StatelessDiffieHellman(Environment* env, ManagedEVPPKey our_key,
ManagedEVPPKey their_key) {
size_t out_size;
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(our_key.get(), nullptr));
if (!ctx ||
EVP_PKEY_derive_init(ctx.get()) <= 0 ||
EVP_PKEY_derive_set_peer(ctx.get(), their_key.get()) <= 0 ||
EVP_PKEY_derive(ctx.get(), nullptr, &out_size) <= 0)
return AllocatedBuffer();
AllocatedBuffer result = env->AllocateManaged(out_size);
CHECK_NOT_NULL(result.data());
unsigned char* data = reinterpret_cast<unsigned char*>(result.data());
if (EVP_PKEY_derive(ctx.get(), data, &out_size) <= 0)
return AllocatedBuffer();
ZeroPadDiffieHellmanSecret(out_size, &result);
return result;
}
void StatelessDiffieHellman(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsObject() && args[1]->IsObject());
KeyObject* our_key_object;
ASSIGN_OR_RETURN_UNWRAP(&our_key_object, args[0].As<Object>());
CHECK_EQ(our_key_object->GetKeyType(), kKeyTypePrivate);
KeyObject* their_key_object;
ASSIGN_OR_RETURN_UNWRAP(&their_key_object, args[1].As<Object>());
CHECK_NE(their_key_object->GetKeyType(), kKeyTypeSecret);
ManagedEVPPKey our_key = our_key_object->GetAsymmetricKey();
ManagedEVPPKey their_key = their_key_object->GetAsymmetricKey();
AllocatedBuffer out = StatelessDiffieHellman(env, our_key, their_key);
if (out.size() == 0)
return ThrowCryptoError(env, ERR_get_error(), "diffieHellman failed");
args.GetReturnValue().Set(out.ToBuffer().ToLocalChecked());
}
void TimingSafeEqual(const FunctionCallbackInfo<Value>& args) {
ArrayBufferViewContents<char> buf1(args[0]);
@ -7366,6 +7414,7 @@ void Initialize(Local<Object> target,
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate);
NODE_DEFINE_CONSTANT(target, kSigEncDER);
NODE_DEFINE_CONSTANT(target, kSigEncP1363);
env->SetMethodNoSideEffect(target, "statelessDH", StatelessDiffieHellman);
env->SetMethod(target, "randomBytes", RandomBytes);
env->SetMethod(target, "signOneShot", SignOneShot);
env->SetMethod(target, "verifyOneShot", VerifyOneShot);

View File

@ -0,0 +1,222 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const crypto = require('crypto');
assert.throws(() => crypto.diffieHellman(), {
name: 'TypeError',
code: 'ERR_INVALID_ARG_TYPE',
message: 'The "options" argument must be of type object. Received undefined'
});
function test({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
{ publicKey: bobPublicKey, privateKey: bobPrivateKey },
expectedValue) {
const buf1 = crypto.diffieHellman({
privateKey: alicePrivateKey,
publicKey: bobPublicKey
});
const buf2 = crypto.diffieHellman({
privateKey: bobPrivateKey,
publicKey: alicePublicKey
});
assert.deepStrictEqual(buf1, buf2);
if (expectedValue !== undefined)
assert.deepStrictEqual(buf1, expectedValue);
}
const alicePrivateKey = crypto.createPrivateKey({
key: '-----BEGIN PRIVATE KEY-----\n' +
'MIIBoQIBADCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKL\n' +
'gNwc0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVt\n' +
'bVHCReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR\n' +
'7ORbPcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkH\n' +
'cJaWbWcMNU5KvJgE8XRsCMojcyf//////////wIBAgSBwwKBwEh82IAVnYNf0Kjb\n' +
'qYSImDFyg9sH6CJ0GzRK05e6hM3dOSClFYi4kbA7Pr7zyfdn2SH6wSlNS14Jyrtt\n' +
'HePrRSeYl1T+tk0AfrvaLmyM56F+9B3jwt/nzqr5YxmfVdXb2aQV53VS/mm3pB2H\n' +
'iIt9FmvFaaOVe2DupqSr6xzbf/zyON+WF5B5HNVOWXswgpgdUsCyygs98hKy/Xje\n' +
'TGzJUoWInW39t0YgMXenJrkS0m6wol8Rhxx81AGgELNV7EHZqg==\n' +
'-----END PRIVATE KEY-----',
format: 'pem'
});
const alicePublicKey = crypto.createPublicKey({
key: '-----BEGIN PUBLIC KEY-----\n' +
'MIIBnzCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc\n' +
'0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHC\n' +
'ReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7ORb\n' +
'PcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkHcJaW\n' +
'bWcMNU5KvJgE8XRsCMojcyf//////////wIBAgOBxAACgcBR7+iL5qx7aOb9K+aZ\n' +
'y2oLt7ST33sDKT+nxpag6cWDDWzPBKFDCJ8fr0v7yW453px8N4qi4R7SYYxFBaYN\n' +
'Y3JvgDg1ct2JC9sxSuUOLqSFn3hpmAjW7cS0kExIVGfdLlYtIqbhhuo45cTEbVIM\n' +
'rDEz8mjIlnvbWpKB9+uYmbjfVoc3leFvUBqfG2In2m23Md1swsPxr3n7g68H66JX\n' +
'iBJKZLQMqNdbY14G9rdKmhhTJrQjC+i7Q/wI8JPhOFzHIGA=\n' +
'-----END PUBLIC KEY-----',
format: 'pem'
});
const bobPrivateKey = crypto.createPrivateKey({
key: '-----BEGIN PRIVATE KEY-----\n' +
'MIIBoQIBADCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKL\n' +
'gNwc0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVt\n' +
'bVHCReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR\n' +
'7ORbPcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkH\n' +
'cJaWbWcMNU5KvJgE8XRsCMojcyf//////////wIBAgSBwwKBwHxnT7Zw2Ehh1vyw\n' +
'eolzQFHQzyuT0y+3BF+FxK2Ox7VPguTp57wQfGHbORJ2cwCdLx2mFM7gk4tZ6COS\n' +
'E3Vta85a/PuhKXNLRdP79JgLnNtVtKXB+ePDS5C2GgXH1RHvqEdJh7JYnMy7Zj4P\n' +
'GagGtIy3dV5f4FA0B/2C97jQ1pO16ah8gSLQRKsNpTCw2rqsZusE0rK6RaYAef7H\n' +
'y/0tmLIsHxLIn+WK9CANqMbCWoP4I178BQaqhiOBkNyNZ0ndqA==\n' +
'-----END PRIVATE KEY-----',
format: 'pem'
});
const bobPublicKey = crypto.createPublicKey({
key: '-----BEGIN PUBLIC KEY-----\n' +
'MIIBoDCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc\n' +
'0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHC\n' +
'ReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7ORb\n' +
'PcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkHcJaW\n' +
'bWcMNU5KvJgE8XRsCMojcyf//////////wIBAgOBxQACgcEAi26oq8z/GNSBm3zi\n' +
'gNt7SA7cArUBbTxINa9iLYWp6bxrvCKwDQwISN36/QUw8nUAe8aRyMt0oYn+y6vW\n' +
'Pw5OlO+TLrUelMVFaADEzoYomH0zVGb0sW4aBN8haC0mbrPt9QshgCvjr1hEPEna\n' +
'QFKfjzNaJRNMFFd4f2Dn8MSB4yu1xpA1T2i0JSk24vS2H55jx24xhUYtfhT2LJgK\n' +
'JvnaODey/xtY4Kql10ZKf43Lw6gdQC3G8opC9OxVxt9oNR7Z\n' +
'-----END PUBLIC KEY-----',
format: 'pem'
});
assert.throws(() => crypto.diffieHellman({ privateKey: alicePrivateKey }), {
name: 'TypeError',
code: 'ERR_INVALID_OPT_VALUE',
message: 'The value "undefined" is invalid for option "publicKey"'
});
assert.throws(() => crypto.diffieHellman({ publicKey: alicePublicKey }), {
name: 'TypeError',
code: 'ERR_INVALID_OPT_VALUE',
message: 'The value "undefined" is invalid for option "privateKey"'
});
const privateKey = Buffer.from(
'487CD880159D835FD0A8DBA9848898317283DB07E822741B344AD397BA84CDDD3920A51588' +
'B891B03B3EBEF3C9F767D921FAC1294D4B5E09CABB6D1DE3EB4527989754FEB64D007EBBDA' +
'2E6C8CE7A17EF41DE3C2DFE7CEAAF963199F55D5DBD9A415E77552FE69B7A41D87888B7D16' +
'6BC569A3957B60EEA6A4ABEB1CDB7FFCF238DF961790791CD54E597B3082981D52C0B2CA0B' +
'3DF212B2FD78DE4C6CC95285889D6DFDB746203177A726B912D26EB0A25F11871C7CD401A0' +
'10B355EC41D9AA', 'hex');
const publicKey = Buffer.from(
'8b6ea8abccff18d4819b7ce280db7b480edc02b5016d3c4835af622d85a9e9bc6bbc22b00d' +
'0c0848ddfafd0530f275007bc691c8cb74a189fecbabd63f0e4e94ef932eb51e94c5456800' +
'c4ce8628987d335466f4b16e1a04df21682d266eb3edf50b21802be3af58443c49da40529f' +
'8f335a25134c1457787f60e7f0c481e32bb5c690354f68b4252936e2f4b61f9e63c76e3185' +
'462d7e14f62c980a26f9da3837b2ff1b58e0aaa5d7464a7f8dcbc3a81d402dc6f28a42f4ec' +
'55c6df68351ed9', 'hex');
const group = crypto.getDiffieHellman('modp5');
const dh = crypto.createDiffieHellman(group.getPrime(), group.getGenerator());
dh.setPrivateKey(privateKey);
// Test simple Diffie-Hellman, no curves involved.
test({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
{ publicKey: bobPublicKey, privateKey: bobPrivateKey },
dh.computeSecret(publicKey));
test(crypto.generateKeyPairSync('dh', { group: 'modp5' }),
crypto.generateKeyPairSync('dh', { group: 'modp5' }));
test(crypto.generateKeyPairSync('dh', { group: 'modp5' }),
crypto.generateKeyPairSync('dh', { prime: group.getPrime() }));
for (const [params1, params2] of [
// Same generator, but different primes.
[{ group: 'modp5' }, { group: 'modp18' }],
// Same primes, but different generator.
[{ group: 'modp5' }, { prime: group.getPrime(), generator: 5 }],
// Same generator, but different primes.
[{ primeLength: 1024 }, { primeLength: 1024 }]
]) {
assert.throws(() => {
test(crypto.generateKeyPairSync('dh', params1),
crypto.generateKeyPairSync('dh', params2));
}, {
name: 'Error',
code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS'
});
}
{
const privateKey = crypto.createPrivateKey({
key: '-----BEGIN PRIVATE KEY-----\n' +
'MIIBoQIBADCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKL\n' +
'gNwc0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVt\n' +
'bVHCReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR\n' +
'7ORbPcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkH\n' +
'cJaWbWcMNU5KvJgE8XRsCMojcyf//////////wIBAgSBwwKBwHu9fpiqrfJJ+tl9\n' +
'ujFtEWv4afub6A/1/7sgishOYN3YQ+nmWQlmPpveIY34an5dG82CTrixHwUzQTMF\n' +
'JaiCW3ax9+qk31f2jTNKrQznmKgopVKXF0FEJC6H79W/8Y0U14gsI9sHpovKhfou\n' +
'RQD0QogW7ejSwMG8hCYibfrvMm0b5PHlwimISyEKh7VtDQ1frYN/Wr9ZbiV+FePJ\n' +
'2j6RUKYNj1Pv+B4zdMgiLLjILAs8WUfbHciU21KSJh1izVQaUQ==\n' +
'-----END PRIVATE KEY-----'
});
const publicKey = crypto.createPublicKey({
key: '-----BEGIN PUBLIC KEY-----\n' +
'MIIBoDCB1QYJKoZIhvcNAQMBMIHHAoHBAP//////////yQ/aoiFowjTExmKLgNwc\n' +
'0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHC\n' +
'ReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7ORb\n' +
'PcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkHcJaW\n' +
'bWcMNU5KvJgE8XRsCMojcyf//////////wIBAgOBxQACgcEAmG9LpD8SAA6/W7oK\n' +
'E4MCuuQtf5E8bqtcEAfYTOOvKyCS+eiX3TtZRsvHJjUBEyeO99PR/KrGVlkSuW52\n' +
'ZOSXUOFu1L/0tqHrvRVHo+QEq3OvZ3EAyJkdtSEUTztxuUrMOyJXHDc1OUdNSnk0\n' +
'taGX4mP3247golVx2DS4viDYs7UtaMdx03dWaP6y5StNUZQlgCIUzL7MYpC16V5y\n' +
'KkFrE+Kp/Z77gEjivaG6YuxVj4GPLxJYbNFVTel42oSVeKuq\n' +
'-----END PUBLIC KEY-----',
format: 'pem'
});
// This key combination will result in an unusually short secret, and should
// not cause an assertion failure.
const secret = crypto.diffieHellman({ publicKey, privateKey });
assert.strictEqual(secret.toString('hex'),
'0099d0fa242af5db9ea7330e23937a27db041f79c581500fc7f9976' +
'554d59d5b9ced934778d72e19a1fefc81e9d981013198748c0b5c6c' +
'762985eec687dc5bec5c9367b05837daee9d0bcc29024ed7f3abba1' +
'2794b65a745117fb0d87bc5b1b2b68c296c3f686cc29e450e4e1239' +
'21f56a5733fe58aabf71f14582954059c2185d342b9b0fa10c2598a' +
'5426c2baee7f9a686fc1e16cd4757c852bf7225a2732250548efe28' +
'debc26f1acdec51efe23d20786a6f8a14d360803bbc71972e87fd3');
}
// Test ECDH.
test(crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }),
crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }));
assert.throws(() => {
test(crypto.generateKeyPairSync('ec', { namedCurve: 'secp256k1' }),
crypto.generateKeyPairSync('ec', { namedCurve: 'secp224k1' }));
}, {
name: 'Error',
code: 'ERR_OSSL_EVP_DIFFERENT_PARAMETERS'
});
// Test ECDH-ES.
test(crypto.generateKeyPairSync('x448'),
crypto.generateKeyPairSync('x448'));
test(crypto.generateKeyPairSync('x25519'),
crypto.generateKeyPairSync('x25519'));
assert.throws(() => {
test(crypto.generateKeyPairSync('x448'),
crypto.generateKeyPairSync('x25519'));
}, {
name: 'Error',
code: 'ERR_CRYPTO_INCOMPATIBLE_KEY',
message: 'Incompatible key types for Diffie-Hellman: x448 and x25519'
});