# Crypto 10 класс

## Решение

Сервер шифрует 64-битные блоки по формуле:

$$
C = (A \cdot P + B) \bmod 2^{64}
$$

Это аффинное преобразование, и его параметры восстанавливаются двумя запросами.

Отправим два блока:

- $P_1 = 0 \Rightarrow C_1 = (A \cdot 0 + B) = B \bmod 2^{64}$
- $P_2 = 1 \Rightarrow C_2 = (A \cdot 1 + B) = (A + B) \bmod 2^{64}$

Восстановим A и B:

$$B = C_1$$

$$C_2 = (A + B) = (A + C_1) \bmod 2^{64}$$
$$A = (C_2 - C_1) \bmod 2^{64}$$

Далее расшифровываем блок с помощью обратного элемента $A^{-1}$ по модулю $2^{64}$:

$$C = (A \cdot P + B) \bmod 2^{64}$$
$$(C - B) = (A \cdot P) \bmod 2^{64}$$

$$P = (C - B) \cdot A^{-1} \bmod 2^{64}$$

Применяем это к каждому 8-байтному блоку зашифрованного флага.

## Код

```python
from pwn import *

context.log_level = "info"


def decrypt_flag(enc_flag: bytes, a: int, b: int) -> bytes:
    a_inv = pow(a, -1, 2**64)
    out = bytearray()
    for i in range(0, len(enc_flag), 8):
        block = enc_flag[i : i + 8]
        if len(block) < 8:
            block = block.ljust(8, b"\x00")
        c = int.from_bytes(block, "little")
        p = ((c - b) * a_inv) % 2**64
        out += p.to_bytes(8, "little")
    return bytes(out)


with remote("localhost", 20054, timeout=5) as p:
    p.recvuntil(b"Encrypted flag (hex): ")
    enc_flag = bytes.fromhex(p.recvline().strip().decode())

    p.sendline(b"00")
    p.recvuntil(b"Ciphertext (hex): ")
    c1 = int.from_bytes(bytes.fromhex(p.recvline().strip().decode()), "little")
    b_val = c1

    p.sendline(b"01")
    p.recvuntil(b"Ciphertext (hex): ")
    c2 = int.from_bytes(bytes.fromhex(p.recvline().strip().decode()), "little")
    a_val = (c2 - b_val)

    flag = decrypt_flag(enc_flag, a_val, b_val)
    print(flag.decode(errors="ignore"))

```

## Флаг

vsosh{alg3bra_1s_y0ur_fr13nd}
