Hi Viktor,
On 7/8/26 08:04, Viktor Dukhovni wrote:
On Tue, Jul 07, 2026 at 10:27:56PM -0700, Christian Huitema wrote:
I just read Jacob Applebaum's message. Given his description of the
late-standardization suspicious change that looks like a backdoor in the
ML-KEM specification, I agree with his conclusion. The WG should not ask for
publication of the current graph, not until the changes requested by Jacob
are made.
The removal of whitening of the `m` random input to Encaps is not a
plausible backdoor.
I note that you do not dispute that it is a plausible covert channel. It
does not appear to be in dispute that this covert channel is only
possible by removing the hash over `m`. I called this a `backdoor
accommodation` and not a `backdoor` in my official comments to NIST in
2023. The trick I have described requires "mistakes" at multiple layers.
This kind of problem coincidentally diffuses responsibility so that
involved parties may plausible simply shrug at the resulting security
issues. I encourage the IETF to not shrug but to mitigate as the
original Kyber designers intended.
It is my understanding from a Kyber author that _not_ using the system
RNG directly was an explicit goal, and that the hash was put into Kyber
_exactly_ to stop this kind of covert channel from being used by a
Dual_EC_DRBG-shaped kleptographic construction.
That same author of Kyber explained to me that NIST motivated removal of
the hash over `m` by discussing the analysis of ML-KEM together with a
secure RNG considered together as one primitive. Thus the hash function
wouldn't be needed because by definition, `m` was always going to be
safe. It is very logical and it appeals to a notion of efficiency. It is
also dangerous and it is certainly not worth the risk given the history.
If all you have is a broken RNG, you're free to
apply whitening to obtain a new less bad RNG and use that instead.
If a client has a broken RNG then its ephemeral ML-KEM key pair is at
risk, indeed. However, if the server has a _sabotaged_ RNG which is a
special class of RNG failures relevant to the IETF's history with
Dual_EC_DRBG, any TLS client can obtain ciphertexts derived from fresh
server RNG output with this change.
Let us assume that the RNG in question is Dual_EC_DRBG or a similar
kleptographic construction. An implementation of Dual_EC_DRBG with the
NIST SP 800-90A points is still present today in at least one widely
deployed cryptographic library, as I cited in my previous email. I trust
that this isn't in dispute. That same library implements ML-KEM but it
does not appear to use Dual_EC_DRBG by default, thankfully.
Unfortunately, the Dual_EC_DRBG kind of sabotage becomes exploitable
exactly because of NIST's removal of the hash function. What is
interesting is that when ML-KEM is used in TLS 1.3, then the client is
able to obtain ML-KEM ciphertexts derived from fresh server RNG output;
because the client generated the corresponding ephemeral decapsulation
key and can instrument its own decapsulation, it can recover the
internal `m` value chosen by the server encapsulation.
The client can repeat this process many times, and such queries look
like ordinary TLS 1.3 ML-KEM handshakes. This is almost an ideal
cryptographic oracle and querying it will blend in with normal TLS 1.3
ML-KEM protected traffic.
If the recovered `m` value leaks enough RNG state in one go, any client
that can exploit Dual_EC_DRBG will be able to do so once it has
accumulated enough bits. As it just so happens, ML-KEM's `m` is 32 bytes
and a suitably truncated 30-byte value can be enough with roughly ~2^16
trial work in the classic Dual_EC_DRBG P-256 recovery setting.
If the `m` value was hashed, this would not be possible.
So is that an issue with ML-KEM or TLS 1.3's use of ML-KEM?
The answer is that _NIST_ had to change Kyber's design for this result,
and thus TLS 1.3 should take this reality into account. Together we see
the practical result.
Nothing stops an ML-KEM implementation from hashing some input (any
number of times, mixing in whatever additional inputs, ...) to produce
its random values.
The patent situation may make this less simple for implementers than it
sounds; some implementers will be reluctant to deviate from the exact
standardized algorithm and associated IPR terms. That may stop many
implementers from deviating from the standardized algorithm.
Please see FIPS 203 Section 6.2, Algorithm 17, and the informal
description below it and FIPS 203 section 7.2, Algorithm 20. Algorithm
20 specifically notes that readers should read Section 3.3. On page 15
in Section 3.3, NIST states: "While conforming implementations must
adhere to all of these requirements, adherence does not guarantee that
the result will be secure" and goes on to say on page 16:
"Randomness generation. Two algorithms in this standard require the
generation of randomness as an internal step: ML-KEM.KeyGen and
ML-KEM.Encaps. In pseudocode, this randomness generation is denoted by a
statement of the form 𝑚 ←− 𝔹32 . A fresh string of random bytes
must be generated for every such invocation. These random bytes shall be
generated using an approved RBG, as prescribed in SP 800-90A, SP
800-90B, and SP 800-90C [18, 19, 20]. Moreover, this RBG shall have a
security strength of at least 128 bits for ML-KEM-512, at least 192 bits
for ML-KEM-768, and at least 256 bits for ML-KEM-1024."
Notably, this NIST statement from FIPS 203 cites SP 800-90A, whose
earlier history is directly relevant to this concern. That is the very
publication that used to contain Dual_EC_DRBG until public reporting on
the Snowden documents connected Dual_EC_DRBG to the broader PROJECT
BULLRUN context. NIST presumably means to cite the latest SP 800-90A
without the widely reported cryptographic sabotage associated with
Dual_EC_DRBG. Note however again that just because an implementation
conforms to all of the requirements, they don't guarantee that the
result will be secure. I think it is fair to read that as saying they
also don't guarantee that the results will be secure if you deviate from
meeting the standard's requirements.
Additionally please see page 47 of Appendix C section C.1 and please
carefully read all four bullet points. NIST says in C.1 that it is
_required_ to use NIST-approved randomness generation.
Why do their requirements matter? The patent/IPR situation is one
reason. FIPS 203 explicitly says NIST entered into two patent license
agreements to facilitate adoption of CRYSTALS-Kyber/ML-KEM.
What do nearly all ML-KEM implementations do as a result? Most
implementations removed the hash over `m` as NIST's changes to the
specification _require_ if you implement it "correctly" following their
change to `ML-KEM.Encaps`. They define ML-KEM, after all.
> The abstract algorithm starts from the final output> of an adequate
RNG that requires no further post-processing.
I do not think FIPS 203 supports that distinction. That distinction
seems to be a semantic game because the "abstract algorithm" is defined
by FIPS 203. That's ML-KEM, full stop.
NIST changed Kyber’s Encaps() Algorithm 8 [0] by removing the hash over
`m`; in FIPS 203, public ML-KEM.Encaps samples `m` and passes it to
`ML-KEM.Encaps_internal()`. NIST freely states this fact which is not in
dispute. In "Kyber.CCAKEM.Enc" defined in Algorithm 8 Kyber's designers
directly stated on page 9 "Do not send output of system RNG" - this
statement remains in the second round design [1], in the third round
design document [2], in version 3.01 [3], and in version 3.02 [4]. I
assume you are familiar with the relevant specifications.
NIST does not claim that their change isn't to "the abstract algorithm"
but rather they simply justify it as secure by qualifying it with a
requirement. That NIST requirement isn't explicitly stated as required
in the draft under discussion, why not? Isn't that requirement why some
of the Kyber team found this to be an acceptable change?
Furthermore, what you're calling "the abstract algorithm" is a
distinction that does not address the practical consequences of this
change by NIST in finalizing FIPS 203. That change was _required_ to
make this exploitable as described. I strongly think the Kyber team
should not have accepted this change from NIST. This change means that
the intended security of ML-KEM can be practically bypassed without
attacking the lattice hardness assumptions. It also has knock-on effects
for subsequent secrets of any cryptographic primitive used after `m` is
sampled from the system RNG.
Your analysis is also ignoring that patent licenses are an extremely
important motivator for a handful of important implementations. Are you
asserting that variants of `ML-KEM.Encaps()` that restore `m ← H(m)`
would be covered by the NIST patent license? If so, on what basis do you
claim that? Such a conclusion would be positive news and indeed, we
could simply put the hash on `m` again, and be done with the topic.
There's nothing suspicious about this simplification.
The original Kyber design included the hash, and the public Kyber
specification says "Do not send output of system RNG." Removing that
step reopens exactly the class of RNG-output channel that this line
avoided. See page 10 for algorithm 8, step 2 "m ← H(m)" which again is
noted as "Do not send output of system RNG" in the Algorithm definition.
The critique in
question makes no sense to me.
That right there is the crux of the issue! Do you need to see an
implementation with working exploit?
> Don't use a broken RNG.>
You can use a good one, and the server can use a bad one _without
knowing it_ because that is how cryptographic sabotage is deployed in
the real world. Things get worse in the Encrypted Client Hello (ECH)
scenario as both sides sample the other's respective system RNG by
ensuring both sides send a ciphertext produced by ML-KEM.Encaps().
The most obvious fix is simple: Fix ML-KEM.Encaps by restoring the `m ←
H(m)` step before `ML-KEM.Encaps_internal()` is called. The draft could
easily state this as a concrete security mitigation exactly to avoid
even the mere appearance of the Dual_EC_DRBG/Extended Random situation
repeating.
Kind regards,
Jacob Appelbaum
[0] https://pq-crystals.org/kyber/data/kyber-specification.pdf
[1] https://pq-crystals.org/kyber/data/kyber-specification-round2.pdf
[2] https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf
[3]
https://pq-crystals.org/kyber/data/kyber-specification-round3-20210131.pdf
[4]
https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
_______________________________________________
TLS mailing list -- [email protected]
To unsubscribe send an email to [email protected]