Тотальный передел, глава вторая
This commit is contained in:
parent
07a2413612
commit
ed54ecb7f9
12
.gitignore
vendored
12
.gitignore
vendored
@ -1,10 +1,2 @@
|
|||||||
Data types/DATA TYPES.md
|
_old/*
|
||||||
SPX/
|
1.2. Терминология.md
|
||||||
_something.md
|
|
||||||
LBM.md
|
|
||||||
Reserved LBM keys.md
|
|
||||||
Reserved events/idk/
|
|
||||||
Reserved events/BaseResponse/
|
|
||||||
Reserved events/BaseSession/
|
|
||||||
Reserved events/BaseUnsigned/
|
|
||||||
Sessions.md
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
# Общие принципы поведения узлов
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Обязанности узла
|
|
||||||
|
|
||||||
1. Оповещать об ошибке, возникшей во время обработки _события_ другого _узла_, но только если ошибка связана с его некорректной формой.
|
|
||||||
2. По умолчанию отклонять все _события_ с ложной подписью в _подписанном соединении_.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Обязанности сервера
|
|
||||||
|
|
||||||
1. Оповещать _узел_ (будь то _клиент_ или _сервер_ в федерации) о всех ошибках, возникших во время обработки его _события_, кроме связанных с безопасностью. <!--TODO: сформулировать точнее-->
|
|
||||||
2. Отдавать предпочтение данным других _серверов_ в федерации, нежели _клиентов_.
|
|
||||||
3. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Обязанности клиента
|
|
||||||
|
|
||||||
1. Не сообщать _серверу_ ни о каких ошибках на своей стороне.
|
|
||||||
2. По умолчанию блокировать до решения юзера обработку любых _событий_, содержащих ложную подпись. <!--TODO: это скорее про фронтенд-->
|
|
||||||
3. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию.
|
|
@ -1,3 +0,0 @@
|
|||||||
# Структуры данных
|
|
||||||
|
|
||||||
Сия спецификация, помимо всего прочего, также упоминает и определяет некоторые необходимые типы и структуры данных. В директории `Data types/` вы найдёте их описания и примеры декларации на языке C++.
|
|
@ -1,20 +0,0 @@
|
|||||||
# Crypto::Algorithm
|
|
||||||
|
|
||||||
Описывает криптографический алгоритм вместе с его базовой конфигурацией.
|
|
||||||
|
|
||||||
## Структура
|
|
||||||
|
|
||||||
`[AlgorithmID: 1B][AlgorithmParams: 1B]`
|
|
||||||
|
|
||||||
## C++
|
|
||||||
|
|
||||||
```C++
|
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
struct Algorithm {
|
|
||||||
AlgorithmID ID;
|
|
||||||
AlgorithmParams Params;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,71 +0,0 @@
|
|||||||
# Crypto::AlgorithmID
|
|
||||||
|
|
||||||
Является перечислением однобайтных целых чисел без знака, соответствующих идентификаторам допустимых к использованию в базовом протоколе криптографических (и не только) алгоритмов: хэшей, контрольных сумм, симметричного и ассиметричного шифрования.
|
|
||||||
|
|
||||||
<!--TODO: мб всё-таки не-криптуху стоит вынести?-->
|
|
||||||
|
|
||||||
## C++
|
|
||||||
|
|
||||||
```C++
|
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
enum struct AlgorithmID : uint8_t {
|
|
||||||
None = 0,
|
|
||||||
// Checksums
|
|
||||||
CRC = 11, // 8/16/32/64/etc.
|
|
||||||
fletcher, // 8/16/32/etc.
|
|
||||||
Adler, // 32/etc.
|
|
||||||
// Non-crypto hashes
|
|
||||||
Murmur64A = 31,
|
|
||||||
Murmur3, // 32/128
|
|
||||||
Spooky, // 128/etc.
|
|
||||||
// Cryptographic hashes
|
|
||||||
BLAKE2b = 51,
|
|
||||||
BLAKE3,
|
|
||||||
GOST,
|
|
||||||
HAS160,
|
|
||||||
HAVAL,
|
|
||||||
MD2,
|
|
||||||
MD5,
|
|
||||||
RIPEMD,
|
|
||||||
SHA1,
|
|
||||||
SHA2,
|
|
||||||
SHA3,
|
|
||||||
SHAKE, // 128/256
|
|
||||||
Skein,
|
|
||||||
Snefru,
|
|
||||||
Streebog,
|
|
||||||
Tiger,
|
|
||||||
Whirlpool,
|
|
||||||
// Symmetric key block ciphers
|
|
||||||
Blowfish = 81,
|
|
||||||
Twofish,
|
|
||||||
Threefish,
|
|
||||||
TripleDES,
|
|
||||||
HPC,
|
|
||||||
MARS,
|
|
||||||
SAFER2PLUS,
|
|
||||||
SQUARE,
|
|
||||||
CRYPTON,
|
|
||||||
AES, // AKA Rijndael, GCM/CBC/CTR/etc.
|
|
||||||
MAGENTA,
|
|
||||||
XTEA1,
|
|
||||||
XTEA3,
|
|
||||||
KHAZAD,
|
|
||||||
Camellia,
|
|
||||||
Salsa20,
|
|
||||||
CAST5,
|
|
||||||
CAST6,
|
|
||||||
Kuznyechik,
|
|
||||||
MESH,
|
|
||||||
Akelarre,
|
|
||||||
RC6
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<!--
|
|
||||||
TODO: симметрики распилить по категориям на блоковые и поточные
|
|
||||||
TODO: ассиметрики и подписи (RSA, YAK, Cramer–Shoup system, Paillier cryptosystem, curves (25519 & 448), ElGamal, etc.)
|
|
||||||
-->
|
|
@ -1,13 +0,0 @@
|
|||||||
# Crypto::AlgorithmParams
|
|
||||||
|
|
||||||
Описывает параметры алгоритма, например размер ключа. Является двухбайтным целым без знака.
|
|
||||||
|
|
||||||
## C++
|
|
||||||
|
|
||||||
```C++
|
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
typedef uint16_t AlgorithmParams;
|
|
||||||
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,9 +0,0 @@
|
|||||||
# EventAsyncID
|
|
||||||
|
|
||||||
Является уникальным двухбайтным целым числом без знака и предназначен для определения отношения запросов к ответам при асинхронном обмене _событиями_.
|
|
||||||
|
|
||||||
## C++
|
|
||||||
|
|
||||||
```C++
|
|
||||||
typedef uint16_t EventAsyncID;
|
|
||||||
```
|
|
@ -1,9 +0,0 @@
|
|||||||
# LocalObjectID
|
|
||||||
|
|
||||||
Уникальный идентификатор объекта на сервере, является восьмибайтным числом без знака.
|
|
||||||
|
|
||||||
## C++
|
|
||||||
|
|
||||||
```C++
|
|
||||||
typedef uint64_t LocalObjectID;
|
|
||||||
```
|
|
45
Events.md
45
Events.md
@ -1,45 +0,0 @@
|
|||||||
# События
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Категории и типы
|
|
||||||
|
|
||||||
Существует три уровня категорий _событий_:
|
|
||||||
|
|
||||||
**Надкатегория** описывает виды взаимодействующих _узлов_. Не указывается и зависит от контекста. Варианты: _Client2Server_ (_событие_ сгенерированное _клиентом_ для _сервера_), _Server2Client_ (_событие_ сгенерированное _сервером_ для _клиента_), _Peer2Peer_ (_событие_ сгенерированное _узлом_ для другого _узла_ того-же ранга, в том числе это касается _серверов_ в федерации).
|
|
||||||
|
|
||||||
**Категория** описывает _события_ одного класса. Является однобайтным числом без знака. Всегда больше нуля. Например: _Authentication_, _Object_, т.п.
|
|
||||||
|
|
||||||
**Подкатегория** описывает конкретное _событие_ из класса, соответствующего категории. Является однобайтным числом без знака. Всегда больше нуля. Например: _Login_, _GetContents_, т.п.
|
|
||||||
|
|
||||||
Все категории вместе - являются типом _события_. Информацию про зарезервированные типы вы можете найти в [Reserved events.md](Reserved%20events.md).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Содержание и структура
|
|
||||||
|
|
||||||
Все _события_ содержат идентификатор _потока_ размером 4 байта. Подробнее - в [Streams.md](Streams.md).
|
|
||||||
|
|
||||||
_События_ в _шифрованном соединении_ содержат хэш, применённый к зашифрованному блобу (см. ниже). Этот хэш имеет размер равно или более 16 байт и подписан с помощью закрытого ключа подписи отправляющего. Он гарантирует достоверность содержания _события_ на уровне прямого подключения между двумя _узлами_. Используемые алгоритмы подписи и хэширования определяются на этапе рукопожатия.
|
|
||||||
|
|
||||||
Все _события_ содержат асинхронный идентификатор _события_, который является двухбайтным целым числом без знака и предназначен для определения отношения запросов к ответам при асинхронном обмене _событиями_ в конкретном _потоке_.
|
|
||||||
|
|
||||||
Все _события_ содержат тип (см. выше раздел "Категории и типы").
|
|
||||||
|
|
||||||
_События_ могут содержать полезную нагрузку, либо один нулевой байт, свидетельствующий о её отсутствии. Данная версия протокола не накладывает ограничений на формат полезной нагрузки, за исключением базовых событий, которые представлены данными в формате _LBM_. Описание всех предопределённых в базовом протоколе ключей ячеек _LBM_ доступно в [Reserved LBM keys.md](Reserved%20LBM%20keys.md). При использовании формата _LBM_, в полезную нагрузку могут добавляться шумовые данные. Неизвестные ключи при обработке полезной нагрузки игнорируются.
|
|
||||||
|
|
||||||
_События_ в _шифрованном соединении_ содержат блоб, зашифрованный с помощью актуального ключа _потока_ и утверждённого алгоритма симметричного шифрования. Этот блоб содержит асинхронный идентификатор, тип события и полезную нагрузку. В нешифрованном _соединении_, указанные поля находятся в "сыром" виде.
|
|
||||||
|
|
||||||
Исходя из всего вышеописанного, минимальный размер сериализованного в бинарный вид _события_ в нешифрованном _соединении_ составляет 9 байт, а его итоговая структура выглядит следующим образом:
|
|
||||||
|
|
||||||
`[Stream ID: 4B][Async ID: 2B][Event Type: 2B][Payload: >0B]`
|
|
||||||
|
|
||||||
В свою очередь, _события_ в _шифрованном соединении_ имеют размер не менее 25-и байт и следующую структуру:
|
|
||||||
|
|
||||||
```text
|
|
||||||
[Stream ID: 4B][Signed Hash: >=16B][Encrypted Blob: >=5B]
|
|
||||||
/ | \
|
|
||||||
[Async ID: 2B][Event Type: 2B][Payload: >0B]
|
|
||||||
```
|
|
||||||
|
|
||||||
Максимальный размер _события_ не нормирован. Ответственность за менеджмент разделения _события_, в случае, если оно не помещается в один пакет, остаётся на транспортном уровне. Максимальный размер полезной нагрузки _события_ определяется на этапе рукопожатия.
|
|
147
Handshake.md
147
Handshake.md
@ -1,147 +0,0 @@
|
|||||||
# Рукопожатие
|
|
||||||
|
|
||||||
На рукопожатие возложена задача выяснить способность _узлов_ устанавливать соединение по описываемому протоколу и согласовать подключение с избранными параметрами каждой стороны. На выбор существует два типа хэндшейка: открытый и зашифрованный. Второй дополнительно требует знать публичный ключ целевого _узла_.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Запрос рукопожатия
|
|
||||||
|
|
||||||
После успешного подключения к целевому _узлу_ через избранный транспорт происходит обмен параметрами обоих сторон. Инициирующий соединение _узел_ отправляет пакет с магический числом, флагом шифрования и сериализованными данными в формат _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, описывающая ошибку в человекочитаемом виде.
|
|
||||||
|
|
||||||
<!--TODO: стартовый SID-->
|
|
92
Overview.md
92
Overview.md
@ -1,92 +0,0 @@
|
|||||||
# Обзор
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Терминология
|
|
||||||
|
|
||||||
Здесь перечислены используемые в данной спецификации термины, значение которых может быть не очевидно и/или не соответствует тому, которое подразумевается обычно.
|
|
||||||
|
|
||||||
### Узел
|
|
||||||
|
|
||||||
Любая машина, способная выполнять коммуникацию по протоколу Stadium. Обычно используется в контексте коммуникации двух машин одного ранга или когда ранг не имеет значения.
|
|
||||||
|
|
||||||
### Сервер
|
|
||||||
|
|
||||||
Выполняющий роль сервера _узел_ в многоранговой сети.
|
|
||||||
|
|
||||||
### Клиент
|
|
||||||
|
|
||||||
Выполняющий роль клиента _узел_ в многоранговой сети.
|
|
||||||
|
|
||||||
### Соединение/поток
|
|
||||||
|
|
||||||
Канал обмена _событиями_ между двумя _узлами_, имеющий свой идентификатор (Stream ID/SID, см. [Streams.md](Streams.md)) и набор настроек.
|
|
||||||
|
|
||||||
### Шифрованное соединение/поток
|
|
||||||
|
|
||||||
_Соединение_ между двумя _узлами_, все _события_ в котором шифруются с помощью оговорённого симметричного алгоритма и ключа, а также подписываются с помощью приватного ключа отправителя.
|
|
||||||
|
|
||||||
### Сессия
|
|
||||||
|
|
||||||
То, что устанавливается при создании первого _соединения_ между двумя _узлами_, с чем ассоциированы конкретные _потоки_ и прочие параметры.
|
|
||||||
|
|
||||||
### Событие
|
|
||||||
|
|
||||||
Структура данных, обладающая конкретными семантическими свойствами в зависимости от типа и содержащая дополнительные поля, требуемые для верного отображения и интерпретации самой структуры. Проще говоря - то, чем обмениваются и что обрабатывают _узлы_ во время коммуникации между собой.
|
|
||||||
|
|
||||||
### Шумовое событие
|
|
||||||
|
|
||||||
_Событие_ предопределённой категории, имеющее случайно-сгенерированные поля.
|
|
||||||
|
|
||||||
### LBM
|
|
||||||
|
|
||||||
Аббревиатура наименования способа форматирования (сериализации) данных, используемого для полезной нагрузки _события_, которая расшифровывается как "Linear Binary Map". Подробнее - в [LBM.md](LBM.md).
|
|
||||||
|
|
||||||
### Шумовые данные
|
|
||||||
|
|
||||||
Случайно-сгенерированные данные, помещённые в специализированную ячейку полезной нагрузки _события_.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Пример коммуникации двух узлов
|
|
||||||
|
|
||||||
Допустим, что у нас есть два неизвестных\* друг-другу _узла_ - `p1` и `p2`. Тогда полная коммуникация по шагам (от подключения неизвестного для `p2` _узла_ - до "правильного" уничтожения сессии и закрытия соединения) будет выглядеть так:
|
|
||||||
|
|
||||||
1. `p1` запрашивает открытое (нешифрованное) рукопожатие с избранными параметрами соединения у `p2`
|
|
||||||
2. `p2` отвечает `p1` согласием со своей частью параметров
|
|
||||||
3. `p1` запрашивает публичный ключ подписи у `p2`
|
|
||||||
4. `p2` передаёт свой публичный ключ, вместе с используемым алгоритмом
|
|
||||||
5. `p1` сохраняет полученный публичный ключ и разрывает\*\* соединение и заново устанавливает его, путём отправки `p2` запроса шифрованного хэндшейка
|
|
||||||
6. `p2` отвечает согласием со своей частью параметров подключения
|
|
||||||
7. `p1` отправляет зашифрованное _событие_ с запросом какого-то объекта
|
|
||||||
8. `p2` отвечает зашифрованным _событием_, содержащее статус-код или этот объект
|
|
||||||
9. `p1` отправляет _событие_ с сообщением о намерении уничтожить сессию и ждёт в течении n времени, по истечению которого может разорвать соединение "насильно"
|
|
||||||
10. `p2` принимает запрос и прекращает любой параллельный обмен данными
|
|
||||||
11. `p2` отвечает _событием_ с кодом успешности операции
|
|
||||||
12. `p2` закрывает соединение
|
|
||||||
|
|
||||||
И в виде схемы:
|
|
||||||
|
|
||||||
```
|
|
||||||
Requesting p2's public key:
|
|
||||||
[p1] ------[raw handshake request]----> [p2]
|
|
||||||
[p1] <-----[raw handshake accept]------ [p2]
|
|
||||||
[p1] ----[request public sign key]----> [p2]
|
|
||||||
[p1] <-[public key and crypto params]-- [p2]
|
|
||||||
[p1] ---------[close session]---------> [p2]
|
|
||||||
[p1] <--------[status code OK]--------- [p2]
|
|
||||||
|
|
||||||
Reconnecting in encrypted way and requesting object:
|
|
||||||
[p1] ---[encrypted handshake request]-> [p2]
|
|
||||||
[p1] <--[encrypted handshake accept]--- [p2]
|
|
||||||
[p1] ------[request some object]------> [p2]
|
|
||||||
[p1] <-[some object data/status code]-- [p2]
|
|
||||||
[p1] ---------[close session]---------> [p2]
|
|
||||||
[p1] <--------[status code OK]--------- [p2]
|
|
||||||
```
|
|
||||||
|
|
||||||
\* - _стоит уточнить, что в реальных сценариях использования публичный ключ целевого узла скорее всего уже известен, либо коммуникация должна производиться через транспорт, гарантирующий достоверность передаваемых данных. `p1` может узнать о существовании таковых, путём отправки события специального типа. В данном примере сей шаг опущен._
|
|
||||||
|
|
||||||
<!--TODO: таки описать этот шаг ^^^-->
|
|
||||||
|
|
||||||
\*\* - _"разрыв" соединения предполагает обмен между узлами событиями с информацией о завершении сессии; в данном пункте эти шаги опущены, но упомянуты ниже._
|
|
22
README.md
22
README.md
@ -1,18 +1,12 @@
|
|||||||
# Спецификация протокола Stadium версии 1.0
|
# Неформальная спецификация протокола Stadium версии 0.5
|
||||||
|
|
||||||
Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта и архитектурно не зависящий от оного. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения (_SPX - Stadium Protocol eXtension_) для более конкретных нужд. Помимо прочего, данный протокол служит основой для полнофункционального мессенджера Marafon<!--, спецификация расширения которого находится в папке `SPX/Marafon/`-->.
|
Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта и архитектурно не зависящий от оного. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения (_SPX - Stadium Protocol eXtension_) для более конкретных нужд. <!--Помимо прочего, данный протокол служит основой для полнофункционального мессенджера Marafon, спецификация расширения которого находится в папке `SPX/Marafon/`.-->
|
||||||
|
|
||||||
Основной фокус при работе над сим проектом идёт на:
|
Основной фокус при работе над этим проектом идёт на:
|
||||||
|
|
||||||
- Возможность функционирования в условиях низкой пропускной способности канала;
|
- Низкий оверхэд и возможность функционирования в условиях низкой пропускной способности канала;
|
||||||
- Устойчивость к цензуре;
|
- Поддержка широкого спектра транспортных протоколов из коробки;
|
||||||
- Поддержка широкого спектра транспортных протоколов;
|
- Гибкое и кастомизируемое сквозное шифрование;
|
||||||
- Построение децентрализованных меш-сетей (как одноуровневых, так и двухуровневых);
|
- Расширяемость и возможность подгонки под конкретные задачи.
|
||||||
- Гибкое сквозное шифрование;
|
|
||||||
- Расширяемость и возможность подстраивания под конкретные задачи.
|
|
||||||
|
|
||||||
|
**Внимание!** В данный момент проект переживает глобальные архитектурные изменения. Данная версия спецификации акцентирует внимание на закреплении общих, преимущественно фундаментальных идей и концепций, потому и является *неформальной*.
|
||||||
|
|
||||||
**ПРОЕКТ В АКТИВНОЙ РАЗРАБОТКЕ/PROJECT UNDER ACTIVE DEVELOPMENT**
|
|
||||||
|
|
||||||
All text will be translated to english later.
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
# Зарезервированные типы событий
|
|
||||||
|
|
||||||
Некоторые категории _событий_ зарезервированы под нужды базового протокола или просто для _событий_ определённого класса. Второе носит рекомендательный характер; вы также можете использовать иные диапазоны для тех-же целей. Ниже приведены диапазоны зарезервированных значений в виде шестнадцатеричных чисел. Конкретный перечень всех зарезервированных событий и описание их структуры - есть в папке `Reserved events/`.
|
|
||||||
|
|
||||||
|
|
||||||
Зарезервировано для нужд протокола и запрещено к использованию в сторонних расширениях:
|
|
||||||
|
|
||||||
1. Категория и субкатегория `0x00`
|
|
||||||
- Запрещены к использованию.
|
|
||||||
|
|
||||||
2. Категория `0x01`
|
|
||||||
- Все субкатегории: выделены для базовых _событий_, связанных с менджментом сессии.
|
|
||||||
|
|
||||||
3. Категория `0x11`
|
|
||||||
- Все субкатегории: выделены для базовых кодов ответа, ошибок и предупреждений.
|
|
||||||
|
|
||||||
|
|
||||||
Рекомендуется к использованию расширениями в конкретных ситуациях:
|
|
||||||
|
|
||||||
1. Категории `0x12`-`0x1F` (включительно)
|
|
||||||
- Все субкатегории: для кодов ответа, ошибок и предупреждений сторонних реализаций.
|
|
@ -1,43 +0,0 @@
|
|||||||
# Категория.Субкатегория
|
|
||||||
|
|
||||||
**HEX:** `BA98`
|
|
||||||
|
|
||||||
**Возможные ответы:** [ДругаяКатегория.ДругаяСубкатегория](Example.md), [ЕщёКатегория.ЕщёСубкатегория](Example.md)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Client2Server
|
|
||||||
|
|
||||||
Какое-то описание типа _события_. Разделы (Client2Server, Server2Client, т.д.) могут находится в произвольном порядке относительно друг-друга. Если ячеек нет, то это указывается явно.
|
|
||||||
|
|
||||||
### Ячейки
|
|
||||||
|
|
||||||
#### ObjectID
|
|
||||||
|
|
||||||
Какое-то описание, к чему применимо значение в этой ячейке, что оно из себя представляет и тому подобное.
|
|
||||||
|
|
||||||
#### PrevEventID
|
|
||||||
|
|
||||||
Тоже какое-то описание.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Server2Client
|
|
||||||
|
|
||||||
Какие-то пояснении об отличии этого _события_ от иных версий. Если отличий нет, то раздел опускается. Если надкатегория _события_ в этом контексте не допустима, то об этом явно указывается. (см. раздел Peer2Peer для примера)
|
|
||||||
|
|
||||||
### Дополнительные ячейки
|
|
||||||
|
|
||||||
#### CryptoAsymCipher
|
|
||||||
|
|
||||||
Ещё какое-то описание.
|
|
||||||
|
|
||||||
### Отсутствующие ячейки
|
|
||||||
|
|
||||||
- **ObjectID**: описание причины, почему не требуется
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Peer2Peer
|
|
||||||
|
|
||||||
_Не применимо._
|
|
@ -1,3 +0,0 @@
|
|||||||
# Marafon SPX
|
|
||||||
|
|
||||||
_Расширение протокола Stadium для мессенджера Marafon._
|
|
26
Streams.md
26
Streams.md
@ -1,26 +0,0 @@
|
|||||||
# Потоки
|
|
||||||
|
|
||||||
**Поток** представляет из себя канал обмена _событиями_ в определённой конфигурации. _Узлы_ должны обрабатывать _события_ единообразно, вне зависимости от того, через какой _поток_ они передаются.
|
|
||||||
|
|
||||||
## Stream ID
|
|
||||||
|
|
||||||
Каждый _поток_ имеет пару собственных уникальных идентификаторов: "Stream ID", "SID". Они используются для определения принадлежности _события_ к существующим _потокам_. Для увеличения энтропии, с целью исключения анализа траффика, SID представляет из себя нефиксированное значение, уникальное для каждого _события_. Каждый из двух _узлов_ в _соединении_ имеет собственный SID.
|
|
||||||
|
|
||||||
Допустим, что есть два _узла_: `pc`, который подключается, и `ps`, к которому подключается `pc`. Тогда пусть SID, используемый _узлом_ `pc` будет называться `sidc`, а `ps` - `sids`. Для того, чтобы установить новое _соединение_, _узлы_ должны проделать следующее:
|
|
||||||
|
|
||||||
1. `pc` генерирует стартовое значение `sidc` и отправляет его _узлу_ `ps` вместе с алгоритмами симметричного шифрования и хэширования для обработки `sids`, а также симметричный ключ соответствующего алгоритму размера.
|
|
||||||
2. `ps` принимает данные и отвечает _узлу_ `pc` стартовым значением `sids`, алгоритмами шифрования и хэширования `sidc`, а также симметричный ключ соответствующего алгоритму размера.
|
|
||||||
|
|
||||||
При этом, `ps` должен иметь единую конфигурацию алгоритмов симметричного шифрования, хэш-функции и используемый ключ для обработки SID всех _потоков_. Перед использованием в отправляемом _событии_, _узел_ должен обработать прежнее значение SID, а именно: зашифровать его с использованием избранного при установке _соединения_ алгоритма симметричного шифрования и ключа, а затем вычислить хэш. Если размер выходных данных хэш-функции больше размера SID, то эти данные поблочно XOR'ятся сами с собой. В реализации это может выглядеть вот так: <!--NOTICE: получше формализовать надо, скорее всего-->
|
|
||||||
|
|
||||||
```C
|
|
||||||
// size_t arr_sz: размер вывода хэш-функции
|
|
||||||
// char *arr: вывод хэш-функции
|
|
||||||
// uint32_t sid: прежний SID
|
|
||||||
sid = *(uint32_t*)arr;
|
|
||||||
for (size_t i = 1; i < arr_sz / 4; ++i)
|
|
||||||
sid = sid ^ ((uint32_t*)arr)[i];
|
|
||||||
```
|
|
||||||
|
|
||||||
Если любой из _узлов_ обнаруживает ложное значение SID в полученном _событии_, то он обязан разорвать _соединение_. <!--и сохранять статус _потока_ в течении времени, определяемого имплементацией и конфигурацией. _Узел_, инициировавший создание _потока_, может попробовать пересоздать его в течении этого времени, -->
|
|
||||||
<!--TODO: StreamRessurectionKey, восстановление потока в случае обрыва связи-->
|
|
51
Оглавление.txt
Normal file
51
Оглавление.txt
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
ВНИМАНИЕ! В этой версии оглавления обнаружены существенные недостатки, потому оно точно изменится в дальнейшем.
|
||||||
|
|
||||||
|
1. Введение
|
||||||
|
1.1. Цели и мотивация
|
||||||
|
1.2. Терминология
|
||||||
|
1.3. Пример работы в виде схемы
|
||||||
|
2. Параметры
|
||||||
|
2.1. Магическое число протокола
|
||||||
|
2.2. Версия протокола
|
||||||
|
2.3. CryptoDesc [дескриптор криптоалгоритма]
|
||||||
|
2.3.1. HashCryptoDesc
|
||||||
|
2.3.2. SymCiphCryptoDesc
|
||||||
|
2.3.3. AsymCiphCryptoDesc
|
||||||
|
2.4. CryptoPack [набор криптоалгоритмов]
|
||||||
|
2.4.1. HashCryptoPack
|
||||||
|
2.4.2. SymCiphCryptoPack
|
||||||
|
2.4.3. SignCryptoPack [набор для подписи, AsymCiphCryptoDesc + HashCryptoDesc]
|
||||||
|
2.4.4. KDCryptoPack [набор для Key Derivation, либо существующая KDF, либо SymCiphCryptoDesc + HashCryptoDesc]
|
||||||
|
2.4.4.1. KDInitValue [значение, которым впервые инициализируется KDF]
|
||||||
|
2.4.4.2. KDPrivConst [приватное значение, используемое в качестве второго аргумента KDF]
|
||||||
|
2.6. Linear Binary Map
|
||||||
|
3. Рукопожатие
|
||||||
|
3.1. Базовые параметры
|
||||||
|
3.2. Параметры криптографии
|
||||||
|
3.3. Запрос
|
||||||
|
3.4. Ответ
|
||||||
|
4. Сессия
|
||||||
|
5. Поток
|
||||||
|
5.1. Состояние
|
||||||
|
5.2. SID, SSID, CSID
|
||||||
|
5.3. Шифрование
|
||||||
|
5.4. Контроль последовательности событий
|
||||||
|
5.5. Шум
|
||||||
|
6. Событие
|
||||||
|
6.1. Заголовок
|
||||||
|
6.1.1. MAC, CMAC, SMAC [проверка целостности + проверка достоверности]
|
||||||
|
6.1.2. Асинхронный идентификатор [AID]
|
||||||
|
6.1.3. Тип события
|
||||||
|
6.2. Полезная нагрузка
|
||||||
|
6.3. Структура
|
||||||
|
6.3.1. Открытого события
|
||||||
|
6.3.2. Шифрованного события
|
||||||
|
6.4. Запрос и ответ
|
||||||
|
7. Безопасность и модель угроз
|
||||||
|
8. Распределение типов событий
|
||||||
|
- ... конкретные типы ...
|
||||||
|
9. Зарезервированные ячейки LBM
|
||||||
|
- ... конкретные ячейки ...
|
||||||
|
10. Расширения протокола
|
||||||
|
10.1. Идентификатор расширения [SPXI]
|
||||||
|
10.2. Дескриптор расширения [SPXD]
|
236
Рукопожатие.md
Normal file
236
Рукопожатие.md
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
# Рукопожатие
|
||||||
|
|
||||||
|
На *рукопожатие* возложена задача создать между *клиентом* и *сервером* новый *поток* на взаимно согласованных условиях. Это включает в себя определение готовности коммуникации по *протоколу*, согласование версии *протокола* в пределах *сессии* (если создаётся новая), а также согласование различных параметров *потока*. *Рукопожатие* может быть "открытое", то есть в котором тело пакета представлено в нешифрованном виде и которое ведёт к созданию нешифрованного *потока*, и "шифрованное", в котором тело пакета зашифровано, подписано, и которое ведёт к созданию шифрованного *потока*. При выполнении этой процедуры используются уникальные форматы пакетов, несоответствующие формальному определению *события*. Формат пакетов использующийся в *рукопожатии* представлен ниже.
|
||||||
|
|
||||||
|
Существуют следующие типы *рукопожатия*:
|
||||||
|
|
||||||
|
- Первый тип: то, что создаёт новый *поток* и одновременно новую *сессию*
|
||||||
|
- Второй тип: то, что создаёт новый *поток* в рамках существующей *сессии*
|
||||||
|
- Третий тип: то, что восстанавливает существующий *поток* из десинхронизированного состояния в рабочее
|
||||||
|
|
||||||
|
*Рукопожатие* любого типа выполняется ровно в два действия:
|
||||||
|
|
||||||
|
1. *Клиент* запрашивает *рукопожатие* с избранными параметрами
|
||||||
|
2. *Сервер* отвечает *клиенту* либо своей частью параметров, либо ошибкой
|
||||||
|
|
||||||
|
Пакет *рукопожатия* состоит из заголовка и тела. В заголовок входят магическое число протокола и флаг шифрования. Тело представляет из себя данные сериализованные в формат LBM. Соответствие ключей ячеек LBM и их содержимого приведено ниже.
|
||||||
|
|
||||||
|
Флаг шифрования является восьмибитным целым числом и может принимать одно из двух значений:
|
||||||
|
|
||||||
|
1. `0x00` - шифрования нет.
|
||||||
|
2. `0x80` - шифрование включено.
|
||||||
|
|
||||||
|
Формат пакета *рукопожатия* следующий:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[Magic number: 8 bytes][Encryption flag: 1 byte][Handshake body: non-fixed bytes]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Базовые параметры
|
||||||
|
|
||||||
|
Базовые параметры, использующиеся в *рукопожатии* и их соответствие ключам ячеек LBM. Обратите внимание, что представленные здесь ключи ячеек не имеют отношения к зарезервированным, которые указаны в разделе 9.
|
||||||
|
|
||||||
|
```text
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
| Name | Key | Description |
|
||||||
|
|------------------|------|------------------------------------------------------------|
|
||||||
|
| NoiseParameters | 0x01 | Параметры шума в потоке |
|
||||||
|
| ProtocolVersion | 0x02 | Версия протокола, использующаяся в сессии |
|
||||||
|
| StreamSecret | 0x03 | Секрет потока |
|
||||||
|
| SessionSecret | 0x04 | Секрет сессии |
|
||||||
|
| MaxPayloadSize | 0x05 | Максимальный размер полезной нагрузки |
|
||||||
|
| ExtensionsEnum | 0x06 | Перечисление расширений |
|
||||||
|
| ErrorCode | 0x20 | Код ошибки сервера |
|
||||||
|
| ErrorDescription | 0x21 | Детальное описание ошибки |
|
||||||
|
----------------------------------------------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
### NoiseParameters
|
||||||
|
|
||||||
|
Является однобайтовым битовым полем, описывает параметры шума в *потоке*. Структура поля выглядит примерно так:
|
||||||
|
|
||||||
|
`[3 bits][2 bits][2 bits][1 bit (reserved)]`
|
||||||
|
|
||||||
|
Первые три бита выделены под настройку количества шумовых *событий*, допустимые значения:
|
||||||
|
|
||||||
|
- `0b000`: отсутствие шумовых *событий*
|
||||||
|
- `0b001`: соотношение шумовых *событий* к реальным 1:8
|
||||||
|
- `0b010`: соотношение 1:4
|
||||||
|
- `0b011`: 1:2
|
||||||
|
- `0b100`: 1:1
|
||||||
|
- `0b101`: 2:1
|
||||||
|
- `0b110`: 4:1
|
||||||
|
- `0b111`: зарезервировано
|
||||||
|
|
||||||
|
Следующие два бита выделены под настройку размера шумовых *событий*:
|
||||||
|
|
||||||
|
- `0b00`: случайный размер, в пределах от размера минимального *события* с нулевой *полезной нагрузкой*, до MaxPayloadSize
|
||||||
|
- `0b01`: случайный размер, на основе среднего размера передаваемого *события* +- 25% (но всегда меньше максимального)
|
||||||
|
- `0b10`: случайный размер, в пределах от минимального, до MaxPayloadSize / 2
|
||||||
|
- `0b11`: зарезервировано
|
||||||
|
|
||||||
|
Ещё два бита выделены под настройку размера шумовых данных в обычных *событиях*:
|
||||||
|
|
||||||
|
- `0b00`: без шумовых данных
|
||||||
|
- `0b01`: заполнение шумовыми данными до лимита *полезной нагрузки*
|
||||||
|
- `0b10`: заполнение шумовыми данными в случайном количестве, от нуля, до лимита *полезной нагрузки*
|
||||||
|
- `0b11`: зарезервировано
|
||||||
|
|
||||||
|
Последний бит зарезервирован.
|
||||||
|
|
||||||
|
### StreamSecret
|
||||||
|
|
||||||
|
Секрет *потока* представляет из себя 16 случайных байт, полученные *сервером* с помощью криптостойкого генератора случайных чисел. <!--TODO: вероятно, что стоит перенести это и пункт ниже в соответствующие разделы про поток и сессию-->
|
||||||
|
|
||||||
|
### SessionSecret
|
||||||
|
|
||||||
|
Секрет *сессии* представляет из себя 32 случайных байта, полученные *сервером* с помощью криптостойкого генератора случайных чисел.
|
||||||
|
|
||||||
|
### MaxPayloadSize
|
||||||
|
|
||||||
|
Целое число без знака размером 1, 2, 4 или 8 байт, означающее максимальный размер *полезной нагрузки*.
|
||||||
|
|
||||||
|
### ExtensionsEnum
|
||||||
|
|
||||||
|
Перечисление расширений *протокола* является массивом нефиксированного общего размера и переменным размером отдельной ячейки. В каждой ячейке содержится корректный дескриптор расширения *протокола* (SPXD).
|
||||||
|
|
||||||
|
### ErrorCode
|
||||||
|
|
||||||
|
Код ошибки *сервера* представляет из себя восьмибитное число без знака. Не может являться нулём. Перечень допустимых значений и ассоциированных с ними названий:
|
||||||
|
|
||||||
|
- `0x01`, FailedToParseBody: не удалось корректно разобрать тело пакета
|
||||||
|
- `0x02`, InsufficientParams: недостаточно параметров для выполнения *рукопожатия* избранного типа
|
||||||
|
- `0x11`, WrongCryptoAlgo: криптографический алгоритм не указан или не существует
|
||||||
|
- `0x12`, UnsupportedCryptoAlgo: указанный криптоалгоритм известен *серверу*, но отключен или не имплементирован
|
||||||
|
- `0x13`, WrongCryptoValue: ключ или иные криптографические данные не указаны, имеют ложный формат или не соответствуют приведённому алгоритму
|
||||||
|
- `0x14`, FailedToDecryptBody: не удалось расшифровать тело пакета
|
||||||
|
- `0x21`, InvalidStreamSecret: указанный секрет *потока* не существует
|
||||||
|
- `0x22`, InvalidSessionSecret: указанный секрет *сессии* не существует
|
||||||
|
- `0x23`, UnsupportedProtocolVersion: указанная версия *протокола* не поддерживается
|
||||||
|
- `0x24`, WrongNoiseParams: параметры шума не указаны, имеют ложный формат или отвергнуты *сервером*
|
||||||
|
|
||||||
|
### ErrorDescription
|
||||||
|
|
||||||
|
Строка в кодировке ASCII с текстовым описанием ошибки, без завершающего нулевого байта.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Криптографические параметры
|
||||||
|
|
||||||
|
Тоже самое, что и базовые параметры, только связанное с криптографией.
|
||||||
|
|
||||||
|
```text
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
| Name | Key | Type | Description |
|
||||||
|
|------------------|------|---------------------|--------------------------------------------------|
|
||||||
|
| PayloadHashAlgo | 0x40 | HashCryptoPack | Способ хэширования события | # Event signing
|
||||||
|
| EvSymCiphAlgo | 0x41 | SymCiphCryptoPack | Способ шифрования события | # Event encryption
|
||||||
|
| EvKDAlgo | 0x42 | KDCryptoPack | Способ генерации ключей шифрования для событий |
|
||||||
|
| EvKDInitValue | 0x43 | KDInitValue | Значение для инициализации генератора ключей |
|
||||||
|
| EvKDPrivConst | 0x44 | KDPrivConst | Константа для использования генератором ключей |
|
||||||
|
| ServerSigAlgo | 0x51 | AsymCiphCryptoDesc | Дескриптор алгоритма подписи сервера | # Server-side event signing
|
||||||
|
| ServerSigPubKey | 0x52 | | Публичный ключ подписи сервера |
|
||||||
|
| ClientSigAlgo | 0x55 | AsymCiphCryptoDesc | Дескриптор алгоритма подписи клиента | # Client-side event signing
|
||||||
|
| ClientSigPubKey | 0x56 | | Публичный ключ подписи клиента |
|
||||||
|
| SsidKDAlgo | 0x61 | KDCryptoPack | Способ генерации SSID | # Server-side SID setup
|
||||||
|
| SsidKDInitValue | 0x62 | KDInitValue | Значение для инициализации генератора SSID |
|
||||||
|
| SsidKDPrivConst | 0x63 | KDPrivConst | Константа для использования генератором SSID |
|
||||||
|
| CsidKDAlgo | 0x65 | KDCryptoPack | Способ генерации CSID | # Client-side SID setup
|
||||||
|
| CsidKDInitValue | 0x66 | KDInitValue | Значение для инициализации генератора CSID |
|
||||||
|
| CsidKDPrivConst | 0x67 | KDPrivConst | Константа для использования генератором CSID |
|
||||||
|
----------------------------------------------------------------------------------------------------
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--TODO: параметры SID'ов можно свести к четырём пунктам, но это повышает вероятность ошибки при формализации и реализации-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 3.3. Запрос
|
||||||
|
|
||||||
|
*Клиент* может отправлять запрос *рукопожатия* второго типа только при условии существования *сессии* между ним и *сервером*, а третьего типа - лишь при условии, что в теле запроса указан существующий *поток* в десинхронизированном состоянии.
|
||||||
|
|
||||||
|
В теле любого пакета-запроса *рукопожатия* должны быть указаны NoiseParameters и может быть указано ExtensionsEnum, содержащее перечень поддерживаемых *клиентом* расширений *протокола*. В теле пакета-запроса *рукопожатия* первого типа должна быть ProtocolVersion, в формате, указанном в разделе 2.2.. В теле пакета-запроса *рукопожатия* второго типа должен содержаться SessionSecret, к которой относится создаваемый *поток*. В теле пакета-запроса *рукопожатия* третьего типа должен быть указан StreamSecret, состояние которого предполагается восстанавливать.
|
||||||
|
|
||||||
|
В шифрованном *рукопожатии*, тело запроса шифруется с помощью заведомо-известного *клиенту* публичного ключа *сервера*. <!--TODO: тут и вообще везде применить ту новую терминологию на тему криптографии--> Задаваемые криптографические алгоритмы и ключи, передаваемые *клиентом* в шифрованном запросе *рукопожатия* - распространяются исключительно на создаваемый или восстанавливаемый *поток*.
|
||||||
|
|
||||||
|
В запросе шифрованного *рукопожатия* любого типа должны быть следующие параметры:
|
||||||
|
|
||||||
|
- EvKDInitValue
|
||||||
|
- SsidKDAlgo
|
||||||
|
- SsidKDPrivConst
|
||||||
|
- CsidKDInitValue
|
||||||
|
|
||||||
|
В запросах шифрованного *рукопожатия* первого и второго типов должны быть следующие параметры:
|
||||||
|
|
||||||
|
- PayloadHashAlgo
|
||||||
|
- EvSymCiphAlgo
|
||||||
|
- EvKDAlgo
|
||||||
|
- EvKDPrivConst
|
||||||
|
- ClientSigAlgo
|
||||||
|
- ClientSigPubKey
|
||||||
|
|
||||||
|
Также в *рукопожатии* первого и второго типов *клиент* может опционально добавить MaxPayloadSize.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 3.4. Ответ
|
||||||
|
|
||||||
|
*Сервер* должен отвечать только в случае, если полученные данные имеют корректную структуру, в них присутствует магическое число протокола и корректное значение флага шифрования.
|
||||||
|
|
||||||
|
Если *сервер* принимает запрос *клиента* и отвечает своей частью параметров, то флаг шифрования должен быть установлен в то-же значение, что и в запросе *клиента* и, соответственно флагу, ответ должен быть либо "открытым", либо "шифрованным". Если *сервер* отвечает ошибкой, то, по умолчанию, предполагается "открытый" ответ, за исключением особо-оговорённых случаев.
|
||||||
|
|
||||||
|
При ответе *клиенту* ошибкой, *сервер* может, но не обязан, добавлять в ответ её описание (ErrorDescription). *Клиент* может, но не обязан, обработать это описание наиболее подходящим образом (например - вывести на экран).
|
||||||
|
|
||||||
|
*Сервер* определяет тип *рукопожатия* по запросу, последовательно выполняя следующие шаги:
|
||||||
|
|
||||||
|
1. Проверить, есть-ли в теле запроса секрет *сессии* (SessionSecret). Если да, то это *рукопожатие* второго типа, создание нового *потока*.
|
||||||
|
2. Проверить, указана-ли в теле версия *протокола* (ProtocolVersion). Если да, то это *рукопожатие* первого типа, создание новой *сессии*.
|
||||||
|
3. Если проверки на прошлых шагах провалились, то полученный запрос интерпретируется как *рукопожатие* третьего типа, восстановление состояния *потока*.
|
||||||
|
|
||||||
|
*Сервер* отвечает ошибкой...
|
||||||
|
|
||||||
|
- ...FailedToDecryptBody, если проваливает попытку расшифровать тело запроса шифрованного *рукопожатия*.
|
||||||
|
- ...FailedToParseBody, если проваливает попытку корректно разобрать тело запроса *рукопожатия*.
|
||||||
|
- ...InsufficientParams, если обнаруживает:
|
||||||
|
- Отсутствие StreamSecret в *рукопожатии* третьего типа
|
||||||
|
- Наличие хотя бы одного криптографического параметра, но при этом в целом криптопараметров недостаточно для создания *потока*
|
||||||
|
- ...UnsupportedProtocolVersion, если не поддерживает запрошенную версию *протокола*.
|
||||||
|
- ...InvalidStreamSecret, если указанный StreamSecret не существует.
|
||||||
|
- ...InvalidSessionSecret, если указанный SessionSecret не существует.
|
||||||
|
- ...UnsupportedCryptoAlgo, если знает, но не поддерживает хотя бы один из параметров:
|
||||||
|
- PayloadHashAlgo
|
||||||
|
- EvSymCiphAlgo
|
||||||
|
- EvKDAlgo
|
||||||
|
- ClientSigAlgo
|
||||||
|
- SsidKDAlgo
|
||||||
|
- ...WrongCryptoAlgo, если обнаруживает недопустимые/неизвестные значения в хотя бы одном из параметров:
|
||||||
|
- PayloadHashAlgo
|
||||||
|
- EvSymCiphAlgo
|
||||||
|
- EvKDAlgo
|
||||||
|
- ClientSigAlgo
|
||||||
|
- SsidKDAlgo
|
||||||
|
- ...WrongCryptoValue, если обнаруживает отсутствие или несоответствие избранным криптографическим параметрам хотя бы одного из параметров:
|
||||||
|
- EvKDInitValue
|
||||||
|
- EvKDPrivConst
|
||||||
|
- CsidKDInitValue
|
||||||
|
- SsidKDPrivConst
|
||||||
|
- ClientSigPubKey
|
||||||
|
|
||||||
|
Если после произведения *сервером* всех проверок не обнаружилось каких-либо проблем, то он должен ответить своей частью параметров. Если в *рукопожатии* любого типа *клиент* предоставил ExtensionsEnum, то *сервер* обязан в ответе предоставить ExtensionsEnum с перечислением поддерживаемых им расширений *протокола*. Если в запросе *рукопожатия* содержался параметр MaxPayloadSize, то ответ *сервера* должен содержать MaxPayloadSize со значением равным значению из запроса или меньше. Некорректные значения MaxPayloadSize в запросе - игнорируются.
|
||||||
|
|
||||||
|
В *рукопожатии* первого и второго типа в ответе *сервера* должны содержаться MaxPayloadSize и StreamSecret. В ответе на *рукопожатие* первого типа должен содержаться параметр SessionSecret.
|
||||||
|
|
||||||
|
В ответе шифрованного *рукопожатия* любого типа должны быть параметры:
|
||||||
|
|
||||||
|
- SsidKDInitValue
|
||||||
|
- CsidKDAlgo
|
||||||
|
- CsidKDPrivConst
|
||||||
|
|
||||||
|
В ответе шифрованного *рукопожатия* первого типа должны быть параметры:
|
||||||
|
|
||||||
|
- ServerSigAlgo
|
||||||
|
- ServerSigPubKey
|
||||||
|
|
||||||
|
<!--TODO: вот тут тоже переделать с новой терминологией-->
|
Loading…
Reference in New Issue
Block a user