Post-Quantum Cryptography — an engineering course

Part 2: The Cryptography You Need Before Learning PQC

Part 2 of 18 · beginner

Sep 11, 2026 · security · 19 min read · 3821 words beginner

The cryptography you need before learning PQC.

security post-quantum cryptography tls

Cryptography is a collection of narrow contracts, and most confusion about "is this secure" comes from silently swapping one contract for another. A hash does not authenticate its publisher. Encryption does not necessarily detect modification. A valid signature does not decide whether its signing key should be trusted in the first place. This chapter builds that vocabulary precisely — confidentiality vs. integrity vs. authenticity, hashes vs. MACs vs. signatures, raw Diffie–Hellman vs. an authenticated key exchange — with a reproducible OpenSSL lab at the end. Learn these contracts now, and every post-quantum replacement in Parts 7–12 becomes a much smaller conceptual jump: you're swapping the math underneath a contract you already understand, not learning a new contract from scratch.

1. Objectives and prerequisites

This chapter assumes you can run a command in a shell and recognize a client/server connection — nothing more. By the end, you should be able to trace how an application turns secret material into authenticated traffic, explain how a certificate connects a name to a key, and identify exactly which steps change during a PQC migration and which don't. Part 1 supplied the landscape; no lattice mathematics is needed here — that starts in Part 4.

Keep the records service from Part 1 in mind. When its engineers say "encrypt the file," the first question worth asking is: protection from what? Unauthorized reading, undetected modification, false attribution, replay, and deletion are five different threats, and a useful cryptographic design states the threat and its trust assumptions before reaching for a library call — not after.

2. Three goals, three questions

Confidentiality asks whether an unauthorized observer can learn protected information — it does not promise that metadata, message size, timing, or the mere existence of a connection is hidden. Integrity asks whether unauthorized modifications are detected. Authenticity asks whether information or participation is attributable to an authorized source under the system's trust model. Three different questions, three different mechanisms, and conflating any two of them is where real designs go wrong.

These goals interact without ever becoming identical. A public software release may need authenticity without confidentiality at all — nobody's trying to hide it, but everybody needs to know it's genuine. A private record needs confidentiality and integrity: a malicious change to an account number is harmful even when an attacker never learns the record's contents. Availability is a fourth requirement entirely, orthogonal to all three — correct authentication cannot make an unreachable service answer requests.

Cryptographic security definitions make these goals precise by describing an attacker, the information and interfaces available to them, and a success condition — this is far more useful than asking whether an algorithm is "strong" in the abstract, a question with no defined answer. Part 4 introduces the standard security games formally. For a deeper foundational treatment, Boneh and Shoup's free applied cryptography book is the reference this course leans on most.

3. Entropy: uncertainty is a resource

A secret key should be unpredictable to the adversary — and its storage length alone tells you nothing about that. A 256-bit buffer filled with the same public constant has zero useful secret uncertainty, no matter how long it is. A password converted into a long hexadecimal string doesn't acquire additional entropy just because its representation grew longer.

A cryptographic random generator expands carefully obtained entropy into pseudorandom output, appropriate when its construction, state handling, and seeding all meet the required assumptions. This is a fundamentally different tool from a simulation-oriented random generator, whose outputs can be predictable after observing a small amount of internal state — the two are not interchangeable, ever, no matter how "random-looking" the simulation output is. Timestamps and process identifiers are not substitutes for a cryptographic entropy source. NIST separates entropy-source assessment from deterministic generator mechanisms in SP 800-90B and SP 800-90A.

Randomness requirements also vary by operation, not just by "is this a key." Key generation needs unpredictable secret material. Some signature schemes need carefully generated per-message randomness; others derive it deterministically under specified rules to avoid a whole class of randomness-failure attacks. A nonce is frequently required to be unique rather than secret — quietly replacing "unique" with "random" without checking the collision probability at your actual message volume can silently violate the intended contract. We return to this exact distinction in the signature chapters (Parts 8–9) and the implementation-security chapter (Part 13).

4. Hashes: fingerprints with a limited promise

