crypto: support derandomized ML-KEM encapsulation#64207
Conversation
|
Review requested:
|
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>
00a3ccd to
69e5174
Compare
panva
left a comment
There was a problem hiding this comment.
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.
|
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. |
Summary
Adds an
entropyoption tocrypto.encapsulate()for derandomized (deterministic)ML-KEM encapsulation, mapping to OpenSSL 3.5's
OSSL_KEM_PARAM_IKME(FIPS 203 §6.2Encaps_internal). The sameentropy+ public key + algorithm deterministically producethe same
ciphertextandsharedKey— needed for known-answer testing and for hybridKEMs such as X-Wing (
draft-connolly-cfrg-xwing-kem), which are defined in terms ofML-KEM's internal encapsulation.
The existing randomized
encapsulate(key)/encapsulate(key, callback)forms areunchanged; the new shape is
encapsulate(key, { entropy }). The 32-byte buffer is threadedthrough
KEMEncapsulateJob→ncrypto::KEM::Encapsulateand set on theEVP_PKEY_CTXbefore
EVP_PKEY_encapsulate, gated on OpenSSL >= 3.5 (OPENSSL_WITH_KEM_IKME). The bindingenforces an exactly-32-byte length and is ML-KEM-only; the randomized path is byte-identical
to today (an absent/
undefinedentropytakes the existing CSPRNG path).Docs and tests are included (determinism, decapsulate round-trip, both length bounds,
empty/
undefinedhandling, and type rejection). Built and tested locally on Windows withOpenSSL 3.5.7;
test/parallel/test-crypto-encap-decap.jspasses.Fixes: #64206