Skip to content

Commit 18133e1

Browse files
committed
crypto: add ML-KEM KeyObject support (keygen, import, export)
Note: import and export in JWK format is not supported yet
1 parent 517305b commit 18133e1

21 files changed

+629
-5
lines changed

deps/ncrypto/ncrypto.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#include <cstring>
1212
#if OPENSSL_VERSION_MAJOR >= 3
1313
#include <openssl/provider.h>
14+
#if OPENSSL_VERSION_MINOR >= 5
15+
#include <crypto/ml_kem.h>
16+
#endif
1417
#endif
1518

1619
// EVP_PKEY_CTX_set_dsa_paramgen_q_bits was added in OpenSSL 1.1.1e.
@@ -1949,6 +1952,9 @@ int EVPKeyPointer::id(const EVP_PKEY* key) {
19491952
if (EVP_PKEY_is_a(key, "ML-DSA-44")) return EVP_PKEY_ML_DSA_44;
19501953
if (EVP_PKEY_is_a(key, "ML-DSA-65")) return EVP_PKEY_ML_DSA_65;
19511954
if (EVP_PKEY_is_a(key, "ML-DSA-87")) return EVP_PKEY_ML_DSA_87;
1955+
if (EVP_PKEY_is_a(key, "ML-KEM-512")) return EVP_PKEY_ML_KEM_512;
1956+
if (EVP_PKEY_is_a(key, "ML-KEM-768")) return EVP_PKEY_ML_KEM_768;
1957+
if (EVP_PKEY_is_a(key, "ML-KEM-1024")) return EVP_PKEY_ML_KEM_1024;
19521958
}
19531959
#endif
19541960
return type;

deps/ncrypto/ncrypto.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#endif // OPENSSL_FIPS
3030

3131
#if OPENSSL_VERSION_MAJOR >= 3
32+
#if OPENSSL_VERSION_MINOR >= 5
33+
#include <crypto/ml_kem.h>
34+
#endif
3235
#define OSSL3_CONST const
3336
#else
3437
#define OSSL3_CONST

doc/api/crypto.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,6 +1916,9 @@ This can be called many times with new data as it is streamed.
19161916
<!-- YAML
19171917
added: v11.6.0
19181918
changes:
1919+
- version: REPLACEME
1920+
pr-url: https://github.com/nodejs/node/pull/00000
1921+
description: Add support for ML-KEM keys.
19191922
- version: REPLACEME
19201923
pr-url: https://github.com/nodejs/node/pull/00000
19211924
description: Add support for ML-DSA keys.
@@ -2024,6 +2027,9 @@ Other key details might be exposed via this API using additional attributes.
20242027
<!-- YAML
20252028
added: v11.6.0
20262029
changes:
2030+
- version: REPLACEME
2031+
pr-url: https://github.com/nodejs/node/pull/00000
2032+
description: Add support for ML-KEM keys.
20272033
- version: REPLACEME
20282034
pr-url: https://github.com/nodejs/node/pull/00000
20292035
description: Add support for ML-DSA keys.
@@ -2064,6 +2070,9 @@ types are:
20642070
* `'ml-dsa-44'`[^openssl35] (OID 2.16.840.1.101.3.4.3.17)
20652071
* `'ml-dsa-65'`[^openssl35] (OID 2.16.840.1.101.3.4.3.18)
20662072
* `'ml-dsa-87'`[^openssl35] (OID 2.16.840.1.101.3.4.3.19)
2073+
* `'ml-kem-512'`[^openssl35] (OID 2.16.840.1.101.3.4.4.1)
2074+
* `'ml-kem-768'`[^openssl35] (OID 2.16.840.1.101.3.4.4.2)
2075+
* `'ml-kem-1024'`[^openssl35] (OID 2.16.840.1.101.3.4.4.3)
20672076

20682077
This property is `undefined` for unrecognized `KeyObject` types and symmetric
20692078
keys.
@@ -2134,6 +2143,8 @@ encryption mechanism, PEM-level encryption is not supported when encrypting
21342143
a PKCS#8 key. See [RFC 5208][] for PKCS#8 encryption and [RFC 1421][] for
21352144
PKCS#1 and SEC1 encryption.
21362145