A cryptographic hash maps a message to a fixed-size digest. The useful security goals are preimage resistance, second-preimage resistance, and collision resistance — three different questions: finding any input for a target digest, finding another input matching a given message, or finding any pair of distinct messages that collide. A digest is not encryption — there's no decryption key that reverses it, and asking "how do I decrypt this hash" is a category error.

Suppose a release page publishes a file and its SHA-256 digest. Recomputing the digest detects accidental corruption and verifies agreement with that published value. But if an attacker controls both the file and the page, they simply replace both together — the digest has not authenticated the publisher at all. The missing ingredient is an independently authenticated value, such as a digest embedded in a signed build manifest that the attacker can't also forge.

The rule that generalizes: always ask who vouches for the expected hash, and how that vouching itself is protected. A digest in a trusted, signed build manifest and a digest downloaded from the same compromised web page carry completely different security meaning, even though both are "SHA-256 of the file." SHA-256 remains useful throughout PQC systems, but the exact security property and output length needed must match the construction using it — hash-based signatures (Part 9) combine many carefully separated hash invocations under a specific tree structure; they are not simply "hash the document and trust it." See FIPS 180-4.

5. MACs and HMAC: authentication with a shared secret

A message authentication code (MAC) computes a tag using a secret shared by participants; a verifier who knows that same secret checks the tag. HMAC is a standardized construction built around a cryptographic hash — it is not the ad hoc, insecure idea of "just hash the secret followed by the message." Its specified inner and outer processing steps matter and exist specifically to defeat length-extension-style attacks against the underlying hash. See RFC 2104.

For our records service, HMAC can authenticate messages between two components that already share a suitable key. But either holder of that shared key can produce valid tags — a MAC gives you no way to prove after the fact which of the two parties actually sent a given message, unlike a public-key signature. Shared-key distribution, rotation, and access control therefore remain central to using a MAC safely, not an afterthought.

Authentication also does not automatically stop replay. If the same validly-tagged request can be submitted twice, its tag remains just as valid the second time. A protocol has to separately authenticate a sequence number, timestamp, request identifier, or state transition, and enforce a freshness policy on top of that. Cryptography binds the fields together; the application decides which field combinations are acceptable. Leaving a transaction amount outside the authenticated data defeats the intended protection completely, even when the MAC implementation itself is flawless.

6. Symmetric encryption and authenticated encryption

Symmetric encryption uses shared secret key material to transform plaintext into ciphertext. A block cipher like AES is a building block, not a complete file format on its own — its surrounding mode specifies how messages of arbitrary length actually get processed. Some encryption modes are malleable: an attacker who can't read the plaintext can still predictably flip specific plaintext bits by modifying ciphertext, without ever learning the key.

Authenticated encryption with associated data (AEAD) combines confidentiality and integrity for the protected payload while also authenticating separate, unencrypted "associated data." Its conceptual inputs are a key, nonce, plaintext, and associated data; decryption produces either plaintext or an explicit failure — never a silent, wrong plaintext. Associated data might carry a protocol version or record header that must stay readable in the clear but must never be silently modified. See RFC 5116.

Nonce discipline is part of the security contract, not an implementation detail. A library that technically accepts the same nonce twice does not mean reuse is safe — for constructions like AES-GCM, nonce reuse under one key can catastrophically compromise both confidentiality and authenticity for every message that shared it. Applications must also respect stated usage limits and handle authentication failure by discarding the plaintext entirely, never delivering unauthenticated bytes as if they were trusted. See SP 800-38D.

Our service therefore needs a record format, explicit key ownership, nonce allocation strategy, defined error behavior, and a recovery plan — PQC migration does not replace any of these responsibilities. Establishing a stronger, post-quantum session secret and then reusing an AEAD nonce can still fully compromise the channel; the new key establishment doesn't protect a broken usage pattern downstream. The safe engineering path is always a maintained protocol implementation that already correctly defines these interactions — not a custom assembly of individually-plausible primitives.

7. Key derivation: one secret, separated purposes

