diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 2456e34a27e8c5..177ce106af599e 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1129,6 +1129,9 @@ passing keys as strings or `Buffer`s due to improved security features. -* `type`: {string} Must be `'rsa'`, `'dsa'`, `'ec'`, `'ed25519'`, or `'ed448'`. +* `type`: {string} Must be `'rsa'`, `'dsa'`, `'ec'`, `'ed25519'`, `'ed448'`, + `'x25519'`, or `'x448'`. * `options`: {Object} - `modulusLength`: {number} Key size in bits (RSA, DSA). - `publicExponent`: {number} Public exponent (RSA). **Default:** `0x10001`. diff --git a/lib/internal/crypto/keygen.js b/lib/internal/crypto/keygen.js index efa6c6c31b854b..80efa01b1b7aa1 100644 --- a/lib/internal/crypto/keygen.js +++ b/lib/internal/crypto/keygen.js @@ -8,6 +8,8 @@ const { generateKeyPairEdDSA, EVP_PKEY_ED25519, EVP_PKEY_ED448, + EVP_PKEY_X25519, + EVP_PKEY_X448, OPENSSL_EC_NAMED_CURVE, OPENSSL_EC_EXPLICIT_CURVE } = internalBinding('crypto'); @@ -197,8 +199,24 @@ function check(type, options, callback) { break; case 'ed25519': case 'ed448': + case 'x25519': + case 'x448': { - const id = type === 'ed25519' ? EVP_PKEY_ED25519 : EVP_PKEY_ED448; + let id; + switch (type) { + case 'ed25519': + id = EVP_PKEY_ED25519; + break; + case 'ed448': + id = EVP_PKEY_ED448; + break; + case 'x25519': + id = EVP_PKEY_X25519; + break; + case 'x448': + id = EVP_PKEY_X448; + break; + } impl = (wrap) => generateKeyPairEdDSA(id, publicFormat, publicType, privateFormat, privateType, @@ -208,7 +226,7 @@ function check(type, options, callback) { default: throw new ERR_INVALID_ARG_VALUE('type', type, "must be one of 'rsa', 'dsa', 'ec', " + - "'ed25519', 'ed448'"); + "'ed25519', 'ed448', 'x25519', 'x448'"); } if (options) { diff --git a/src/env.h b/src/env.h index 70c566dce9a08f..aa64befebf320c 100644 --- a/src/env.h +++ b/src/env.h @@ -146,6 +146,8 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; V(crypto_ec_string, "ec") \ V(crypto_ed25519_string, "ed25519") \ V(crypto_ed448_string, "ed448") \ + V(crypto_x25519_string, "x25519") \ + V(crypto_x448_string, "x448") \ V(crypto_rsa_string, "rsa") \ V(cwd_string, "cwd") \ V(data_string, "data") \ diff --git a/src/node_crypto.cc b/src/node_crypto.cc index d4d0af4795484b..026e41a3ec6770 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3451,6 +3451,10 @@ Local KeyObject::GetAsymmetricKeyType() const { return env()->crypto_ed25519_string(); case EVP_PKEY_ED448: return env()->crypto_ed448_string(); + case EVP_PKEY_X25519: + return env()->crypto_x25519_string(); + case EVP_PKEY_X448: + return env()->crypto_x448_string(); default: CHECK(false); } @@ -6336,6 +6340,8 @@ void Initialize(Local target, env->SetMethod(target, "generateKeyPairEdDSA", GenerateKeyPairEdDSA); NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED25519); NODE_DEFINE_CONSTANT(target, EVP_PKEY_ED448); + NODE_DEFINE_CONSTANT(target, EVP_PKEY_X25519); + NODE_DEFINE_CONSTANT(target, EVP_PKEY_X448); NODE_DEFINE_CONSTANT(target, OPENSSL_EC_NAMED_CURVE); NODE_DEFINE_CONSTANT(target, OPENSSL_EC_EXPLICIT_CURVE); NODE_DEFINE_CONSTANT(target, kKeyEncodingPKCS1); diff --git a/test/fixtures/test_x25519_privkey.pem b/test/fixtures/test_x25519_privkey.pem new file mode 100644 index 00000000000000..b2f60cca40e547 --- /dev/null +++ b/test/fixtures/test_x25519_privkey.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VuBCIEILD/13Y5R/tmcCjZVSooIcpfGvZxf+qt6dMu5FYaOC1a +-----END PRIVATE KEY----- diff --git a/test/fixtures/test_x25519_pubkey.pem b/test/fixtures/test_x25519_pubkey.pem new file mode 100644 index 00000000000000..3d1e7b835e14ec --- /dev/null +++ b/test/fixtures/test_x25519_pubkey.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VuAyEAYHCXnz085FKclfnx+gdiGXAyy7BhJjx0pxyE4wbXF0A= +-----END PUBLIC KEY----- diff --git a/test/fixtures/test_x448_privkey.pem b/test/fixtures/test_x448_privkey.pem new file mode 100644 index 00000000000000..39c507d2b8d5d6 --- /dev/null +++ b/test/fixtures/test_x448_privkey.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MEYCAQAwBQYDK2VvBDoEOPilLIAZTQqUbFb0LhTGaqn47zN2p2yGVk+2hhQQk9C8 +8SvFqEFw73YITSIJ2NUBZnZKNz2nGkrm +-----END PRIVATE KEY----- diff --git a/test/fixtures/test_x448_pubkey.pem b/test/fixtures/test_x448_pubkey.pem new file mode 100644 index 00000000000000..841c2bb66b5bfd --- /dev/null +++ b/test/fixtures/test_x448_pubkey.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MEIwBQYDK2VvAzkAbceBBM+LkveTK09QojZdnHokCh7lOWxyVZrlbH3Ny3WorprD +Iir5A6heZzlRnz1elOHp7ZpPfWk= +-----END PUBLIC KEY----- diff --git a/test/parallel/test-crypto-key-objects.js b/test/parallel/test-crypto-key-objects.js index 7075f4a2201d40..fb1c3de1d7e224 100644 --- a/test/parallel/test-crypto-key-objects.js +++ b/test/parallel/test-crypto-key-objects.js @@ -174,7 +174,13 @@ const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii'); keyType: 'ed25519' }, { private: fixtures.readSync('test_ed448_privkey.pem', 'ascii'), public: fixtures.readSync('test_ed448_pubkey.pem', 'ascii'), - keyType: 'ed448' } + keyType: 'ed448' }, + { private: fixtures.readSync('test_x25519_privkey.pem', 'ascii'), + public: fixtures.readSync('test_x25519_pubkey.pem', 'ascii'), + keyType: 'x25519' }, + { private: fixtures.readSync('test_x448_privkey.pem', 'ascii'), + public: fixtures.readSync('test_x448_pubkey.pem', 'ascii'), + keyType: 'x448' } ].forEach((info) => { const keyType = info.keyType; diff --git a/test/parallel/test-crypto-keygen.js b/test/parallel/test-crypto-keygen.js index ae29c9af40ad5a..7a164dffe9059b 100644 --- a/test/parallel/test-crypto-keygen.js +++ b/test/parallel/test-crypto-keygen.js @@ -425,7 +425,8 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); type: TypeError, code: 'ERR_INVALID_ARG_VALUE', message: "The argument 'type' must be one of " + - "'rsa', 'dsa', 'ec', 'ed25519', 'ed448'. Received 'rsa2'" + "'rsa', 'dsa', 'ec', 'ed25519', 'ed448'," + + " 'x25519', 'x448'. Received 'rsa2'" }); } @@ -786,7 +787,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher); // Test EdDSA key generation. { if (!/^1\.1\.0/.test(process.versions.openssl)) { - ['ed25519', 'ed448'].forEach((keyType) => { + ['ed25519', 'ed448', 'x25519', 'x448'].forEach((keyType) => { generateKeyPair(keyType, common.mustCall((err, publicKey, privateKey) => { assert.ifError(err);