CyStack logo
  • Products & Services
  • Solutions
  • Pricing
  • Company
  • Resources
En

en

Threats & Research

What Actually Changes When You Migrate to Post-Quantum Cryptography

CyStack image

Sumit Giri

AI Security Engineer | LLM Security · Adversarial ML · Secure AI Deployment | Cryptography|April 28, 2026
Reading Time: 8 minutes

PQC migration is not a config change. It is three different problems layered on top of each other — and most teams only see the first one.

This series is from one of our Security Research – Sumit Giri PhD experience and demonstration. You can explore further from his series about Post-Quantum Cryptography from his personal Medium’s page

In Part 1 of this series, I covered the mathematical foundations of ML-KEM and ML-DSA — the lattice problems they rest on, why the NIST standardization process took eight years, and why the threat from quantum computers is real before a cryptographically relevant machine exists. If you haven’t read it, it covers the “why.” This article is the “what changes.”

A server rack full of intranet and internet connection. The image reference to Post-Quantum Cryptography Connection.
Post-Quantum Cryptography Connection. Photo by Tyler from Unsplash.

I recently gave a talk at TASK 2026 on PQC in practice. Preparing for it forced me to go beyond reading papers and start reasoning carefully about what migration actually requires of a real engineering team. What I found is that most of the framing I had seen in the industry — “just update your cipher suite” — describes only the shallowest layer of the problem.

This article covers the three layers of PQC migration complexity, the specific ML-DSA API changes that will break existing signing pipelines, and why crypto agility is an infrastructure investment, not a project milestone.

The Problem Is Not the Algorithm. It Is the Assumption.

Most systems treat cryptographic algorithms as a fixed property — chosen once, baked in, revisited only when something breaks. RSA-2048 is in the TLS config. ECDSA P-256 is in the code signing pipeline. AES-128 is in the database encryption layer. Nobody has touched these in years because they work and there is no visible reason to change them.

This assumption — that cryptographic stability is a feature — is precisely what makes PQC migration hard.

The threat model has two timelines that operate independently of each other:

The first is the arrival of a cryptographically relevant quantum computer (CRQC). Estimates vary. Most serious researchers put this somewhere between 10 and 20 years. This timeline is uncertain, and it is the one people argue about.

The second is the data exposure window. This is not uncertain at all. Medical records have regulatory retention requirements of decades. Defense communications are classified for longer. Financial audit trails, long-term contracts, and intellectual property — all of these have confidentiality lifetimes that extend well past any reasonable estimate for when a CRQC arrives.

The intersection of these two timelines is the actual problem. An adversary does not need a quantum computer today. They need only to record your encrypted traffic now and wait. This attack has a name — Harvest Now, Decrypt Later — and it is the reason the NSA issued its first migration warning in 2015, nine years before NIST published its first finalized PQC standards.

NIST IR 8547, currently in draft, puts concrete policy dates on the consequence: RSA and ECDSA are deprecated for new systems by 2030 and disallowed entirely by 2035. In January 2026, CISA issued guidance under Executive Order 14306 requiring federal agencies to procure only PQC-capable products in categories where they are already widely available — cloud services, web servers, browsers, and endpoint encryption are on that list now.

This is not a US-only policy story. The Canadian Centre for Cyber Security published its PQC migration roadmap for the Government of Canada with equally concrete milestones: federal departments must develop an initial PQC migration plan by April 2026, complete migration of high-priority systems by end of 2031, and complete migration of all remaining systems by end of 2035. The Cyber Centre’s position is unambiguous — every organization managing IT systems must migrate to become quantum-safe, and standardized PQC is the recommended path. For Canadian federal departments and any organization in their supply chain, the planning deadline is not years away. It is this month.

The comfortable window to start planning is not closing. For some data, it has already closed.

Three Layers of Migration Complexity

When I started preparing the talk, I expected the migration story to be straightforward: swap the algorithm name in the config, recompile, test, done. The reality is three layers deep, and most teams stop at the first one.

Layer 1 — Config and API (the easy part)

For TLS endpoints running OpenSSL 3.5 — released April 2025, the first version with native PQC without third-party patches — enabling hybrid post-quantum key exchange is genuinely close to a configuration change.

# nginx.conf — enable hybrid ML-KEM-768 + X25519 key exchange
ssl_ecdh_curve X25519MLKEM768:X25519;

That is the entire change for a web server. The application code does not change. The TLS protocol version does not change. Clients that do not support X25519MLKEM768 fall back to X25519 automatically. This is the right place to start any PQC migration, and it is deployable today.

