146 lines
10 KiB
Markdown
146 lines
10 KiB
Markdown
# Рукопожатие
|
||
|
||
На рукопожатие возложена задача выяснить способность _узлов_ устанавливать соединение по описываемому протоколу и согласовать подключение с избранными параметрами каждой стороны. На выбор существует два типа хэндшейка: открытый и зашифрованный. Второй дополнительно требует знать публичный ключ целевого _узла_.
|
||
|
||
|
||
|
||
## Запрос рукопожатия
|
||
|
||
После успешного подключения к целевому _узлу_ через избранный транспорт происходит обмен параметрами обоих сторон. Инициирующий соединение _узел_ отправляет пакет с магический числом, флагом шифрования и сериализованными данными в формат _LBM_. В случае с зашифрованным хэндшейком, сериализованные данные дополнительно зашифровываются с помощью публичного ключа целевого _узла_.
|
||
|
||
Структура пакета с запросом рукопожатия выглядит следующим образом:
|
||
|
||
`[magic number: 8B][encryption flag: 1B][LBM-formatted data: >0B]`
|
||
|
||
### Магическое число
|
||
|
||
Магическим числом является следующая последовательность байт:
|
||
|
||
```
|
||
HEX: 0x53 0x74 0x61 0x64 0x69 0x75 0x6d 0x50
|
||
DEC: 83 116 97 100 105 117 109 80
|
||
ASCII: S t a d i u m P
|
||
```
|
||
|
||
Если _узел_ получает пакет, который не содержит магического числа на указанной позиции, то он должен молча закрыть соединение.
|
||
|
||
### Флаг шифрования
|
||
|
||
Запрос шифрованного хэндшейка предполагает установку этого флага в значение `0x7a`. Все остальные значения должны интерпретироваться как запрос открытого хэндшейка.
|
||
|
||
### Данные
|
||
|
||
Данные в формате _LBM_ содержат следующие ячейки:
|
||
|
||
- Версия протокола
|
||
- _Ключ:_ `0x01`
|
||
- _Тип:_ `uint8_t`
|
||
- _Обязательна:_ да
|
||
- Поддерживаемая запрашивающим _узлом_ версия протокола.
|
||
- `0b10000000`: зарезервировано
|
||
- `0b01111111`: номер версии
|
||
|
||
- Алгоритмы хэширования полезной нагрузки
|
||
- _Ключ:_ `0x02`
|
||
- _Тип:_ `Crypto::Algorithm[]`
|
||
- _Обязательна:_ только для шифрованного ХШ
|
||
- Описывает запрашиваемые к использованию в этом соединении хэш-функции для формирования хэша полезной нагрузки. <!--TODO: упомянуть в структуре события использование нескольких алгоритмов совместно-->
|
||
|
||
- Алгоритм подписи
|
||
- _Ключ:_ `0x03`
|
||
- _Тип:_ `Crypto::Algorithm`
|
||
- _Обязательна:_ только для шифрованного ХШ
|
||
- Описывает используемый запрашивающим _узлом_ алгоритм подписи.
|
||
|
||
- Публичный ключ подписи
|
||
- _Ключ:_ `0x04`
|
||
- _Тип:_ `char[]`
|
||
- _Обязательна:_ только для шифрованного ХШ
|
||
- Публичный ключ подписи запрашивающего _узла_, который будет использован для проверки достоверности событий в соединении.
|
||
|
||
- Алгоритмы симметричного шифрования
|
||
- _Ключ:_ `0x05`
|
||
- _Тип:_ `Crypto::Algorithm[]`
|
||
- _Обязательна:_ только для шифрованного ХШ
|
||
- Описывает запрашиваемые к использованию в этом соединении симметричные алгоритмы шифрования.
|
||
|
||
- Приватный ключ
|
||
- _Ключ:_ `0x06`
|
||
- _Тип:_ `char[]`
|
||
- _Обязательна:_ только для шифрованного ХШ
|
||
- Используемый в этом соединении приватный ключ, размера соответствующего избранному алгоритму симметричного шифрования.
|
||
|
||
- Параметры шума
|
||
- _Ключ:_ `0x07`
|
||
- _Тип:_ `uint8_t`
|
||
- _Обязательна:_ нет
|
||
- Описывает параметры шума в соединении:
|
||
- `0b11100000`: выделено под настройку количества _шумовых пакетов_
|
||
- `0b000`: отсутствие _шумовых пакетов_
|
||
- `0b001`: соотношение _шумовых пакетов_ к реальным - 1:8
|
||
- `0b010`: соотношение - 1:4
|
||
- `0b011`: 1:2
|
||
- `0b100`: 1:1
|
||
- `0b101`: 2:1
|
||
- `0b110`: 4:1
|
||
- `0b111`: зарезервировано
|
||
- `0b00011000`: выделено под настройку размера _шумовых пакетов_
|
||
- `0b00`: случайный размер, в пределах от минимального _пакета_ с нулевой полезной нагрузкой, до размера _пакета_ с полезной нагрузкой размерности, которую должен передать целевой _узел_ при одобрении рукопожатия
|
||
- `0b01`: случайный размер, на основе среднего размера передаваемого пакета +- 25% (но всегда меньше максимального)
|
||
- `0b10`: случайный размер, в пределах от минимального, до максимального / 2
|
||
- `0b11`: зарезервировано
|
||
- `0b00000110`: выделено под настройку размера _шумовых данных_ в обычных _пакетах_
|
||
- `0b00`: без шумовых данных
|
||
- `0b01`: заполнение шумовыми данными до лимита полезной нагрузки
|
||
- `0b10`: заполнение шумовыми данными в случайном количестве, от нуля, до лимита полезной нагрузки
|
||
- `0b11`: зарезервировано
|
||
- `0b00000001`: зарезервировано
|
||
|
||
<!--
|
||
- Запрос транспорта (опционально)
|
||
- _Ключ:_ `0x05`
|
||
- _Тип:_ `uint8_t`
|
||
- Если существует, то интерпретируется как запрос переподключения к другому виду транспорта. TODO: Надо сделать енум.
|
||
-->
|
||
|
||
|
||
|
||
## Ответ на рукопожатие
|
||
|
||
На запрос рукопожатия с корректным магическим числом целевой _узел_ должен ответить пакетом либо с согласием, либо с ошибкой. Если это ответ с согласием, то данные в пакете должны быть зашифрованы с помощью переданного в запросе хэндшейка симметричного шифра и переданного приватного ключа. Если это ответ с ошибкой, то он может быть незашифрован, в случае, если ошибка связанна с инициализацией шифрования или версией протокола. Таким образом, запрашивающий _узел_ должен быть готов обработать оба варианта развития событий, исходя из значения флага шифрования. Если цель не поддерживает указанные при рукопожатии параметры, запрашивающий может попробовать установить соединение снова, с иными параметрами.
|
||
|
||
Пакет ответа имеет следующую структуру:
|
||
|
||
`[magic number: 8B][encryption flag: 1B][LBM-formatted data: >0B]`
|
||
|
||
### Данные
|
||
|
||
Данные в формате _LBM_ содержат следующие ячейки:
|
||
|
||
- Максимальный размер полезной нагрузки
|
||
- _Ключ:_ `0x71`
|
||
- _Тип:_ `uint16_t`
|
||
- _Обязательна:_ только для соглашения
|
||
- Всегда больше нуля. Оба _узла_ должны соблюдать размерность полезной нагрузки в событии, она всегда должна быть равна или меньше этого значения.
|
||
|
||
- Код ошибки
|
||
- _Ключ:_ `0x72`
|
||
- _Тип:_ `uint8_t`
|
||
- _Обязательна:_ только для ошибки
|
||
- Код, описывающий тип ошибки:
|
||
- `0x01`: магическое число ложно
|
||
- `0x02`: неподдерживаемая версия протокола
|
||
- `0x03`: недопустимый алгоритм хэширования
|
||
- `0x04`: недопустимый алгоритм подписи
|
||
- `0x05`: недопустимый алгоритм симметричного шифрования
|
||
- `0x06`: некорректный приватный ключ
|
||
- `0x07`: некорректный публичный ключ подписи
|
||
- `0x08`: недопустимые параметры шума
|
||
- `0x09`: невозможно корректно расшифровать данные (ложный публичный ключ целевого _узла_)
|
||
|
||
- Описание ошибки
|
||
- _Ключ:_ `0x73`
|
||
- _Тип:_ `char[]`
|
||
- _Обязательна:_ нет
|
||
- Строка в кодировке ASCII, описывающая ошибку в человекочитаемом виде.
|