Init. commit
This commit is contained in:
51
crypto-elliptic-enigma/WRITEUP.md
Normal file
51
crypto-elliptic-enigma/WRITEUP.md
Normal file
@@ -0,0 +1,51 @@
|
||||
<h1 align="center">Elliptic Enigma</h1>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/category-Crypto-blueviolet" alt="Crypto"/>
|
||||
<img src="https://img.shields.io/badge/points-852-orange" alt="852 pts"/>
|
||||
</p>
|
||||
|
||||
В руках два файла:
|
||||
|
||||
| Файл | Что внутри |
|
||||
|---|---|
|
||||
| `public/server.py` | Код сервера подписи |
|
||||
| `public/signatures.json` | Параметры кривой, публичный ключ, 30 подписей, шифротекст флага |
|
||||
|
||||
ECDSA на кастомной эллиптической кривой — смотрим генерацию nonce `k`, обычно вся соль в нём.
|
||||
|
||||
## Решение
|
||||
|
||||
В коде сервера:
|
||||
|
||||
```python
|
||||
k = random.getrandbits(120)
|
||||
```
|
||||
|
||||
Порядок группы `n` — 128 бит. У каждого `k` старшие 8 бит тупо равны нулю. Даже небольшая утечка нескольких бит nonce, размазанная по десяткам подписей, приводит прямиком к [Hidden Number Problem](https://link.springer.com/chapter/10.1007/3-540-68697-5_11), а HNP классически решается решёточной редукцией ([LLL](https://en.wikipedia.org/wiki/Lenstra%E2%80%93Lenstra%E2%80%93Lov%C3%A1sz_lattice_basis_reduction_algorithm)).
|
||||
|
||||
Стандартная ECDSA-подпись: для сообщения с хешем $z$ считается
|
||||
|
||||
$$s = k^{-1}(z + r \cdot d) \pmod{n}$$
|
||||
|
||||
Откуда чистой алгеброй:
|
||||
|
||||
$$k = s^{-1} z + s^{-1} r d \pmod{n}$$
|
||||
|
||||
Обозначим $t_i = s_i^{-1} r_i \pmod{n}$ и $u_i = s_i^{-1} z_i \pmod{n}$, и для каждой подписи получаем уравнение вида
|
||||
|
||||
$$k_i = u_i + t_i \cdot d \pmod{n}, \qquad k_i < 2^{120}$$
|
||||
|
||||
Получили классическую постановку HNP: много сравнений по модулю $n$, а сами скрытые числа маленькие.
|
||||
|
||||
Дальше — стандартный пайплайн:
|
||||
|
||||
1. Загружаем подписи из `signatures.json`.
|
||||
2. Для каждого сообщения считаем `z_i` так же, как сервер: `SHA-256`, первые 16 байт.
|
||||
3. Вычисляем `t_i` и `u_i`.
|
||||
4. Собираем из них решётку для LLL и запускаем редукцию.
|
||||
5. Из редуцированного базиса вытаскиваем кандидатов на приватный ключ `d`.
|
||||
6. С `d` на руках расшифровываем флаг: `AES-256-CBC(SHA256(d), iv=0, ciphertext)`.
|
||||
|
||||
## Флаг
|
||||
`caplag{b14s3d_n0nc3_l4tt1c3_r3duc710n}`
|
||||
Reference in New Issue
Block a user