The equivalent in curl:

curl --curves X25519MLKEM768 https://your-server.com

This layer is real and it matters — but it covers only one scenario: TLS key exchange at a modern endpoint with up-to-date software. Everything else is harder.

Layer 2 — Data flow and size (where the real constraints appear)

PQC algorithms produce substantially larger keys and signatures than their classical equivalents. This is not a bandwidth nuisance — it is an architectural constraint that touches multiple layers of infrastructure simultaneously.

A table with data of size comparison. Artifact between Public key, Signature, TLS Client and Cert Chain
PQC key and signature size comparison table

Each of these numbers has a downstream consequence worth naming explicitly.

1,600-byte ClientHello can exceed MTU limits in constrained network environments, causing IP fragmentation before the TLS session is established. RFC 9242 (IKEv2 Intermediate Exchange) exists specifically because this problem appeared in VPN deployments when PQ key shares were added.

1,184-byte ML-KEM-768 public key blows past the buffer sizes in most current hardware security modules. HSMs were designed around 32–64 byte ECC keys. Most require firmware or hardware upgrades to handle PQ material — and for some older devices, the upgrade path does not exist. This is the single most common gating constraint I hear about from teams doing real migration planning.

The 17 KB ML-DSA certificate chain is an active problem. The IETF TLS Working Group is debating certificate compression and suppression mechanisms. Until those land and become widely deployed, PQ certificates add significant per-connection overhead that classical compression cannot fully offset.

Layer 3 — Application type (where one algorithm choice does not fit all)

The right algorithm depends on the system. Not every workload should use the same PQC algorithm, the same way not every workload uses the same symmetric cipher.

Algorithm selection by application type
Algorithm selection by application type

SLH-DSA (SPHINCS+) warrants a specific note because its public key is tiny — 32 bytes — which looks attractive at first glance. Its signature is 7,856 bytes and signing runs at roughly 90 operations per second. That makes it excellent for long-lived, infrequent signing: root CA certificates, firmware trust anchors, software release signing. It is completely wrong for anything that signs at high frequency, like TLS certificates in a busy PKI or API request signing in a microservices architecture.

The ML-DSA API Change That Will Break Your Signing Pipeline

This is the section that most reliably surprises engineers who have been told PQC migration is a configuration problem. It is not, for signatures. Moving from ECDSA to ML-DSA requires updating every signing call site in your codebase, and the failure mode when you miss one is silent.

The interface change is specific. ECDSA signing takes a message and a private key. ML-DSA signing takes a message, a private key, and a new mandatory parameter — a context string.

# ECDSA — two arguments
signature = ecdsa_sign(message, private_key)
# Output: 64 bytes, deterministic — same message always produces same signature

# ML-DSA — three arguments, context string is new and mandatory
signature = mldsa_sign(message, private_key, context_string)
# Output: 3,309 bytes (ML-DSA-65), non-deterministic

The context string is up to 255 bytes with no equivalent in any classical scheme. Existing wrappers that assume a two-argument signature function will not fail at compile time — they will fail at runtime, silently, in ways that depend on how the library handles the missing argument. In some implementations the context defaults to empty and signs anyway, producing a valid signature for the wrong context. In others it throws. Either way, the behaviour is not what you intended.

Three additional implications worth knowing before you touch a signing pipeline:

Non-determinism. ECDSA with RFC 6979 is deterministic — the same message and key always produce the same signature. ML-DSA uses rejection sampling internally, so the same inputs produce a different valid signature each time. Any test that compares signatures byte-for-byte will fail. Tests need to be rewritten to verify mathematically — call the verify function, do not compare outputs.

Pre-hash mode carries a different OID. If you have a pattern where hashing happens on one system and signing happens on an HSM — common in high-throughput signing pipelines where the data is too large to transfer — that pattern needs to be redesigned. HashML-DSA is a distinct algorithm with its own OID, not a mode of ML-DSA. You cannot split the hash from the sign across a trust boundary the way ECDSA allows.

Side-channel scope is larger. ECDSA’s sensitive operations are well-understood and well-bounded — the scalar multiplication is the primary target. ML-DSA’s rejection sampling and NTT operations require side-channel protection across a significantly larger portion of the computation. Expect higher latency in secure hardware implementations, and verify your HSM vendor’s timing characteristics before deploying.

# Verify your OpenSSL version supports ML-DSA (requires 3.5+)
openssl list -signature-algorithms | grep -i mldsa

