We are given the following file:

The task description introduces the affine cipher that works by encrypting cleartext x to ciphertext y in the following way: y = (ax + b) mod m for some constants a, b and m.

We can see this in the gen.py script:

#!/usr/bin/env python
from math import gcd
import random
import binascii

# Encrypt the text using the affine cipher y = (ax + b) mod m
def affine_encrypt(text, a, b, m):
    result = 0
    for letter in text:
        c = (a * letter + b) % m
        result = (result << 8) + c
    return hex(result)

# Generate keys for the affine cipher and encrypt the flag
if __name__ == '__main__':
    with open('flag.txt', 'rb') as file:
        plaintext = file.read().strip(b'\n')

    m = 256
    a = random.randint(1, m)
    while gcd(a, m) != 1:
        a = random.randint(1, m)
    b = random.randint(0, m)

    print(f'Key = {(a, b)}')
    ciphertext = affine_encrypt(plaintext, a, b, m)

    with open('output.txt', 'w') as file:
        file.write(ciphertext)

We are also given the hex ciphertext in output.txt:

0xe9e962ea422bdc1d39965e2b341de5dc260f5050c9b2260f960f016c0f50342b6c39dcf8

We can notice that the ciphertext starts with e9e962 which would map the the flag prefix of DDC, so lets find constants a and b that satisfice this:

from math import gcd

m = 256
ciphertext = bytes.fromhex('e9e962')
crib = b'DDC'

for a in range(1, m+1):
  if gcd(a, m) != 1:
    continue
  for b in range(0, m+1):
    candidate = True

    for y, x in zip(ciphertext, crib):
      if (a * y + b) % m != x:
        candidate = False
        break

    if candidate: print(f"Pair found: ({a}, {b})")

When we run this we get Pair found: (55, 53)

We can then decrypt the cipher in the following way:

m = 256
a = 55
b = 53

cipher = bytes.fromhex('e9e962ea422bdc1d39965e2b341de5dc260f5050c9b2260f960f016c0f50342b6c39dcf8')

result = 0

for c in cipher:
  d = (a * c + b) % m
  result = (result << 8) + d

print(hex(result))

Which gives us: 0x4444437b63727970746f6772617068795f6e656564735f6e6f6e6c696e6561726974797d which from hex gives is DDC{cryptography_needs_nonlinearity}.