2146+
Note: ML-KEM keys JWK export is not yet supported.
2147+
21372148
### `keyObject.symmetricKeySize`
21382149

21392150
<!-- YAML
@@ -3412,6 +3423,9 @@ input.on('readable', () => {
34123423
<!-- YAML
34133424
added: v11.6.0
34143425
changes:
3426+
- version: REPLACEME
3427+
pr-url: https://github.com/nodejs/node/pull/00000
3428+
description: Add support for ML-KEM keys.
34153429
- version: REPLACEME
34163430
pr-url: https://github.com/nodejs/node/pull/00000
34173431
description: Add support for ML-DSA keys.
@@ -3446,13 +3460,16 @@ must be an object with the properties described above.
34463460
If the private key is encrypted, a `passphrase` must be specified. The length
34473461
of the passphrase is limited to 1024 bytes.
34483462

3449-
Note: ML-DSA keys JWK import is not yet supported.
3463+
Note: ML-DSA and ML-KEM keys JWK import is not yet supported.
34503464

34513465
### `crypto.createPublicKey(key)`
34523466

34533467
<!-- YAML
34543468
added: v11.6.0
34553469
changes:
3470+
- version: REPLACEME
3471+
pr-url: https://github.com/nodejs/node/pull/00000
3472+
description: Add support for ML-KEM keys.
34563473
- version: REPLACEME
34573474
pr-url: https://github.com/nodejs/node/pull/00000
34583475
description: Add support for ML-DSA keys.
@@ -3501,7 +3518,7 @@ extracted from the returned `KeyObject`. Similarly, if a `KeyObject` with type
35013518
`'private'` is given, a new `KeyObject` with type `'public'` will be returned
35023519
and it will be impossible to extract the private key from the returned object.
35033520

3504-
Note: ML-DSA keys JWK import is not yet supported.
3521+
Note: ML-DSA and ML-KEM keys JWK import is not yet supported.
35053522

35063523
### `crypto.createSecretKey(key[, encoding])`
35073524

@@ -3667,6 +3684,9 @@ underlying hash function. See [`crypto.createHmac()`][] for more information.
36673684
<!-- YAML
36683685
added: v10.12.0
36693686
changes:
3687+
- version: REPLACEME
3688+
pr-url: https://github.com/nodejs/node/pull/00000
3689+
description: Add support for ML-KEM key pairs.
36703690
- version: REPLACEME
36713691
pr-url: https://github.com/nodejs/node/pull/00000
36723692
description: Add support for ML-DSA key pairs.
@@ -3725,7 +3745,8 @@ changes:
37253745
* `privateKey`: {string | Buffer | KeyObject}
37263746

37273747
Generates a new asymmetric key pair of the given `type`. RSA, RSA-PSS, DSA, EC,
3728-
Ed25519, Ed448, X25519, X448, and DH are currently supported.
3748+
Ed25519, Ed448, X25519, X448, DH, ML-DSA[^openssl35], and ML-KEM[^openssl35]
3749+
are currently supported.
37293750

37303751
If a `publicKeyEncoding` or `privateKeyEncoding` was specified, this function
37313752
behaves as if [`keyObject.export()`][] had been called on its result. Otherwise,
@@ -3789,6 +3810,9 @@ a `Promise` for an `Object` with `publicKey` and `privateKey` properties.
37893810
<!-- YAML
37903811
added: v10.12.0
37913812
changes:
3813+
- version: REPLACEME
3814+
pr-url: https://github.com/nodejs/node/pull/00000
3815+
description: Add support for ML-KEM key pairs.
37923816
- version: REPLACEME
37933817
pr-url: https://github.com/nodejs/node/pull/00000
37943818
description: Add support for ML-DSA key pairs.
@@ -3818,7 +3842,8 @@ changes:
38183842

38193843
* `type`: {string} Must be `'rsa'`, `'rsa-pss'`, `'dsa'`, `'ec'`, `'ed25519'`,
38203844
`'ed448'`, `'x25519'`, `'x448'`, `'dh'`, `'ml-dsa-44'`[^openssl35],
3821-
`'ml-dsa-65'`[^openssl35], or `'ml-dsa-87'`[^openssl35].
3845+
`'ml-dsa-65'`[^openssl35], `'ml-dsa-87'`[^openssl35], `'ml-kem-512'`[^openssl35],
3846+
`'ml-kem-768'`[^openssl35], and `'ml-kem-1024'`[^openssl35].
38223847
* `options`: {Object}
38233848
* `modulusLength`: {number} Key size in bits (RSA, DSA).
38243849
* `publicExponent`: {number} Public exponent (RSA). **Default:** `0x10001`.
@@ -3842,7 +3867,8 @@ changes:
38423867
* `privateKey`: {string | Buffer | KeyObject}
38433868

38443869
Generates a new asymmetric key pair of the given `type`. RSA, RSA-PSS, DSA, EC,
3845-
Ed25519, Ed448, X25519, X448, DH, and ML-DSA[^openssl35] are currently supported.
3870+
Ed25519, Ed448, X25519, X448, DH, ML-DSA[^openssl35], and ML-KEM[^openssl35]
3871+
are currently supported.
38463872

38473873
If a `publicKeyEncoding` or `privateKeyEncoding` was specified, this function
38483874
behaves as if [`keyObject.export()`][] had been called on its result. Otherwise,

lib/internal/crypto/keygen.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ const {
2222
EVP_PKEY_ML_DSA_44,
2323
EVP_PKEY_ML_DSA_65,
2424
EVP_PKEY_ML_DSA_87,
25+
EVP_PKEY_ML_KEM_512,
26+
EVP_PKEY_ML_KEM_768,
27+
EVP_PKEY_ML_KEM_1024,
2528
EVP_PKEY_X25519,
2629
EVP_PKEY_X448,
2730
OPENSSL_EC_NAMED_CURVE,
@@ -173,6 +176,9 @@ const ids = {
173176
'ml-dsa-44': EVP_PKEY_ML_DSA_44,
174177
'ml-dsa-65': EVP_PKEY_ML_DSA_65,
175178
'ml-dsa-87': EVP_PKEY_ML_DSA_87,
179+
'ml-kem-512': EVP_PKEY_ML_KEM_512,
180+
'ml-kem-768': EVP_PKEY_ML_KEM_768,
181+
'ml-kem-1024': EVP_PKEY_ML_KEM_1024,
176182
};
177183

178184
function createJob(mode, type, options) {
@@ -294,6 +300,9 @@ function createJob(mode, type, options) {
294300
case 'ml-dsa-44':
295301
case 'ml-dsa-65':
296302
case 'ml-dsa-87':
303+
case 'ml-kem-512':
304+
case 'ml-kem-768':
305+
case 'ml-kem-1024':
297306
{
298307
if (ids[type] === undefined) {
299308
throw new ERR_INVALID_ARG_VALUE('type', type, 'must be a supported key type');

src/crypto/crypto_keys.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,12 @@ Local<Value> KeyObjectHandle::GetAsymmetricKeyType() const {
919919
return env()->crypto_ml_dsa_65_string();
920920
case EVP_PKEY_ML_DSA_87:
921921
return env()->crypto_ml_dsa_87_string();
922+
case EVP_PKEY_ML_KEM_512:
923+
return env()->crypto_ml_kem_512_string();
924+
case EVP_PKEY_ML_KEM_768:
925+
return env()->crypto_ml_kem_768_string();
926+
case EVP_PKEY_ML_KEM_1024:
927+
return env()->crypto_ml_kem_1024_string();
922928
#endif
923929
default:
924930
return Undefined(env()->isolate());
@@ -1199,6 +1205,9 @@ void Initialize(Environment* env, Local<Object> target) {
11991205
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_DSA_44);
12001206
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_DSA_65);
12011207
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_DSA_87);
1208+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_KEM_512);
1209+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_KEM_768);
1210+
NODE_DEFINE_CONSTANT(target, EVP_PKEY_ML_KEM_1024);
12021211
#endif
12031212
NODE_DEFINE_CONSTANT(target, EVP_PKEY_X25519);
12041213
NODE_DEFINE_CONSTANT(target, EVP_PKEY_X448);

src/env_properties.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@
118118
V(crypto_ml_dsa_44_string, "ml-dsa-44") \
119119
V(crypto_ml_dsa_65_string, "ml-dsa-65") \
120120
V(crypto_ml_dsa_87_string, "ml-dsa-87") \
121+
V(crypto_ml_kem_512_string, "ml-kem-512") \
122+
V(crypto_ml_kem_768_string, "ml-kem-768") \
123+
V(crypto_ml_kem_1024_string, "ml-kem-1024") \
121124
V(crypto_x25519_string, "x25519") \
122125
V(crypto_x448_string, "x448") \
123126
V(crypto_rsa_string, "rsa") \

test/fixtures/keys/Makefile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,18 @@ all: \
110110
ml_dsa_87_private_seed_only.pem \
111111
ml_dsa_87_private_priv_only.pem \
112112
ml_dsa_87_public.pem \
113+
ml_kem_512_private.pem \
114+
ml_kem_512_private_seed_only.pem \
115+
ml_kem_512_private_priv_only.pem \
116+
ml_kem_512_public.pem \
117+
ml_kem_768_private.pem \
118+
ml_kem_768_private_seed_only.pem \
119+
ml_kem_768_private_priv_only.pem \
120+
ml_kem_768_public.pem \
121+
ml_kem_1024_private.pem \
122+
ml_kem_1024_private_seed_only.pem \
123+
ml_kem_1024_private_priv_only.pem \
124+
ml_kem_1024_public.pem \
113125

114126
#
115127
# Create Certificate Authority: ca1
@@ -903,6 +915,42 @@ ml_dsa_87_private_priv_only.pem: ml_dsa_87_private.pem
903915
ml_dsa_87_public.pem: ml_dsa_87_private.pem
904916
openssl pkey -in ml_dsa_87_private.pem -pubout -out ml_dsa_87_public.pem
905917

918+
ml_kem_512_private.pem:
919+
openssl genpkey -algorithm ml-kem-512 -out ml_kem_512_private.pem
920+
921+
ml_kem_512_private_seed_only.pem: ml_kem_512_private.pem
922+
openssl pkey -in ml_kem_512_private.pem -provparam ml-kem.output_formats=seed-only -out ml_kem_512_private_seed_only.pem
923+
924+
ml_kem_512_private_priv_only.pem: ml_kem_512_private.pem
925+
openssl pkey -in ml_kem_512_private.pem -provparam ml-kem.output_formats=priv-only -out ml_kem_512_private_priv_only.pem
926+
927+
ml_kem_512_public.pem: ml_kem_512_private.pem
928+
openssl pkey -in ml_kem_512_private.pem -pubout -out ml_kem_512_public.pem
929+
930+
ml_kem_768_private.pem:
931+
openssl genpkey -algorithm ml-kem-768 -out ml_kem_768_private.pem
932+
933+
ml_kem_768_private_seed_only.pem: ml_kem_768_private.pem
934+
openssl pkey -in ml_kem_768_private.pem -provparam ml-kem.output_formats=seed-only -out ml_kem_768_private_seed_only.pem
935+
936+
ml_kem_768_private_priv_only.pem: ml_kem_768_private.pem
937+
openssl pkey -in ml_kem_768_private.pem -provparam ml-kem.output_formats=priv-only -out ml_kem_768_private_priv_only.pem
938+
939+
ml_kem_768_public.pem: ml_kem_768_private.pem
940+
openssl pkey -in ml_kem_768_private.pem -pubout -out ml_kem_768_public.pem
941+
942+
ml_kem_1024_private.pem:
943+
openssl genpkey -algorithm ml-kem-1024 -out ml_kem_1024_private.pem
944+
945+
ml_kem_1024_private_seed_only.pem: ml_kem_1024_private.pem
946+
openssl pkey -in ml_kem_1024_private.pem -provparam ml-kem.output_formats=seed-only -out ml_kem_1024_private_seed_only.pem
947+
948+
ml_kem_1024_private_priv_only.pem: ml_kem_1024_private.pem
949+
openssl pkey -in ml_kem_1024_private.pem -provparam ml-kem.output_formats=priv-only -out ml_kem_1024_private_priv_only.pem
950+
951+
ml_kem_1024_public.pem: ml_kem_1024_private.pem
952+
openssl pkey -in ml_kem_1024_private.pem -pubout -out ml_kem_1024_public.pem
953+
906954
x448_private.pem:
907955
openssl genpkey -algorithm x448 -out x448_private.pem
908956

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
-----BEGIN PRIVATE KEY-----
2+
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
70+
cJM=
71+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)