From 0e435115ca1918c9dadfcea4a877e0ee53177726 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Sun, 12 Apr 2026 14:29:55 +0200 Subject: [PATCH] crypto: add JWK support for ML-KEM and SLH-DSA key types Signed-off-by: Filip Skokan --- benchmark/crypto/kem.js | 3 - doc/api/crypto.md | 42 ++-- doc/api/webcrypto.md | 18 +- lib/internal/crypto/ml_kem.js | 14 ++ lib/internal/crypto/webcrypto.js | 6 + node.gyp | 4 +- src/crypto/crypto_keys.cc | 36 ++- src/crypto/crypto_ml_dsa.cc | 165 ------------- src/crypto/crypto_ml_dsa.h | 23 -- src/crypto/crypto_pqc.cc | 180 ++++++++++++++ src/crypto/crypto_pqc.h | 23 ++ src/node_crypto.h | 2 +- test/fixtures/keys/Makefile | 51 ++++ test/fixtures/keys/ml-dsa-44.json | 6 + test/fixtures/keys/ml-dsa-65.json | 6 + test/fixtures/keys/ml-dsa-87.json | 6 + test/fixtures/keys/ml-kem-1024.json | 6 + test/fixtures/keys/ml-kem-512.json | 6 + test/fixtures/keys/ml-kem-768.json | 6 + test/fixtures/keys/slh-dsa-sha2-128f.json | 6 + test/fixtures/keys/slh-dsa-sha2-128s.json | 6 + test/fixtures/keys/slh-dsa-sha2-192f.json | 6 + test/fixtures/keys/slh-dsa-sha2-192s.json | 6 + test/fixtures/keys/slh-dsa-sha2-256f.json | 6 + test/fixtures/keys/slh-dsa-sha2-256s.json | 6 + test/fixtures/keys/slh-dsa-shake-128f.json | 6 + test/fixtures/keys/slh-dsa-shake-128s.json | 6 + test/fixtures/keys/slh-dsa-shake-192f.json | 6 + test/fixtures/keys/slh-dsa-shake-192s.json | 6 + test/fixtures/keys/slh-dsa-shake-256f.json | 6 + test/fixtures/keys/slh-dsa-shake-256s.json | 6 + test/parallel/test-crypto-encap-decap.js | 10 +- .../test-crypto-pqc-key-objects-ml-dsa.js | 68 +----- .../test-crypto-pqc-key-objects-ml-kem.js | 69 +++++- .../test-crypto-pqc-key-objects-slh-dsa.js | 62 ++++- .../parallel/test-crypto-pqc-keygen-ml-kem.js | 19 ++ .../test-crypto-pqc-keygen-slh-dsa.js | 22 ++ .../test-webcrypto-export-import-ml-dsa.js | 52 +--- .../test-webcrypto-export-import-ml-kem.js | 222 ++++++++++++++++-- 39 files changed, 842 insertions(+), 357 deletions(-) delete mode 100644 src/crypto/crypto_ml_dsa.cc delete mode 100644 src/crypto/crypto_ml_dsa.h create mode 100644 src/crypto/crypto_pqc.cc create mode 100644 src/crypto/crypto_pqc.h create mode 100644 test/fixtures/keys/ml-dsa-44.json create mode 100644 test/fixtures/keys/ml-dsa-65.json create mode 100644 test/fixtures/keys/ml-dsa-87.json create mode 100644 test/fixtures/keys/ml-kem-1024.json create mode 100644 test/fixtures/keys/ml-kem-512.json create mode 100644 test/fixtures/keys/ml-kem-768.json create mode 100644 test/fixtures/keys/slh-dsa-sha2-128f.json create mode 100644 test/fixtures/keys/slh-dsa-sha2-128s.json create mode 100644 test/fixtures/keys/slh-dsa-sha2-192f.json create mode 100644 test/fixtures/keys/slh-dsa-sha2-192s.json create mode 100644 test/fixtures/keys/slh-dsa-sha2-256f.json create mode 100644 test/fixtures/keys/slh-dsa-sha2-256s.json create mode 100644 test/fixtures/keys/slh-dsa-shake-128f.json create mode 100644 test/fixtures/keys/slh-dsa-shake-128s.json create mode 100644 test/fixtures/keys/slh-dsa-shake-192f.json create mode 100644 test/fixtures/keys/slh-dsa-shake-192s.json create mode 100644 test/fixtures/keys/slh-dsa-shake-256f.json create mode 100644 test/fixtures/keys/slh-dsa-shake-256s.json diff --git a/benchmark/crypto/kem.js b/benchmark/crypto/kem.js index e03ae65f1926ca..ffdcac6d7fcb0d 100644 --- a/benchmark/crypto/kem.js +++ b/benchmark/crypto/kem.js @@ -54,9 +54,6 @@ const bench = common.createBenchmark(main, { // assess whether mutexes over the key material impact the operation if (p.keyFormat === 'keyObject.unique') return p.mode === 'async-parallel'; - // JWK is not supported for ml-kem for now - if (p.keyFormat === 'jwk') - return !p.keyType.startsWith('ml-'); // raw-public is only supported for encapsulate, not rsa if (p.keyFormat === 'raw-public') return p.keyType !== 'rsa' && p.op === 'encapsulate'; diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 84e5520186dbb6..b421d12fc7ab38 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -88,23 +88,23 @@ The following table lists the asymmetric key types recognized by the | `'ml-dsa-44'`[^openssl35] | ML-DSA-44 | 2.16.840.1.101.3.4.3.17 | ✔ | ✔ | ✔ | ✔ | | ✔ | | `'ml-dsa-65'`[^openssl35] | ML-DSA-65 | 2.16.840.1.101.3.4.3.18 | ✔ | ✔ | ✔ | ✔ | | ✔ | | `'ml-dsa-87'`[^openssl35] | ML-DSA-87 | 2.16.840.1.101.3.4.3.19 | ✔ | ✔ | ✔ | ✔ | | ✔ | -| `'ml-kem-512'`[^openssl35] | ML-KEM-512 | 2.16.840.1.101.3.4.4.1 | ✔ | ✔ | | ✔ | | ✔ | -| `'ml-kem-768'`[^openssl35] | ML-KEM-768 | 2.16.840.1.101.3.4.4.2 | ✔ | ✔ | | ✔ | | ✔ | -| `'ml-kem-1024'`[^openssl35] | ML-KEM-1024 | 2.16.840.1.101.3.4.4.3 | ✔ | ✔ | | ✔ | | ✔ | +| `'ml-kem-512'`[^openssl35] | ML-KEM-512 | 2.16.840.1.101.3.4.4.1 | ✔ | ✔ | ✔ | ✔ | | ✔ | +| `'ml-kem-768'`[^openssl35] | ML-KEM-768 | 2.16.840.1.101.3.4.4.2 | ✔ | ✔ | ✔ | ✔ | | ✔ | +| `'ml-kem-1024'`[^openssl35] | ML-KEM-1024 | 2.16.840.1.101.3.4.4.3 | ✔ | ✔ | ✔ | ✔ | | ✔ | | `'rsa-pss'` | RSA PSS | 1.2.840.113549.1.1.10 | ✔ | ✔ | | | | | | `'rsa'` | RSA | 1.2.840.113549.1.1.1 | ✔ | ✔ | ✔ | | | | -| `'slh-dsa-sha2-128f'`[^openssl35] | SLH-DSA-SHA2-128f | 2.16.840.1.101.3.4.3.21 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-sha2-128s'`[^openssl35] | SLH-DSA-SHA2-128s | 2.16.840.1.101.3.4.3.20 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-sha2-192f'`[^openssl35] | SLH-DSA-SHA2-192f | 2.16.840.1.101.3.4.3.23 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-sha2-192s'`[^openssl35] | SLH-DSA-SHA2-192s | 2.16.840.1.101.3.4.3.22 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-sha2-256f'`[^openssl35] | SLH-DSA-SHA2-256f | 2.16.840.1.101.3.4.3.25 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-sha2-256s'`[^openssl35] | SLH-DSA-SHA2-256s | 2.16.840.1.101.3.4.3.24 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-shake-128f'`[^openssl35] | SLH-DSA-SHAKE-128f | 2.16.840.1.101.3.4.3.27 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-shake-128s'`[^openssl35] | SLH-DSA-SHAKE-128s | 2.16.840.1.101.3.4.3.26 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-shake-192f'`[^openssl35] | SLH-DSA-SHAKE-192f | 2.16.840.1.101.3.4.3.29 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-shake-192s'`[^openssl35] | SLH-DSA-SHAKE-192s | 2.16.840.1.101.3.4.3.28 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-shake-256f'`[^openssl35] | SLH-DSA-SHAKE-256f | 2.16.840.1.101.3.4.3.31 | ✔ | ✔ | | ✔ | ✔ | | -| `'slh-dsa-shake-256s'`[^openssl35] | SLH-DSA-SHAKE-256s | 2.16.840.1.101.3.4.3.30 | ✔ | ✔ | | ✔ | ✔ | | +| `'slh-dsa-sha2-128f'`[^openssl35] | SLH-DSA-SHA2-128f | 2.16.840.1.101.3.4.3.21 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-sha2-128s'`[^openssl35] | SLH-DSA-SHA2-128s | 2.16.840.1.101.3.4.3.20 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-sha2-192f'`[^openssl35] | SLH-DSA-SHA2-192f | 2.16.840.1.101.3.4.3.23 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-sha2-192s'`[^openssl35] | SLH-DSA-SHA2-192s | 2.16.840.1.101.3.4.3.22 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-sha2-256f'`[^openssl35] | SLH-DSA-SHA2-256f | 2.16.840.1.101.3.4.3.25 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-sha2-256s'`[^openssl35] | SLH-DSA-SHA2-256s | 2.16.840.1.101.3.4.3.24 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-shake-128f'`[^openssl35] | SLH-DSA-SHAKE-128f | 2.16.840.1.101.3.4.3.27 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-shake-128s'`[^openssl35] | SLH-DSA-SHAKE-128s | 2.16.840.1.101.3.4.3.26 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-shake-192f'`[^openssl35] | SLH-DSA-SHAKE-192f | 2.16.840.1.101.3.4.3.29 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-shake-192s'`[^openssl35] | SLH-DSA-SHAKE-192s | 2.16.840.1.101.3.4.3.28 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-shake-256f'`[^openssl35] | SLH-DSA-SHAKE-256f | 2.16.840.1.101.3.4.3.31 | ✔ | ✔ | ✔ | ✔ | ✔ | | +| `'slh-dsa-shake-256s'`[^openssl35] | SLH-DSA-SHAKE-256s | 2.16.840.1.101.3.4.3.30 | ✔ | ✔ | ✔ | ✔ | ✔ | | | `'x25519'` | X25519 | 1.3.101.110 | ✔ | ✔ | ✔ | ✔ | ✔ | | | `'x448'` | X448 | 1.3.101.111 | ✔ | ✔ | ✔ | ✔ | ✔ | | @@ -2397,6 +2397,10 @@ type, value, and parameters. This method is not