Skip to main content

All weeks · Worksheet · Overview

Week 5 · Lecture slides

Week 5

Contents19 sections

Key Exchanges (Diffie-Hellman, MITM on unauthenticated DH)

Security & Cryptography · Nutthakorn Chalaemwongwan


Today

  • Why a key exchange, not just "send a key"
  • Diffie-Hellman: the math, and why it's hard to break passively
  • The active-attacker gap: MITM on unauthenticated DH
  • The fix: authenticate the DH public keys (HMAC), keep forward secrecy
  • 🕵️ Signature game: The Silent Third Wheel

Recap — Week 4

  • AES block-cipher modes: ECB leaks patterns, CBC needs a random IV, GCM gives you authentication too
  • Week 4 assumed Alice and Bob already share a key
  • Week 5's question: how do they get that shared key in the first place — over a network anyone can watch?

The problem: sharing a secret over a public channel

  • Alice and Bob want a shared symmetric key for AES
  • They've never met; the only channel is the open network
  • Naive idea: just send the key. What goes wrong?
  • Anyone watching the wire (an eavesdropper) now has it too

Diffie-Hellman — the idea

  • Public, shared: a large prime p and generator g
  • Alice picks secret a, sends g^a mod p
  • Bob picks secret b, sends g^b mod p
  • Both compute the same shared secret: g^(ab) mod p
  • An eavesdropper sees g^a, g^b, p, g — but not a, b, or g^(ab)

Why an eavesdropper can't recover it

  • Recovering a from g^a mod p = the discrete logarithm problem
  • No efficient algorithm known for a well-chosen, large prime p
  • This week's lab uses RFC 3526 Group 14: a standard 2048-bit MODP prime
  • Small or non-prime p, or a bad g, can make the DLP tractable — never invent your own parameters

But DH answers the wrong question

  • DH gives Alice and Bob a secret no eavesdropper can compute
  • It gives neither side a way to check who they just agreed it with
  • "Whoever answers when I dial Bob's address" ≠ "Bob"
  • That gap is everything an active attacker needs

Meet the lab: Alice, Bob, and Relay

ServiceRoleWhat it does
bob.pyServerListens on :5000, DH handshake, decrypts one AES-GCM message
alice.pyClientConnects to PEER_HOST:PEER_PORT — relay, never bob directly
relay.pyAttackerSits on the network path between them
  • The premise is the lesson: Alice's peer address is relay, not bob

The attack: two handshakes, one puppet-master

  1. Relay runs a full DH handshake with Alice — posing as Bob
  2. Relay runs a second, completely independent DH handshake with Bob — posing as Alice
  3. Relay now holds two different shared secrets: one per side
  4. It decrypts Alice's AES-GCM message with the Alice-side key, logs it, re-encrypts the same plaintext under the Bob-side key, forwards it

Why neither side notices

  • Alice's handshake completes successfully — she has a shared secret
  • Bob's handshake completes successfully — he has a shared secret
  • Neither is the same secret, and neither side ever checks that
  • No MAC, no signature, nothing binds the public key to an identity
  • CWE-322 — Key Exchange without Entity Authentication

Watch it happen (vulnerable mode)

week05-relay | RELAY: completed independent DH handshake with Alice (posing as Bob)
week05-alice | ALICE: sent encrypted message ('the launch code is 4471')
week05-relay | RELAY: completed independent DH handshake with Bob (posing as Alice)
week05-relay | RELAY INTERCEPTED: the launch code is 4471
week05-bob   | BOB RECEIVED: the launch code is 4471

The fix: authenticate the public key, not the channel

  • Each side computes HMAC-SHA256(AUTH_KEY, public_key_bytes) and sends the tag alongside its DH public value
  • The peer verifies the tag before deriving any session key
  • relay doesn't have AUTH_KEY — it can still try the identical substitution, but it can only send a junk tag
  • Verification fails → both sides print AUTH FAILED - ABORTING and exit

What the fix does not give up

  • DH still runs fresh, every session — the session key is still ephemeral
  • That means forward secrecy: if AUTH_KEY leaks next year, past captured traffic is still safe
  • The fix authenticates the exchange — it does not replace it
  • Real systems (TLS, SSH) authenticate DH with signatures/certificates, not a shared MAC — same principle: authenticate the exchange, don't just run it

Watch it fail (fixed mode)

week05-relay | RELAY: (fixed mode) attempted DH substitution with Alice (posing as Bob)
week05-alice | AUTH FAILED - ABORTING
week05-relay | RELAY: (fixed mode) attempted DH substitution with Bob (posing as Alice)
week05-bob   | AUTH FAILED - ABORTING
  • Zero occurrences of RELAY INTERCEPTED — that absence is the evidence

Not in today's demo — stays conceptual

  • Weak/non-standard groups (small or non-prime p) — Q7
  • Missing public-key validation — this lab's code does not validate peer_y against the group order — Q8
  • Small-subgroup confinement attack — a malicious public key can collapse the "shared secret" to one of only a handful of possible values, letting an attacker leak bits of a private key — Q9 / EiPE Part 2b

🕵️ Signature game — The Silent Third Wheel

  • Be the eavesdropper who becomes an active puppet-master
  • Sit silently between Alice and Bob, run your own DH handshake with each
  • Read their "secure" channel in the clear — they never notice
  • Then watch one HMAC tag over the public key shut you out completely, no other code change

Lab today

📋 Worksheet 5 — labs/week05-key-exchanges/worksheet.md · Part 1 (10 essay Q's) + Part 2 (AIR-Sec: lab evidence, EiPE, Prompt Problem, viva)

  • Run, don't exploit-and-fix code — this is a read/run/observe lab
  • Vulnerable: docker compose -f docker-compose.vulnerable.yml up --build → capture RELAY INTERCEPTED: the launch code is 4471
  • Fixed: docker compose -f docker-compose.fixed.yml up --build → capture both AUTH FAILED - ABORTING lines + confirm grep -c "RELAY INTERCEPTED" = 0
  • + EiPE (small-subgroup, plain English) + Prompt Problem (critique an AI's MITM explanation) — see worksheet

Key takeaways

  • Textbook-secure primitive, real-system failure: DH's math defeats a passive eavesdropper — it says nothing about who you just agreed a secret with
  • An active attacker who controls the network path exploits exactly that silence — two independent handshakes, invisible to both sides (CWE-322, CWE-300)
  • The fix authenticates the exchange without sacrificing what DH is for: forward secrecy

Questions?

Next week: Authenticated Encryption (AEAD)

All weeks in Security & Cryptography