# Generate an ML-DSA-65 key pair
openssl genpkey -algorithm ML-DSA-65 -out mldsa65_private.pem
openssl pkey -in mldsa65_private.pem -pubout -out mldsa65_public.pem

# Sign a file
openssl dgst -sign mldsa65_private.pem -out signature.bin message.txt

# Verify — returns "Verified OK" if valid
openssl dgst -verify mldsa65_public.pem -signature signature.bin message.txt

Crypto Agility — Not a Project, a Capability

The section of the talk that generated the most follow-up questions was crypto agility. I want to be precise about what this means because it is often described as a vague aspiration in vendor materials and conference talks.

Crypto agility is the ability to replace cryptographic algorithms in running systems without redesigning those systems. NIST defines it in CSWP 39. RFC 7696 formalizes it. The reason it matters beyond PQC is stated plainly in CISA’s January 2026 guidance: they will update the product category list periodically. NIST IR 8547 schedules RSA and ECDSA deprecation for 2030 and disallows them by 2035 — but a cryptanalytic break could accelerate that timeline without any policy process.

If your cryptographic choices are hard-coded into application logic, every one of those updates requires a code change, a test cycle, and a deployment. If they are abstracted behind a provider interface, it is a configuration change.

# BAD — algorithm hard-coded, zero agility
from cryptography.hazmat.primitives.asymmetric import ec
private_key = ec.generate_private_key(ec.SECP256R1())

# BETTER — algorithm from config, swappable without touching code
import config
from crypto_provider import get_kem_algorithm

kem = get_kem_algorithm(config.get("kem_algorithm", "X25519MLKEM768"))
public_key, private_key = kem.generate_keypair()

Five patterns that make agility real rather than aspirational:

Isolate crypto logic behind a provider interface. OpenSSL providers, JCA in Java, CNG in Windows — these exist precisely to make algorithm selection a runtime concern rather than a compile-time one. The algorithm name should live in configuration, not in code.

Embed algorithm identifiers in every key and certificate object. Consumers of cryptographic material must be able to identify what algorithm was used without out-of-band coordination. This is what OIDs in X.509 certificates do — it needs to extend to internal key storage formats, secrets managers, and HSM key labels as well.

Support hybrid negotiation in protocols. TLS 1.3, IKEv2 (RFC 9370), and SSH all have algorithm negotiation built in. Enable multiple groups. Let the protocol select the strongest mutual option. This gives backward compatibility with existing clients and forward agility for new ones simultaneously.

Automate key and certificate lifecycle. Agility fails at scale if rotation requires manual intervention. Certificate managers — HashiCorp Vault, EJBCA, cert-manager in Kubernetes — need to be evaluated and updated for PQ OID support before you need to rotate, not after.

Maintain a Crypto SBOM. Enumerate all cryptographic dependencies per service: library name, version, algorithm, key type, protocol version. Tools like semgrep with crypto-specific rulesets, testssl.sh for TLS endpoint scanning, and CycloneDX SBOM extensions can automate significant portions of this. That document is your checklist when an algorithm is deprecated — without it, you are discovering your exposure reactively under pressure.

Where to Go From Here

The three layers I covered here — config and API, data flow and size, application type — represent the scoping work that should happen before any code is touched. The crypto agility patterns are the engineering investment that makes migration sustainable across multiple rounds of algorithm change, not just this one.

Part 3 of this series covers the hands-on side: running a live PQ TLS connection to Google’s production servers using Docker, reading the handshake output, and the real benchmark numbers from comparing ML-KEM and ML-DSA against classical algorithms on the same machine.

Connect on LinkedIn or GitHub. If you are working through a PQC migration and have specific questions about HSM evaluation, certificate lifecycle, or language-specific integrations, I am always open to a conversation.

Read the Vietnamese version / Đọc bản tiếng Việt tại đây

Related posts

Analysis of Suspected Malware Linked to APT-Q-27 Targeting Financial Institutions

Reading Time: 12 minutesĐọc bản tiếng Việt tại đây Overview Context In mid-January 2026, CyStack’s security team observed anomalous activity on a corporate […]

The attack on ONUS – A real-life case of the Log4Shell vulnerability

Reading Time: 6 minutesĐọc bản tiếng Việt tại đây Log4Shell has recently been a nightmare (probably the worst one for now) to businesses. […]

Static binary injection with high-level code
Static binary injection with high-level code
April 29 2026|Threats & Research

Reading Time: 8 minutesGiới thiệu Static binary injection là một kỹ thuật dùng để chèn những đoạn code từ ngoài vào trong một […]