CS409 · Cryptography

Applied Cryptography & Exploits

A CTF-style lab series — each challenge is a live remote service implementing a cryptographic primitive with a subtle flaw, and the assignment is to recover a flag. Theme: cryptography in textbooks is a list of primitives; cryptography in practice is a list of ways the primitives were used wrong.

Timeline
Aug – Sept 2025 · CS409 Introduction to Cryptography, IIT Bombay
Instructor
Prof. Shruthi Shekar
Language
Python 3 · ~3,775 LOC across the four labs
Stack
PyCryptodome · pwntools · hashlib · ecdsa · OpenSSL CLI
Scope
Labs 1–4 · OTP attacks · block-cipher modes · MACs & hash collisions · public-key & signatures
Repo
github.com/.../CS409-Cryptography/Labs

Lab 1 — One-time pad variants

Four challenges on weakened OTPs: two-time pad (XOR keystream reuse, recoverable via crib-dragging), modular OTP with a deterministic key expansion, a distinguishing attack on a faulty OTP with a reduced keyspace, and ciphertext recovery from a base-255 radix-encryption scheme.

Lab 2 — Block-cipher modes

Attacks across AES modes:

Lab 3 — MACs & hash collisions

HMAC timing side-channel

The target verified MAC tags with a byte-by-byte loop that short-circuited on the first mismatch — and each matching byte introduced a 1-second artificial delay, simulating timing variance. The attack measures latency with time.perf_counter(), averages over TRIALS=3 samples per candidate byte, and walks the tag forward one byte at a time. The first 10 hex characters of the tag fall to this in seconds.

Merkle–Damgård collisions (Nostradamus / diamond structure)

Bonus challenge — "Nostradamus' Resurrection": a chosen-target-forced-prefix attack against an MD-style hash with no length finalisation and length-independent padding. The server hands over a 2–32 byte prefix; the attacker has to produce a message that hashes to a pre-committed target. The solution is a diamond structure — precompute a converging tree of collisions at 2n/2 cost, then for any forced prefix find a suffix that lands on the precomputed target. Cleared 100 / 100 trials. This is exactly why modern designs (SHA-3, sponge construction) abandon the Merkle–Damgård paradigm.

A second challenge in the same lab recovers the full flag from only n/4 Merkle proof queries — the structure of the tree itself leaks more than the proofs were meant to.

Lab 4 — Public-key & signatures

ECDSA nonce reuse → private key recovery

A textbook failure mode on SECP256k1: signing two different messages with the same nonce k leaks the private key in a few lines of modular arithmetic — the same mistake Sony made on the PS3.

EdDSA-style forgery (weakened nonce)

On NIST P-256 with a weakened deterministic-nonce rule — r = SHA256(msg[:len/2] ∥ privkey) — the attacker requests signatures on five chosen messages, recovers enough structure to predict r, then forges a valid signature on a sixth, unseen message.

Other Lab 4 challenges

RSA-OAEP decryption against a malformed oracle, X.509 certificate analysis on https://www.cse.iitb.ac.in to extract the flag from the issuer field, and a bonus Grover-style classical search-space reduction.

Tooling

Solutions are written in Python against PyCryptodome for the primitives (Crypto.Cipher.AES, Crypto.Util.strxor, Crypto.Util.Padding) and pwntools for remote-server interaction. The standard hashlib and time modules cover the MAC and side-channel work.

What stuck

These weren't toy exercises — each one was a live network service, and most labs took longer to set up the attack harness than to execute the actual exploit. That ratio is the lesson: most cryptographic break-ins are engineering work, not cryptographic genius.

Source & exploit scripts Per-lab solutions, attack harnesses, and notes
View on GitHub