A key derivation function turns input keying material into keys suitable for specific, defined uses. HKDF separates extraction from expansion: extraction produces a uniform pseudorandom key from input material that may not itself be uniformly random, and expansion derives one or more output keys using an explicit context parameter. It does not create entropy that wasn't in the input to begin with — it reshapes existing entropy into the right form. See RFC 5869.

Purpose separation is the key intuition to hold onto. A protocol can derive distinct client-to-server and server-to-client traffic keys from the same shared secret, and separately distinguish an "exporter" key (handed to an application) from the traffic-encryption key actually protecting the wire. The context string has to be unambiguous and precisely specified — two components casually reusing the same derived bytes for both encryption and authentication can introduce interactions the original security proof never covered, silently invalidating it.

Password processing is a genuinely different situation from key derivation in general. A human-chosen password may have very low guessing resistance, so a password-based KDF (like Argon2 or scrypt) deliberately imposes a large, tunable computational and memory cost on every guess. HKDF is not a substitute for that cost — a long, well-derived output key cannot conceal that an attacker only needs to search a modest password dictionary. The source of uncertainty and the cost of testing a single guess are two separate design levers, and both need to be addressed.

8. Public and private keys

Public-key cryptography lets a public value participate in an operation while a related private value stays secret. The word "public" means the scheme is designed to tolerate disclosure of that value — it does not mean every public key should automatically be trusted, and it does not mean a private key can safely be reused across unrelated operations just because the math "technically works."

RSA is historically important for both encryption/key transport and signatures, but secure RSA operations require specified encodings and padding schemes — textbook modular exponentiation alone is not a safe encryption API, full stop. RSA's factoring-based foundation is one of the core reasons for PQC migration in the first place (§4 of Part 1). Different RSA schemes also serve genuinely different purposes: RSA-OAEP (encryption) and RSA-PSS (signatures) are not interchangeable names for one operation, and mixing them up is a real, historically common vulnerability class. See RFC 8017.

Public-key mechanisms usually protect compact secret material or authenticate a digest/message structure, while symmetric cryptography handles bulk data efficiently underneath. This layered design is exactly why migrating public-key assumptions doesn't require replacing every byte of a record-encryption implementation — it does require carefully checking the specific boundaries where keys get delivered and authenticated for that implementation to use.

9. Diffie–Hellman through a tiny worked example

Finite-field Diffie–Hellman lets two parties compute a shared value from private exponents and public shares, without ever transmitting the shared value itself. In an intentionally insecure toy group modulo 23, take generator \(g = 5\). Alice chooses \(a = 6\) and publishes \(A = 5^6 \bmod 23 = 8\). Bob chooses \(b = 15\) and publishes \(B = 5^{15} \bmod 23 = 19\). Alice computes \(B^a \bmod 23 = 2\); Bob computes \(A^b \bmod 23 = 2\) — the same value, from different starting exponents.

The equality follows because both sides ultimately compute \(5^{ab} \bmod 23\), just reaching it from different directions. This toy example is for arithmetic intuition only — its tiny 23-element space is trivially brute-forceable in microseconds. Real protocols additionally validate inputs, choose cryptographically appropriate groups, derive keys from the shared value through a KDF (§7), and authenticate the exchange (§10–11). Raw, unauthenticated DH by itself is vulnerable to an active intermediary quietly establishing two separate secrets, one with each participant, and relaying between them — the classic man-in-the-middle.

Elliptic-curve Diffie–Hellman uses a different algebraic group for an analogous purpose. X25519 is a standardized function used specifically for key agreement — it is not a signature algorithm, despite superficially similar-looking curve arithmetic. Ed25519, despite the related naming and underlying arithmetic, is used for signatures instead. Reusing the same key material across the two roles requires real care and is not an introductory design shortcut worth taking. See RFC 7748 and RFC 8032.

10. Signatures: verification needs a separate trust decision

A signature scheme has key generation, signing, and verification operations. Its security goal normally considers an attacker who can obtain signatures on messages of their own choosing, and then tries to forge a valid signature on a new message they never got signed. ECDSA and EdDSA are classical examples; ML-DSA and SLH-DSA (Parts 8–9) supply entirely different mathematical assumptions for the same broad role.

