# Рукопожатие На рукопожатие возложена задача выяснить способность _узлов_ устанавливать соединение по описываемому протоколу и согласовать подключение с избранными параметрами каждой стороны. На выбор существует два типа хэндшейка: открытый и зашифрованный. Второй дополнительно требует знать публичный ключ целевого _узла_. ## Запрос рукопожатия После успешного подключения к целевому _узлу_ через избранный транспорт происходит обмен параметрами обоих сторон. Инициирующий соединение _узел_ отправляет пакет с магический числом, флагом шифрования и сериализованными данными в формат _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[]` - _Обязательна:_ только для шифрованного ХШ - Описывает запрашиваемые к использованию в этом соединении хэш-функции для формирования хэша полезной нагрузки. - Алгоритм подписи - _Ключ:_ `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`: зарезервировано ## Ответ на рукопожатие На запрос рукопожатия с корректным магическим числом целевой _узел_ должен ответить пакетом либо с согласием, либо с ошибкой. Если это ответ с согласием, то данные в пакете должны быть зашифрованы с помощью переданного в запросе хэндшейка симметричного шифра и переданного приватного ключа. Если это ответ с ошибкой, то он может быть незашифрован, в случае, если ошибка связанна с инициализацией шифрования или версией протокола. Таким образом, запрашивающий _узел_ должен быть готов обработать оба варианта развития событий, исходя из значения флага шифрования. Если цель не поддерживает указанные при рукопожатии параметры, запрашивающий может попробовать установить соединение снова, с иными параметрами. Пакет ответа имеет следующую структуру: `[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, описывающая ошибку в человекочитаемом виде.