Harvest Now, Decrypt Later: What JEP 527 Hybrid Key Exchange Protects and What It Doesn’t
An attacker does not need a quantum computer today to threaten your data. They only need a disk. If they record your encrypted traffic now, they can wait until a quantum computer exists and decrypt it later.
JDK 27 answers this threat with JEP 527, which adds hybrid post-quantum key exchange to TLS 1.3. However, it solves only part of the problem. In this article, we look at what it protects, what it leaves untouched, and why certificates and signatures need a separate migration.
The Threat: Harvest Now, Decrypt Later
Every TLS connection begins with a key exchange, which creates the shared secret that encrypts the session. According to JEP 527, a hybrid scheme combines a quantum-resistant algorithm with a traditional one, and it stays secure as long as one of them remains unbroken. The risk comes from Shor’s algorithm, which, as JEP 497 explains, could compromise widely used public-key algorithms on a large future quantum computer.
Consequently, traffic captured today with a classical key exchange could be opened later. That is why key exchange is the urgent part.
What JEP 527 Adds
The facts
JEP 527, titled “Post-Quantum Hybrid Key Exchange for TLS 1.3”, is marked completed for JDK 27. The Inside Java announcement lists three new hybrid groups: X25519MLKEM768, SecP256r1MLKEM768 and SecP384r1MLKEM1024. By default, X25519MLKEM768 is enabled and sits first, so a client offers two key shares: one hybrid and one plain x25519.
Moreover, applications that use the javax.net.ssl APIs benefit without code changes. A hands-on report on Amazon Corretto 27, which became generally available on September 17, 2026, confirmed this in JDK debug logs. Its OpenSSL 3.5 test server selected X25519MLKEM768 on a default setup.
Why hybrid, and what it builds on
The JEP builds on the KEM API from Java 21 (JEP 452) and ML-KEM from Java 24 (JEP 496). It deliberately avoids pure ML-KEM exchanges. Also, the JEP admits that the IETF specifications were still drafts when it was written, so the details could still evolve.
What It Does Not Protect
| Item | Covered by JEP 527? | Why |
|---|---|---|
| Recorded TLS 1.3 sessions that used a hybrid group | Yes | The shared secret no longer depends on classical math alone |
| Connections where the peer lacks hybrid support | No | The default list still includes classical groups, so a handshake can fall back |
| Server certificates and their signatures | No | The JEP changes key exchange only |
| TLS 1.2 and earlier | No | The JEP targets TLS 1.3 |
| Non-TLS data, such as stored files | No | A hybrid KEM outside TLS 1.3 is a stated non-goal |
Signatures are a separate migration
Here is the key idea. A forged signature only helps an attacker who can break it at the moment of the connection, so authentication does not suffer from “harvest now, decrypt later” in the same way. That is my reasoning, not a quote, but it explains why key exchange moved first.
Even so, signatures will need to change. ML-DSA has been in the JDK since Java 24 through JEP 497, as part of the KeyPairGenerator, Signature and KeyFactory APIs. Having the algorithm does not migrate your certificate chain, though, because certificate authorities, clients and your own systems must all move together.
A Snippet You Can Run
JEP 527 itself needs JDK 27, but its building block is available today. This program performs an ML-KEM-768 exchange with the standard KEM API. It needs Java 24 or newer, and it prints ciphertext bytes: 1088 and secrets match: true.
cat > Kem.java <<'JAVA'
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Arrays;
import javax.crypto.KEM;
public class Kem {
public static void main(String[] args) throws Exception {
KeyPair kp = KeyPairGenerator.getInstance("ML-KEM-768")
.generateKeyPair();
KEM kem = KEM.getInstance("ML-KEM-768");
KEM.Encapsulated sent = kem.newEncapsulator(kp.getPublic())
.encapsulate();
var received = kem.newDecapsulator(kp.getPrivate())
.decapsulate(sent.encapsulation());
System.out.println("ciphertext bytes: "
+ sent.encapsulation().length);
System.out.println("secrets match: " + Arrays.equals(
sent.key().getEncoded(), received.getEncoded()));
}
}
JAVA
java Kem.java
I ran it on JDK 25 and got exactly those two lines. On JDK 21 it fails with “ML-KEM-768 KeyPairGenerator not available”, which confirms the Java 24 requirement.
What the Numbers Say
Key exchange: small and quick
I measured the building blocks on JDK 25. I could not run JEP 527 itself, because JDK 27 is not available in my sandbox, so these are component numbers, not handshake benchmarks.
| Operation | X25519 | ML-KEM-768 |
|---|---|---|
| Public key, encoded | 44 bytes | 1,206 bytes |
| Ciphertext | none | 1,088 bytes |
| Key generation | 370 µs | 156 µs |
| Agree or encapsulate | 225 µs | 193 µs |
| Decapsulate | none | 125 µs |

The hybrid share is about 1.2 KB, compared with 32 bytes for x25519 alone. Since JDK 27 sends both shares by default, that adds up to 1,248 bytes. In return, the computation stays comparable, and ML-KEM was even a little faster in this JDK-level test. In short, protecting key exchange is cheap.
Signatures: a much bigger bill
| Algorithm | Public key | Signature | Sign | Verify |
|---|---|---|---|---|
| ML-DSA-65 | 1,974 B | 3,309 B | 529 µs | 396 µs |
| ECDSA P-256 | 91 B | 71 B | 552 µs | 1,347 µs |
| RSA-2048 | 294 B | 256 B | 1,260 µs | 57 µs |
| Ed25519 | 44 B | 64 B | 648 µs | 703 µs |

The speed of ML-DSA is fine, so computation is not the problem. Size is. A two-certificate chain with a CertificateVerify signature needs about 395 bytes with ECDSA P-256 and about 13,875 bytes with ML-DSA-65, roughly 35 times more. That growth explains why the signature migration is harder and slower, even though the algorithm already exists.
A Practical Order of Work
First, move to JDK 27 or later so that hybrid key exchange is on by default, then confirm the negotiated group in the JDK debug logs. Next, inventory every place where you rely on signatures, including certificates, tokens and code signing. Finally, plan that migration on its own schedule, because it depends on partners and certificate authorities, not only on your JDK.
Quick checklist
- Upgrade to JDK 27 to get hybrid key exchange by default.
- Check debug logs to see which group each connection selected.
- Remember that peers without hybrid support can still fall back.
- Do not call your service quantum-safe while certificates are classical.
- Start a separate plan for signatures and certificates.
What We Have Learned
“Harvest now, decrypt later” targets recorded traffic, so key exchange is the urgent part of the post-quantum migration. JEP 527 delivers that in JDK 27 by adding hybrid groups to TLS 1.3, with X25519MLKEM768 first by default, and it protects sessions as long as one of the two algorithms stays unbroken. It does not change certificates or signatures, it does not cover TLS 1.2 or data outside TLS, and it cannot protect connections where the peer falls back to classical groups. In our measurements, hybrid key exchange added about 1.2 KB with similar compute time, while an ML-DSA certificate chain was roughly 35 times larger than an ECDSA one. So, adopt JEP 527 now, and start the signature migration as its own project.