The exact message definition is part of the protocol, not an afterthought. Does the signer authorize raw file bytes, a canonical manifest, or a structure that includes a version number and intended destination? If a signature covers a library's bytes but not its claimed package name, an attacker may be able to place those exact, validly-signed bytes into an unintended context — a classic signature-confusion vulnerability. Context separation, canonical encoding, and explicit domain separation are what make the authorization boundary actually precise instead of implicit.

Signature validity by itself does not settle replay, freshness, revocation, or entitlement — those are four more separate questions. An update client should reject an old, known-vulnerable release when policy forbids rollback, even though its historical signature still verifies perfectly correctly. Likewise, a signature made using a stolen key is mathematically indistinguishable from a legitimate one. Operational security must independently constrain who can request a signature in the first place, and provide a recovery mechanism for when a key's trust needs to be revoked.

11. PKI and X.509: how names meet keys

A public-key infrastructure (PKI) provides a structured way to distribute and validate trust in keys at scale. An X.509 certificate contains a public key plus a set of statements signed by an issuer. A typical chain runs from an end-entity certificate through one or more intermediates up to a trust anchor the relying party already accepts as a starting point — that final trust has to come from somewhere external (an OS trust store, a pinned config); the chain doesn't bootstrap its own trust from nothing. See RFC 5280.

Validation involves considerably more than just checking signatures cryptographically. Time validity windows, path constraints, permitted key usages, name-matching rules, and issuer policy all separately affect whether a chain should be accepted. For a TLS client specifically, service identity checking has to match the intended endpoint exactly — a perfectly valid certificate for the wrong name does not authenticate the service you actually meant to reach. See RFC 9525.

Trust chain: possession vs. proof of possession Configured trust anchor ↓ authorizes an issuer under constraints Intermediate CA ↓ signs a certificate under its permitted role Service certificate ↓ binds service identity to a public key Handshake proof of private-key use

Fig. 1 — A certificate is meant to be copied freely. A successful protocol must additionally prove the live peer can perform the matching private-key operation, and that the resulting identity is acceptable under policy — copying the chain proves nothing by itself.

This diagram separates possession of a certificate from proof of using its private key. A public certificate is meant to be copied — that's the point of it being public. A successful protocol must establish that the live peer can actually perform the required private-key operation, and that the resulting identity is acceptable under policy. Replacing a certificate's signature algorithm affects every verifier that ever encounters it, including devices with years-long update cycles that may never see a software update again — this is exactly why Part 12 treats PKI migration as its own multi-year project, not a config flag.

12. Where TLS 1.3 puts each piece

In a certificate-authenticated TLS 1.3 connection: the handshake negotiates parameters and establishes secret material; authentication binds the peer identity and the full transcript; a key schedule derives distinct traffic keys; and AEAD protects the actual records. The handshake's key-establishment group and its certificate's signature algorithm are two entirely separate choices — a cipher-suite name alone does not identify both of them, a common source of confusion when reading a handshake log. The current base specification is RFC 9846.

Ephemeral key agreement supports forward secrecy against later compromise of long-term authentication keys, under the protocol's stated assumptions. It does not make the public-key agreement itself mathematically immune to a future quantum attack against a recorded exchange — those are different threats with different time horizons. That distinction is exactly why an otherwise fully modern, correctly-configured classical TLS connection today can still be squarely relevant to harvest-now-decrypt-later analysis (Part 1, §5).

A KEM supplies another interface for establishing secret material, and it is worth restating precisely here: it is not simply "encrypt an arbitrary chosen message to the recipient." Encapsulation produces a ciphertext and a corresponding secret exactly as the specification defines, no more and no less. In hybrid TLS, the protocol combines the traditional and post-quantum components through one exact, specified construction — not an ad hoc concatenation. Parts 7 and 11 make those details fully concrete once the necessary mathematics (Part 4 onward) is in place.

13. Hands-on: observe three contracts directly

Use a POSIX shell and an isolated working directory with a maintained OpenSSL installation. Set OPENSSL to its full path if your default executable is older than 3.x. These commands generate only disposable demonstration keys — they never touch trust stores or system libraries.

