Skip to content

crypto: support derandomized ML-KEM encapsulation#64207

Open
dotCooCoo wants to merge 1 commit into
nodejs:mainfrom
dotCooCoo:crypto-mlkem-encapsulate-entropy
Open

crypto: support derandomized ML-KEM encapsulation#64207
dotCooCoo wants to merge 1 commit into
nodejs:mainfrom
dotCooCoo:crypto-mlkem-encapsulate-entropy

Conversation

@dotCooCoo

Copy link
Copy Markdown

Summary

Adds an entropy option to crypto.encapsulate() for derandomized (deterministic)
ML-KEM encapsulation, mapping to OpenSSL 3.5's OSSL_KEM_PARAM_IKME (FIPS 203 §6.2
Encaps_internal). The same entropy + public key + algorithm deterministically produce
the same ciphertext and sharedKey — needed for known-answer testing and for hybrid
KEMs such as X-Wing (draft-connolly-cfrg-xwing-kem), which are defined in terms of
ML-KEM's internal encapsulation.

The existing randomized encapsulate(key) / encapsulate(key, callback) forms are
unchanged; the new shape is encapsulate(key, { entropy }). The 32-byte buffer is threaded
through KEMEncapsulateJobncrypto::KEM::Encapsulate and set on the EVP_PKEY_CTX
before EVP_PKEY_encapsulate, gated on OpenSSL >= 3.5 (OPENSSL_WITH_KEM_IKME). The binding
enforces an exactly-32-byte length and is ML-KEM-only; the randomized path is byte-identical
to today (an absent/undefined entropy takes the existing CSPRNG path).

Docs and tests are included (determinism, decapsulate round-trip, both length bounds,
empty/undefined handling, and type rejection). Built and tested locally on Windows with
OpenSSL 3.5.7; test/parallel/test-crypto-encap-decap.js passes.

Fixes: #64206

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/crypto
  • @nodejs/security-wg

@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Jun 30, 2026
Add an `entropy` option to `crypto.encapsulate()` that injects the 32-byte
message m as OSSL_KEM_PARAM_IKME, selecting FIPS 203 (6.2) Encaps_internal
derandomized encapsulation. The same entropy, public key, and algorithm
then deterministically produce the same ciphertext and shared key, which
is required for known-answer testing and for protocols such as X-Wing.

The existing randomized `encapsulate(key)` and `encapsulate(key, callback)`
forms are unchanged; the new shape is `encapsulate(key, { entropy })`. The
buffer is threaded through KEMEncapsulateJob into ncrypto::KEM::Encapsulate
and set on the EVP_PKEY_CTX before EVP_PKEY_encapsulate. It is gated on
OpenSSL >= 3.5 (OPENSSL_WITH_KEM_IKME) and is not supported for RSA, EC,
X25519, or X448 keys. The binding rejects an entropy buffer that is not
exactly 32 bytes.

Fixes: nodejs#64206
Signed-off-by: dotCooCoo <robertleelw@gmail.com>
@dotCooCoo dotCooCoo force-pushed the crypto-mlkem-encapsulate-entropy branch from 00a3ccd to 69e5174 Compare June 30, 2026 03:36

@panva panva left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://docs.openssl.org/3.6/man7/EVP_KEM-ML-KEM/#ml-kem-kem-parameters
This parameter should not be used for purposes other than testing.

https://www.ietf.org/archive/id/draft-connolly-cfrg-xwing-kem-10.html#name-derandomized
For testing, it is convenient to have a deterministic version of encapsulation. An X-Wing implementation MAY provide the following derandomized function.

This is distinctly only for test vector validation, as such I don't think it's worth the churn in node:crypto. Hybrid KEMs do not make use of it other than vector testing either.

@dotCooCoo

Copy link
Copy Markdown
Author

That's a fair point @panva. I wasn't thinking of this as a production feature so much as exposing a testing primitive that OpenSSL already provides.

The main use case I had in mind was deterministic vector validation and interoperability/regression testing. Today that requires dropping down to OpenSSL or another implementation, even though the underlying capability already exists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

crypto: support derandomized ML-KEM encapsulation in crypto.encapsulate()

3 participants