← Back to Writeups
CUSTOMMediumCrypto

Not easy — Affine Cipher

XESXOR9/10/20261 min read
#crypto#custom#medium#affine_cipher_cryptanalysis#modular_inverse

Not easy — Affine Cipher

Platform: cryptokids20 | Category: Crypto | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-03-08 | Status: Solved Techniques: affine_cipher_cryptanalysis, modular_inverse

Summary

It's affine cipher: ahfupn{ryzzs_g_qo_aeur_qnngdy_ughryl}. Flag format: spbctf{...}

Not easy — Crypto Kids 2.0

Description

It's affine cipher: ahfupn{ryzzs_g_qo_aeur_qnngdy_ughryl}. Flag format: spbctf{...}

Analysis

Affine cipher: E(x) = (ax + b) mod 26

Known:

  • "spbctf" → "ahfupn"
  • s(18) → a(0): 18a + b ≡ 0 (mod 26)
  • p(15) → h(7): 15a + b ≡ 7 (mod 26)

Subtracting: 3a ≡ -7 ≡ 19 (mod 26) a = 19 * 3^(-1) mod 26 = 19 * 9 = 171 ≡ 15 (mod 26) b = -18*15 mod 26 = -270 mod 26 = 16

For decryption: D(y) = a^(-1) * (y - b) mod 26 a^(-1) = 15^(-1) mod 26 = 7 (since 15*7 = 105 ≡ 1 mod 26) ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

python
#!/usr/bin/env python3
def mod_inverse(a, m):
    for x in range(1, m):
        if (a * x) % m == 1:
            return x
    return None

def affine_decrypt(ciphertext, a, b):
    a_inv = mod_inverse(a, 26)
    result = []
    for c in ciphertext:
        if c.isalpha():
            base = ord('a') if c.islower() else ord('A')
            y = ord(c.lower()) - ord('a')
            x = (a_inv * (y - b)) % 26
            result.append(chr(base + x))
        else:
            result.append(c)
    return ''.join(result)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

ciphertext = "ahfupn{ryzzs_g_qo_aeur_qnngdy_ughryl}"
# a = 15, b = 16
plaintext = affine_decrypt(ciphertext, 15, 16)
print(plaintext)
# Output: spbctf{REDACTED}

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