92 lines
9.4 KiB
Markdown
92 lines
9.4 KiB
Markdown
# Анализ и реализация клиента для Project Colette V53
|
||
|
||
Этот документ представляет подробный технический разбор процесса подключения к серверу Project Colette V53. Он анализирует криптографическое рукопожатие, структуру пакетов и логику обмена сообщениями, реализованную в Python-клиенте `main.py`.
|
||
|
||
## [*] Основные концепции
|
||
|
||
Протокол обмена данными — это пользовательский протокол, работающий поверх стандартного TCP. Шифрование построено с использованием криптографической библиотеки **NaCl** (в коде C# упоминается как `TweetNaCl`), которая предоставляет:
|
||
- **Асимметричное шифрование**: `Curve25519` для обмена ключами через эллиптическую кривую Диффи-Хеллмана (ECDH).
|
||
- **Симметричное шифрование**: `XSalsa20-Poly1305` для потокового шифрования после установления сессии.
|
||
- **Хеширование**: `Blake2b` для генерации одноразовых номеров (nonce).
|
||
|
||
Каждое сообщение (пакет) в протоколе предваряется 7-байтным заголовком:
|
||
- **ID сообщения** (2 байта): Идентификатор типа сообщения.
|
||
- **Длина полезной нагрузки** (3 байта): Длина предстоящих данных.
|
||
- **Версия** (2 байта): Версия сообщения.
|
||
|
||
## [!] Пошаговый разбор процесса подключения
|
||
|
||
Процесс от первоначального подключения до полностью установленной зашифрованной сессии включает обмен четырьмя ключевыми пакетами.
|
||
|
||
---
|
||
|
||
### **Шаг 1: `ClientHello` (ID: 10100)**
|
||
|
||
- **Направление**: Клиент -> Сервер
|
||
- **Шифрование**: Нет
|
||
|
||
Это самый первый пакет, который клиент отправляет после установления TCP-соединения. Его единственная цель — инициировать сессию на сервере и сообщить о готовности начать рукопожатие. Полезная нагрузка этого пакета не имеет значения для криптографии и может быть заполнена нулями.
|
||
|
||
---
|
||
|
||
### **Шаг 2: `LoginMessage` (ID: 10101)**
|
||
|
||
- **Направление**: Клиент -> Сервер
|
||
- **Шифрование**: Асимметричное (`Box`)
|
||
|
||
Это ключевой пакет от клиента, где происходит основная магия обмена ключами.
|
||
|
||
#### **Подготовка на стороне клиента (перед отправкой):**
|
||
1. **Ключ сервера**: Клиент использует статический `server_public_key` сервера, который известен заранее (извлечен из исходного кода сервера).
|
||
2. **Ключи клиента**: Клиент генерирует новую, **эфемерную (временную)** пару ключей `Curve25519` — `client_public_key` и `client_private_key`. Эта пара будет использоваться только для текущей сессии.
|
||
3. **Общий секрет (`s`)**: Клиент немедленно вычисляет предварительный общий секрет (`shared_secret` или `s`), используя свой новый приватный ключ и публичный ключ сервера. Это стандартная операция ECDH. В `PyNaCl` это делается с помощью `Box.beforenm(server_public_key, client_private_key)`. Этот секрет `s` понадобится для расшифровки ответа сервера.
|
||
4. **Nonce клиента (`RNonce`)**: Клиент генерирует 24 случайных байта, `client_nonce`. Сервер называет это `RNonce` (Nonce получателя). Это критически важная часть рукопожатия.
|
||
|
||
#### **Структура и передача пакета:**
|
||
Пакет `10101` состоит из двух частей:
|
||
1. **Публичный ключ клиента** (32 байта): Отправляется в открытом виде.
|
||
2. **Зашифрованная полезная нагрузка**:
|
||
- **Данные для шифрования**: Открытый текст для шифрования содержит:
|
||
1. Временный сеансовый ключ (24 байта, генерируется клиентом, но игнорируется сервером).
|
||
2. `client_nonce` (`RNonce`) (24 байта).
|
||
3. Фактические данные для входа (ID аккаунта, версия клиента и т.д.), сериализованные в байтовый поток.
|
||
- **Nonce для шифрования**: Nonce для этой операции вычисляется как хеш публичных ключей: `blake2b(client_public_key + server_public_key)`.
|
||
- **Процесс шифрования**: Вышеуказанные данные шифруются с помощью `Box(client_private_key, server_public_key).encrypt(...)`.
|
||
|
||
---
|
||
|
||
### **Шаг 3: `ServerHello` (ID: 20100)**
|
||
|
||
- **Направление**: Сервер -> Клиент
|
||
- **Шифрование**: Асимметричное (`Box`)
|
||
|
||
Это ответ сервера, который завершает асимметричную фазу рукопожатия.
|
||
|
||
#### **Процесс расшифровки на стороне клиента:**
|
||
1. **Вычисление Nonce**: Чтобы расшифровать этот пакет, клиент должен использовать тот же `nonce`, который использовал сервер. Сервер вычисляет его по формуле: `blake2b(RNonce + client_public_key + server_public_key)`. У клиента уже есть все три компонента: он сам сгенерировал `RNonce` и знает оба публичных ключа.
|
||
2. **Процесс расшифровки**: Расшифровка выполняется с использованием ранее вычисленного общего секрета `s`. Формула: `Box.open_afternm(payload, nonce, shared_secret)`.
|
||
|
||
#### **Содержимое расшифрованного пакета:**
|
||
Внутри находятся два ключевых элемента для всей будущей коммуникации:
|
||
1. **Финальный сеансовый ключ (`session_key`)** (32 байта): Это симметричный ключ, который будет использоваться для шифрования всех последующих сообщений.
|
||
2. **Nonce сервера (`SNonce`)** (24 байта): Этот nonce будет основой для шифрования сообщений, идущих **от сервера к клиенту**.
|
||
|
||
---
|
||
|
||
### **Шаг 4: Переход к симметричному шифрованию и `LoginOk` (ID: 20104)**
|
||
|
||
- **Направление**: Сервер -> Клиент
|
||
- **Шифрование**: Симметричное (`SecretBox`)
|
||
|
||
После получения `ServerHello` криптографическая сессия считается полностью установленной. Все последующие пакеты шифруются симметрично с использованием `SecretBox` и `session_key`.
|
||
|
||
#### **Логика Nonce (`NextNonce`)**
|
||
Ключевой особенностью протокола является то, что nonce увеличивается **на 2** перед каждой операцией шифрования или дешифрования. Функция `next_nonce` в коде точно воспроизводит эту логику на стороне сервера.
|
||
|
||
#### **`LoginOk`**
|
||
Это первый пакет, который клиент получает в зашифрованном виде.
|
||
1. **Получить Nonce**: Клиент берет `SNonce`, полученный на предыдущем шаге.
|
||
2. **Увеличить Nonce**: Он применяет к нему логику `next_nonce` (увеличивая его на 2).
|
||
3. **Расшифровать**: Он расшифровывает пакет с помощью `SecretBox(session_key).decrypt(payload, nonce)`.
|
||
|
||
Успешная расшифровка `LoginOk` подтверждает, что весь процесс прошел корректно, и клиент теперь находится в полностью зашифрованной сессии с сервером. Этот пакет содержит данные о созданном аккаунте (ID, токен и т.д.). |