Tags: white-box-crypto cocotb verilog aes hardware reverse
Rating:
# Покой
**Категория:** Reverse / Hardware
**Сложность:** Hard
**Теги:** reverse, hardware, verilog, cocotb, aes, white-box-crypto
**Флаг:** `alfa{whitebox_means_open_floor_plan_3f16ce7b86f56a86f645c24e4b1}`
## Описание
Дан синтезированный Yosys нетлист на Verilog (`peace.v`, ~58k строк) и Python-скрипт cocotb (`peace.py`), симулирующий аппаратное устройство с клавиатурой 4×4 и дисплеем 128×64 пикселей. Устройство отображает 64 hex-байта на экране. Кто-то набрал флаг на клавиатуре, и экран показал конкретный 64-байтный вывод. Нужно восстановить набранный текст.
## Этап 1 — Изучение симуляции
Скрипт `peace.py` управляет cocotb-симуляцией Verilog-модуля. Дисплей 128×64 пикселей отображается символами Unicode. Клавиатура 4×4 (клавиши `1-9`, `0`, `*`, `#`, `A-D`) подаёт 4-битные коды на вход.
Ключевые наблюдения из `peace.py`:
- `COMMIT_CYCLES = HZ // 2 + 4 + 64 + 30` — после окончания ввода аппаратный конвейер ещё работает, прежде чем вывод стабилизируется.
- Дисплей сканируется построчно через `scan_pixels`, который читает 128-битные строки целиком.
## Этап 2 — Определение внутреннего состояния
Прогнав симуляцию и зачитав содержимое внутренних блоков памяти, нашли:
| Память | Размер | Назначение |
|--------|--------|------------|
| `_M_00000_`..`_M_00015_` | 16 × 256 × 8 бит | S-box'ы финального раунда |
| `_M_00016_`..`_M_00159_` | 144 × 256 × 32 бит | T-таблицы (9 раундов × 16) |
| `_M_00160_`, `_M_00161_` | 64 × 8 бит | Буфер дисплея (runtime) |
| `_M_00324_` | 4 × 128 бит | Промежуточное состояние шифра |
| `_M_00325_` | 4 × 128 бит | Выход шифра (4 блока) |
Дисплей читает `_M_00161_`, где хранится побайтово перевёрнутое содержимое `_M_00325_`. Каждый 128-битный слот = 16 байт = 32 hex-символа на экране. Четыре слота = 64 отображаемых байта.
## Этап 3 — Распознавание AES
Структура из 144 T-таблиц (9 раундов × 16 на раунд) + 16 байтовых S-box'ов (финальный раунд) однозначно указывает на **AES-128** с 10 раундами (9 T-табличных + 1 финальный SubBytes).
Проверили, что 16 S-box'ов финального раунда `M_00000..M_00015` имеют вид:
```
M_j[i] = AES_SBOX[i ⊕ a_j] ⊕ b_j
```
для некоторых констант `(a_j, b_j)`. Все 16 совпали со **стандартным S-box'ом AES**. Значения `a_j` — это байты ключа раунда 9, а `b_j` — байты ключа раунда 10.
Аналогично T-таблицы `M_00016..M_00159` совпали со стандартными AES T-таблицами `T0..T3` с побайтовым XOR ключа.
## Этап 4 — Извлечение ключа AES
Из T-таблиц первого раунда (`M_00016..M_00031`) значения `a` (pre-XOR) дают **мастер-ключ** (RK0) для каждой позиции входного байта. Маппинг ROM → входной байт определяется из Verilog `assign`:
```
M_00016 → байт 0 (a=0x3d) M_00024 → байт 2 (a=0x73)
M_00017 → байт 1 (a=0x2e) M_00025 → байт 3 (a=0x73)
M_00018 → байт 10 (a=0x0f) M_00026 → байт 4 (a=0x0d)
M_00019 → байт 11 (a=0xe3) M_00027 → байт 5 (a=0xed)
M_00020 → байт 12 (a=0xb8) M_00028 → байт 6 (a=0x60)
M_00021 → байт 13 (a=0x3b) M_00029 → байт 7 (a=0xec)
M_00022 → байт 14 (a=0x15) M_00030 → байт 8 (a=0x44)
M_00023 → байт 15 (a=0x72) M_00031 → байт 9 (a=0x75)
```
**Мастер-ключ:** `3d 2e 73 73 0d ed 60 ec 44 75 0f e3 b8 3b 15 72`
## Этап 5 — Расшифровка флага
64 отображённых hex-байта формируют 4 блока AES. Каждый блок — побайтово перевёрнутый шифротекст из `_M_00325_`. Открытый текст также хранится в обратном порядке байт.
Процедура расшифровки для каждого блока:
1. Взять 16 отображаемых байт.
2. Перевернуть порядок байт → шифротекст `_M_00325_`.
3. AES-128-ECB расшифровать с мастер-ключом.
4. Перевернуть порядок байт → исходные набранные символы.
```
Блок 0: "alfa{whitebox_me"
Блок 1: "ans_open_floor_p"
Блок 2: "lan_3f16ce7b86f5"
Блок 3: "6a86f645c24e4b1}"
```
## Флаг
`alfa{whitebox_means_open_floor_plan_3f16ce7b86f56a86f645c24e4b1}`
Флаг отсылает к **white-box криптографии** — реализации AES, где ключ встроен прямо в таблицы подстановок и виден в нетлисте.