Convergent Cipher
Author: 0xIDA
Platform: FlagYard · Category: crypto · Difficulty: Medium
Solvers
Summary
Custom 6-byte block cipher: each 3-byte half is XORed with a key half, inverted in GF(P) with P = 2^24+43, then XORed with SHA256(key)[:6]. Two chosen plaintexts cancel the final keystream so each 3-byte key half is recovered by a 2^24 search; pairs are filtered with the full encrypt oracle.
Challenge
Server (TCP): 2 plaintext→ciphertext queries under a random 6-byte key, then guess the key to get the flag.
P = 2**24 + 43
def sub(x): # 3 bytes
return (pow(int.from_bytes(x,'big'), -1, P) % 2**24).to_bytes(3,'big')
def encrypt(pt, key): # |pt|=|key|=6
k0, k1 = key[:3], key[3:]
k2 = hashlib.sha256(key).digest()[:6]
v = sub(xor(pt[:3], k0)) + sub(xor(pt[3:], k1))
return xor(v, k2)
Solution
Differential that kills k2
ct1 XOR ct2 = (sub(pt1L XOR k0) || sub(pt1R XOR k1))
XOR (sub(pt2L XOR k0) || sub(pt2R XOR k1))
So each half satisfies an independent relation:
sub(a XOR k) XOR sub(b XOR k) = d
with known a,b,d and k ∈ [0, 2^24).
Brute force + filter
- Precompute modular inverses for all nonzero 24-bit inputs (~20s, 64MB table).
- Enumerate all k0 matching the left differential (~2–6 collisions).
- Enumerate all k1 matching the right differential (~2–4 collisions).
- For each pair form
key = k0||k1and keep the unique key that re-encrypts both plaintexts (verifies k2 = SHA256(key)[:6]).
Chosen plaintexts used live: 00*6 and 01*6.
Live run
Plaintext: 000000000000 → Ciphertext: efd8f54db21c
Plaintext: 010101010101 → Ciphertext: 8516cc5d1b76
Recovered key: e533b40ed8f5
FlagY{m33t_1n_th3_m1ddl3_0r_d1ff3r3n714l?}
Flag
FlagY{m33t_1n_th3_m1ddl3_0r_d1ff3r3n714l?}
Tools
- Python 3 (socket client + inv table)
- Challenge source:
Convergent_Cipher_server.py
Key takeaways
- Final whitening with a key-derived mask cancels under ciphertext XOR → pure differential on the S-box layer.
- 24-bit halves are small enough for exhaustive search; multi-collisions on the differential need the full encrypt check (SHA256-derived k2).
- Name/flag hint “meet in the middle or differential” matches this structure.