Crypto categories in CTFs intimidate more newcomers than any other. The barrier isn’t math — it’s pattern recognition. Almost every CTF crypto challenge is a known weakness applied to slightly different parameters.

The First Pass — Identify the Family

When a challenge drops, classify it in under 30 seconds:

SignalLikely category
Output contains only A-Z and length divisible by 5Classical (Caesar, Vigenère, transposition)
Strings of = paddingBase64 / Base32 / encoding
c = pow(m, e, n) in sourceTextbook RSA
Hex strings of length 32 / 64 / 128MD5 / SHA-256 / SHA-512
AES.new(key, AES.MODE_ECB)AES ECB block patterns
xor(plaintext, repeated_key)XOR-based
Output looks like noise, source uses os.urandomStream cipher or PRNG analysis

90% of CTF crypto challenges fall into half a dozen categories. Familiarity with each saves hours.

Classical Ciphers

Use dCode or CyberChef automatic decoders first. Custom tooling only when nothing matches.

  • Caesar / ROT-N: brute force all 26 keys.
  • Vigenère: index of coincidence to find key length, then Kasiski/frequency analysis.
  • Transposition: pattern-spot column counts (text length factors).

Textbook RSA — The Pattern Bank

n = 2477...  # public modulus
e = 65537
c = 1827...  # ciphertext

Run through the checklist:

  1. Small n (<1024 bits) → factor with FactorDB, factor, or cado-nfs.
  2. Small e (e=3) and short message → cube root recovery: m = c ** (1/3).
  3. e = 1 → ciphertext is plaintext.
  4. p and q close together → Fermat’s factorization (isqrt(n)+k loop).
  5. Common modulus, two different e → use the extended Euclidean algorithm to combine ciphertexts.
  6. Same plaintext encrypted under multiple moduli with small e → Håstad’s broadcast attack via CRT.
  7. Partial private key leakage → Coppersmith’s method (SageMath has it built-in).
# Fermat — close p,q
from sympy import isqrt
a = isqrt(n) + 1
while True:
    b2 = a*a - n
    b = isqrt(b2)
    if b*b == b2: break
    a += 1
p, q = a-b, a+b

AES Mode Misuse

AES is unbreakable; AES mode usage rarely is.

  • ECB — the legendary penguin. Identical plaintext blocks → identical ciphertext blocks. Detect with len(set(blocks)) < len(blocks).
  • CBC bit-flipping — XOR the previous ciphertext block to flip bits in the next plaintext block (the canonical “change admin=0 to admin=1” trick).
  • CBC padding oracle — when the server tells you whether padding is valid, recover plaintext byte-by-byte. Tooling: padbuster.
  • CTR nonce reuse — XOR two ciphertexts under the same nonce → XOR of the plaintexts. Crib-drag to recover.
  • GCM nonce reuse — same as CTR, plus you can forge tags.

XOR

# Repeating-key XOR — single-character key
def score(b):
    return sum(c in b' etaoinshrdlu' for c in b)

ct = bytes.fromhex(hex_input)
for k in range(256):
    pt = bytes(c ^ k for c in ct)
    if score(pt) > 50:
        print(k, pt)

For longer keys: known-plaintext attacks if you know any portion of the original (e.g., a fixed file header).

Hash & Signature Schemes

  • Length-extension (MD5, SHA-1, SHA-256) — when H(secret || message) is used as a MAC and you know the message + hash, append to it. hashpump automates.
  • Hash collisions — MD5 colliders are commodity. Real challenges use chosen-prefix collisions (e.g., hashclash).
  • ECDSA nonce reuse — two signatures using the same k reveal the private key. The Sony PS3 break, in CTF form.

Random Number Predictability

  • Python’s random is a Mersenne Twister. Given 624 consecutive 32-bit outputs, you can reconstruct the entire state and predict all future outputs.
  • LCGs are trivial to recover from a few outputs.
# Recover Mersenne Twister state
from randcrack import RandCrack
rc = RandCrack()
for v in outputs[:624]:
    rc.submit(v)
predicted = rc.predict_getrandbits(32)

Lattice Problems

When the challenge involves “I added a small error to…” or modular constraints, lattice reduction is often the answer. LLL via SageMath solves a surprising fraction of crypto challenges in one line. Worth knowing exists even if you never write the matrix yourself.

A Solver’s Toolkit

  • SageMath — the swiss army knife. RSA, ECC, lattices, Galois fields.
  • CyberChef — for encoding/decoding chains.
  • OpenSSL CLIopenssl rsautl, openssl enc.
  • pwntools — networking + automation around oracle servers.
  • gmpy2 / sympy — Python big-integer math.

References