OPENSSL=${OPENSSL:-openssl}
"$OPENSSL" version -a
umask 077
work=$(mktemp -d)
cd "$work"
printf 'release=1\n' > message.txt
"$OPENSSL" dgst -sha256 message.txt
"$OPENSSL" genpkey -algorithm ED25519 -out signing.pem
"$OPENSSL" pkey -in signing.pem -pubout -out verify.pem
"$OPENSSL" pkeyutl -sign -rawin -inkey signing.pem \
  -in message.txt -out signature.bin
"$OPENSSL" pkeyutl -verify -rawin -pubin -inkey verify.pem \
  -in message.txt -sigfile signature.bin
printf 'release=2\n' > changed.txt
if "$OPENSSL" pkeyutl -verify -rawin -pubin -inkey verify.pem \
  -in changed.txt -sigfile signature.bin; then
  echo 'ERROR: modified message accepted' >&2
  exit 1
fi
Validation: these exact commands were run against an isolated OpenSSL 3.5.8 build on macOS arm64. The original signature verified successfully, and the modified-message check failed as intended — the negative check is the important one here. A script that only prints a successful signature proves far less than a verifier that correctly rejects tampered content. The generated verification key is trusted in this lab only because we created it ourselves for the experiment; this is deliberately not a complete release-signing system. Command behavior is documented in OpenSSL pkeyutl.

14. What PQC replaces — and what stays exactly the same

ComponentPQC migration roleResponsibility that remains unchanged
RSA, finite-field DH, ECDHReplace the vulnerable public-key assumption in relevant protocolsAuthentication, input validation, key derivation
ECDSA, EdDSA, RSA signaturesIntroduce ML-DSA/SLH-DSA and appropriate certificate profilesKey trust, authorization, freshness, revocation
AEAD and symmetric encryptionRetain sound constructions; review parameters and usage limitsKey secrecy, nonce discipline, failure handling
Hashes, HMAC, KDFsContinue as components with suitable, unchanged security goalsDomain separation and correct composition
PKI and code signingMigrate algorithm support across trust relationshipsIssuer policy, rollback protection, update distribution
Random generatorsSupply the required uncertainty to new algorithmsEntropy quality, state protection, reseeding, failure behavior
Why is a public digest insufficient to authenticate a release?

Anyone who controls both the release file and the page publishing its digest can replace both together, consistently. The expected digest value has to be independently authenticated — for example, embedded in a manifest that's itself signed by a key the attacker doesn't hold (§4).

Does a successful signature check prove a file is the newest permitted version?

No. The signed structure and the surrounding update policy have to separately express and enforce freshness or anti-rollback requirements — signature validity alone says nothing about version recency (§10).

Why not just use raw Diffie–Hellman output directly everywhere?

Different operations need specified derivation and purpose separation (§7). Matching bytes at both ends of a DH exchange does not by itself establish a sound multi-purpose key schedule — reusing the raw shared secret for both encryption and authentication can introduce interactions the security proof never accounted for.

Takeaways

  • Confidentiality, integrity, and authenticity are three separate questions answered by three different mechanisms — encryption, MACs/AEAD, and signatures/PKI respectively. Conflating any two is where real designs fail.
  • A hash is not authentication. Anyone who controls both a file and its published digest can replace both consistently; the digest needs an independently-authenticated source of truth.
  • A MAC proves shared-secret knowledge, not sender identity — either party holding the key can produce a valid tag. Only public-key signatures give a third party non-repudiation.
  • AEAD nonce discipline is part of the security contract, not an implementation detail — nonce reuse under one key can catastrophically break both confidentiality and authenticity for AES-GCM-style constructions.
  • A KEM is not "encrypt to the recipient" and DH by itself is not authenticated — both need a full protocol wrapper (transcript binding, key derivation, identity checks) to be secure against an active attacker.
  • Migrating public-key assumptions doesn't touch AEAD, HMAC, or KDF correctness — those stay exactly as they are; PQC migration changes the key-establishment and signature layers specifically.

References & further reading

← Part 1 next: Part 3 →
© cvam — written in plaintext, served warm