Продолжаем новое
This commit is contained in:
parent
acae23fe35
commit
812465ec2e
3
Data types.md
Normal file
3
Data types.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Структуры данных
|
||||
|
||||
Сия спецификация, помимо всего прочего, также упоминает и определяет некоторые необходимые типы и структуры данных. В директории `Data types/` вы найдёте их описания и примеры декларации на языке C++.
|
20
Data types/Crypto_Algorithm.md
Normal file
20
Data types/Crypto_Algorithm.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Crypto::Algorithm
|
||||
|
||||
Описывает криптографический алгоритм вместе с его базовой конфигурацией.
|
||||
|
||||
## Структура
|
||||
|
||||
`[AlgorithmID: 1B][AlgorithmParams: 1B]`
|
||||
|
||||
## C++
|
||||
|
||||
```C++
|
||||
namespace Crypto {
|
||||
|
||||
struct Algorithm {
|
||||
AlgorithmID ID;
|
||||
AlgorithmParams Params;
|
||||
};
|
||||
|
||||
}
|
||||
```
|
71
Data types/Crypto_AlgorithmID.md
Normal file
71
Data types/Crypto_AlgorithmID.md
Normal file
@ -0,0 +1,71 @@
|
||||
# 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.)
|
||||
-->
|
13
Data types/Crypto_AlgorithmParams.md
Normal file
13
Data types/Crypto_AlgorithmParams.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Crypto::AlgorithmParams
|
||||
|
||||
Описывает параметры алгоритма, например размер ключа. Является двухбайтным целым без знака.
|
||||
|
||||
## C++
|
||||
|
||||
```C++
|
||||
namespace Crypto {
|
||||
|
||||
typedef uint16_t AlgorithmParams;
|
||||
|
||||
}
|
||||
```
|
9
Data types/EventAsyncID.md
Normal file
9
Data types/EventAsyncID.md
Normal file
@ -0,0 +1,9 @@
|
||||
# EventAsyncID
|
||||
|
||||
Является уникальным двухбайтным целым числом без знака и предназначен для определения отношения запросов к ответам при асинхронном обмене _событиями_.
|
||||
|
||||
## C++
|
||||
|
||||
```C++
|
||||
typedef uint16_t EventAsyncID;
|
||||
```
|
9
Data types/LocalObjectID.md
Normal file
9
Data types/LocalObjectID.md
Normal file
@ -0,0 +1,9 @@
|
||||
# LocalObjectID
|
||||
|
||||
Уникальный идентификатор объекта на сервере, является восьмибайтным числом без знака.
|
||||
|
||||
## C++
|
||||
|
||||
```C++
|
||||
typedef uint64_t LocalObjectID;
|
||||
```
|
32
Events.md
32
Events.md
@ -6,11 +6,11 @@
|
||||
|
||||
Существует три уровня категорий _событий_:
|
||||
|
||||
**Надкатегория** описывает типы взаимодействующих _узлов_. Не указывается и зависит от контекста. Варианты: _Client2Server_ (_событие_ сгенерированное _клиентом_ для _сервера_), _Server2Client_ (_событие_ сгенерированное _сервером_ для _клиента_), _Peer2Peer_ (_событие_ сгенерированное _узлом_ для другого _узла_ того-же ранга, в том числе это касается _серверов_ в федерации).
|
||||
**Надкатегория** описывает виды взаимодействующих _узлов_. Не указывается и зависит от контекста. Варианты: _Client2Server_ (_событие_ сгенерированное _клиентом_ для _сервера_), _Server2Client_ (_событие_ сгенерированное _сервером_ для _клиента_), _Peer2Peer_ (_событие_ сгенерированное _узлом_ для другого _узла_ того-же ранга, в том числе это касается _серверов_ в федерации).
|
||||
|
||||
**Категория** описывает _события_ одного класса. Является однобайтовым числом без знака. Всегда больше нуля. Например: _Authentication_, _Object_, т.п.
|
||||
**Категория** описывает _события_ одного класса. Является однобайтным числом без знака. Всегда больше нуля. Например: _Authentication_, _Object_, т.п.
|
||||
|
||||
**Подкатегория** описывает конкретное _событие_ из класса, соответствующего категории. Является однобайтовым числом без знака. Всегда больше нуля. Например: _Login_, _GetContents_, т.п.
|
||||
**Подкатегория** описывает конкретное _событие_ из класса, соответствующего категории. Является однобайтным числом без знака. Всегда больше нуля. Например: _Login_, _GetContents_, т.п.
|
||||
|
||||
Все категории вместе - являются типом _события_. Информацию про зарезервированные типы вы можете найти в [Reserved events.md](Reserved%20events.md).
|
||||
|
||||
@ -18,22 +18,28 @@
|
||||
|
||||
## Содержание и структура
|
||||
|
||||
_События_ всех типов содержат хэш полезной нагрузки размером равно или более 16 байт, зашифрованный с помощью закрытого ключа подписи отправляющего. Этот подписанный хэш гарантирует достоверность полезной нагрузки на уровне прямого подключения между двумя _узлами_. Используемый алгоритм хэширования определяется на этапе рукопожатия.
|
||||
Все _события_ содержат идентификатор серверной сессии размером 4 байта. Подробнее про сессии - в [Sessions.md](Sessions.md).
|
||||
|
||||
Идентификатор серверной сессии является четырёхбайтным целым числом без знака. Подробнее про сессии - в [Sessions.md](Sessions.md).
|
||||
_События_ в _шифрованном соединении_ содержат хэш, применённый к зашифрованному блобу (см. ниже). Этот хэш имеет размер равно или более 16 байт и подписан с помощью закрытого ключа подписи отправляющего. Он гарантирует достоверность содержания _события_ на уровне прямого подключения между двумя _узлами_. Используемые алгоритмы подписи и хэширования определяются на этапе рукопожатия.
|
||||
|
||||
Идентификатор _события_ является двухбайтным целым числом без знака и предназначен для определения отношения запросов к ответам при асинхронном обмене _событиями_.
|
||||
Все _события_ содержат асинхронный идентификатор _события_, который является двухбайтным целым числом без знака и предназначен для определения отношения запросов к ответам при асинхронном обмене _событиями_.
|
||||
|
||||
Данная версия протокола не накладывает ограничений на формат полезной нагрузки, за исключением базовых событий, которые представлены данными в формате _LBM_. Описание всех предопределённых в базовом протоколе ключей ячеек _LBM_ доступно в [Reserved LBM keys.md](Reserved%20LBM%20keys.md). Неизвестные ключи при обработке полезной нагрузки игнорируются. Если полезная нагрузка отсутствует, то она заменяется на один нулевой байт.
|
||||
Все _события_ содержат тип (см. выше раздел "Категории и типы").
|
||||
|
||||
<!--TODO: разные виды сериализации, в зависимости от транспорта?-->
|
||||
_События_ могут содержать полезную нагрузку, либо один нулевой байт, свидетельствующий о её отсутствии. Данная версия протокола не накладывает ограничений на формат полезной нагрузки, за исключением базовых событий, которые представлены данными в формате _LBM_. Описание всех предопределённых в базовом протоколе ключей ячеек _LBM_ доступно в [Reserved LBM keys.md](Reserved%20LBM%20keys.md). При использовании формата _LBM_, в полезную нагрузку могут добавляться шумовые данные. Неизвестные ключи при обработке полезной нагрузки игнорируются.
|
||||
|
||||
Исходя из всего вышеописанного, минимальный размер сериализованного в бинарный вид _события_ составляет 25 байт, а его итоговая структура выглядит следующим образом:
|
||||
_События_ в _шифрованном соединении_ содержат блоб, зашифрованный с помощью актуального ключа сессии и утверждённого алгоритма симметричного шифрования. Этот блоб содержит асинхронный идентификатор, тип события и полезную нагрузку. В нешифрованном соединении, указанные поля находятся в "сыром" виде.
|
||||
|
||||
`[category: 1B][subcategory: 1B][session id: 4B][event async id: 2B][payload hash: >16B][payload: >0B]`
|
||||
Исходя из всего вышеописанного, минимальный размер сериализованного в бинарный вид _события_ в нешифрованном соединении составляет 9 байт, а его итоговая структура выглядит следующим образом:
|
||||
|
||||
Максимальный размер _события_ не нормирован и ответственность за его менеджмент остаётся на транспортном уровне. Максимальный размер полезной нагрузки _события_ определяется на этапе рукопожатия.
|
||||
`[Session ID: 4B][Async ID: 2B][Event Type: 2B][Payload: >0B]`
|
||||
|
||||
### Событие в шифрованном соединении
|
||||
В свою очередь, _события_ в _шифрованном соединении_ имеют размер не менее 25-и байт и следующую структуру:
|
||||
|
||||
В _шифрованном соединении_ _события_ сериализуются в бинарное представление и зашифровываются с помощью утверждённого симметричного ключа сессии.
|
||||
```text
|
||||
[Session ID: 4B][Signed Hash: >=16B][Encrypted Blob: >=5B]
|
||||
/ | \
|
||||
[Async ID: 2B][Event Type: 2B][Payload: >0B]
|
||||
```
|
||||
|
||||
Максимальный размер _события_ не нормирован. Ответственность за менеджмент разделения _события_, в случае, если оно не помещается в один пакет, остаётся на транспортном уровне. Максимальный размер полезной нагрузки _события_ определяется на этапе рукопожатия.
|
||||
|
145
Handshake.md
Normal file
145
Handshake.md
Normal file
@ -0,0 +1,145 @@
|
||||
# Рукопожатие
|
||||
|
||||
На рукопожатие возложена задача выяснить способность _узлов_ устанавливать соединение по описываемому протоколу и согласовать подключение с избранными параметрами каждой стороны. На выбор существует два типа хэндшейка: открытый и зашифрованный. Второй дополнительно требует знать публичный ключ целевого _узла_.
|
||||
|
||||
|
||||
|
||||
## Запрос рукопожатия
|
||||
|
||||
После успешного подключения к целевому _узлу_ через избранный транспорт происходит обмен параметрами обоих сторон. Инициирующий соединение _узел_ отправляет пакет с магический числом, флагом шифрования и сериализованными данными в формат _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, описывающая ошибку в человекочитаемом виде.
|
125
Handshakes.md
125
Handshakes.md
@ -1,125 +0,0 @@
|
||||
# Рукопожатие
|
||||
|
||||
<!--TODO: переделать-->
|
||||
|
||||
|
||||
|
||||
## Протокольного уровня
|
||||
|
||||
После успешного подключения к целевому _узлу_ через избранный транспорт - происходит обмен параметрами обоих сторон, AKA "рукопожатие протокольного уровня". Инициирующий соединение _узел_ отправляет пакет следующего формата:
|
||||
|
||||
`[magic number: 8B][protocol version: 4B][crypto params: 8B][noise params: 1B][reconnection flags: 4B]`
|
||||
|
||||
|
||||
- Магическое число
|
||||
- _Тип:_ `uint64_t`
|
||||
- Магическое число протокола, по которому определяется совместимость цели с протоколом Stadium. См. раздел "Магическое число" для справки.
|
||||
|
||||
- Версия протокола
|
||||
- _Тип:_ `uint32_t`
|
||||
- Поддерживаемая запрашивающим версия протокола.
|
||||
|
||||
- Параметры криптографии
|
||||
- _Тип:_ `CryptoAlgo[4]`
|
||||
- Описывает используемые криптографические алгоритмы на уровне прямого подключения (т.е. "узел-узел"). Первый элемент выделен под хэш-функцию; второй для ассиметричной функции подписи; третий для ассиметричной функции шифрования; четвёртый для симметричной функции.
|
||||
- Если равно нулю, то используются опции данной версии протокола по умолчанию (SHA-384, RSA-3072, AES-256).
|
||||
|
||||
- Параметры генерации шума в соединении
|
||||
- _Тип:_ `uint8_t`
|
||||
- Описывает прочие параметры соединения:
|
||||
- `0b11100000`: выделено под настройки количества _шумовых пакетов_
|
||||
- `0b000`: отсутствие _шумовых пакетов_
|
||||
- `0b001`: количество задаётся по усмотрению целевого _узла_ <!--TODO: звучит странно-->
|
||||
- `0b010`: соотношение _шумовых пакетов_ к реальным - 1:8
|
||||
- `0b011`: соотношение - 1:4
|
||||
- `0b100`: 1:2
|
||||
- `0b101`: 1:1
|
||||
- `0b110`: 2:1
|
||||
- `0b111`: 4:1
|
||||
- `0b00011000`: выделено под настройки размера _шумовых пакетов_
|
||||
- `0b00`: по усмотрению целевого _узла_ <!--TODO: звучит странно-->
|
||||
- `0b01`: случайный размер, в пределах от минимального _пакета_ с нулевой полезной нагрузкой, до размера _пакета_ с полезной нагрузкой размерности, которую должен передать целевой _узел_ при одобрении рукопожатия
|
||||
- `0b10`: случайный размер, в пределах от минимального, до максимального / 2
|
||||
- `0b11`: случайный размер, на основе среднего размера передаваемого пакета +- 25% (но всегда меньше максимального)
|
||||
- `0b00000111`: выделено под настройки размера _шумовых данных_ в обычных _пакетах_
|
||||
- `0b000`: без шумовых данных
|
||||
- `0b001`: заполнение шумовыми данными до лимита полезной нагрузки
|
||||
- `0b010`: заполнение шумовыми данными в случайном количестве, от нуля, до лимита полезной нагрузки
|
||||
- Диапазон `0b011`-`0b111`: зарезервировано <!--TODO: ещё варианты сделать-->
|
||||
|
||||
- Флаги переподключения <!--TODO: сделать енам с перечислением доступных транспортов и их параметров-->
|
||||
- _Тип:_ `uint32_t`
|
||||
- Описывает параметры нового подключения:
|
||||
- `0b00000000000000000000000000000000`: оставить текущее подключение
|
||||
- `0b00000000000000000000000000000001`: запросить новый транспорт для подключения
|
||||
- `0b00000000000000000000000000000100`: использовать TCP
|
||||
- `0b00000000000000000000000000010000`: использовать TLS
|
||||
- `0b00001111111111111111111111101010`: резерв под расширение
|
||||
- `0b11110000000000000000000000000000`: резерв под под нужды сторонних реализаций
|
||||
|
||||
|
||||
На это целевой _узел_ отвечает пакетом либо с согласием, либо с ошибкой.
|
||||
|
||||
Пакет с согласием имеет следующий формат:
|
||||
|
||||
`[magic number: 8B][0x00][reconnection port: 2B][event payload max size: 2B]`
|
||||
|
||||
|
||||
- Магическое число
|
||||
- _Тип:_ `uint64_t`
|
||||
- См. выше.
|
||||
|
||||
- `0x00`
|
||||
- _Тип:_ `uint8_t`
|
||||
- Байт с фиксированным нулевым значением, свидетельствующий об успешном подключении и принятии целевым _узлом_ обозначенных условий.
|
||||
|
||||
- Порт для переподключения
|
||||
- _Тип:_ `uint16_t`
|
||||
- К указанному порту целевой _узел_ предлагает подключиться запрашиваемому, если тот запросил его. Значение должно быть нулём, если порт не был запрошен.
|
||||
|
||||
- Максимальный размер полезной нагрузки
|
||||
- _Тип:_ `uint16_t`
|
||||
- Всегда больше нуля. Запрашивающий должен соблюдать размерность полезной нагрузки в событии и она всегда должна быть равна или меньше этого значения.
|
||||
|
||||
|
||||
Пакет с ошибкой имеет следующий формат:
|
||||
|
||||
`[magic number: 8B][error code: 1B][error description: ~B, zero-terminated]`
|
||||
|
||||
|
||||
- Магическое число
|
||||
- _Тип:_ `uint64_t`
|
||||
- См. выше.
|
||||
|
||||
- Код ошибки
|
||||
- _Тип:_ `uint8_t`
|
||||
- Код, описывающий ошибку конкретнее.
|
||||
- `0x01`: магическое число ложно.
|
||||
- `0x02`: неподдерживаемая версия протокола.
|
||||
- `0x03`: невозможно выделить новый порт для подключения.
|
||||
- `0x04`: указанный транспортный протокол не поддерживается.
|
||||
- `0x05`: указанная конфигурация размерностей не поддерживается.
|
||||
- `0x06`: недопустимые (несуществующие) параметры криптографии.
|
||||
- `0x07`: один из указанных криптографических алгоритмов отключён на _узле_.
|
||||
|
||||
- Описание ошибки
|
||||
- _Тип:_ `uint8_t`
|
||||
- Текстовое описание ошибки. Является строкой в кодировке ASCII, оканчивающейся нулевым байтом.
|
||||
|
||||
|
||||
Если цель не поддерживает указанные при рукопожатии параметры, запрашивающий может попробовать установить соединение снова, с иными значениями.
|
||||
|
||||
Если при хэндшейке запрашивающим был указан новый способ подключения и получен валидный ответ с согласием от целевого _узла_ - то они обязаны разорвать текущее соединение, затем, спустя разумное случайное количество времени, создать новое.
|
||||
|
||||
|
||||
|
||||
## Магическое число
|
||||
|
||||
Магическим числом протокола является следующая последовательность байт:
|
||||
|
||||
```
|
||||
HEX: 0x53 0x74 0x61 0x64 0x69 0x75 0x6d 0x50
|
||||
DEC: 83 116 97 100 105 117 109 80
|
||||
```
|
||||
|
||||
Что соответствует строке "StadiumP" в кодировке ASCII.
|
99
Overview.md
99
Overview.md
@ -18,13 +18,9 @@
|
||||
|
||||
Выполняющий роль клиента _узел_ в многоранговой сети.
|
||||
|
||||
### Подписанное соединение/сессия
|
||||
|
||||
Соединение между двумя _узлами_, все _события_ в котором подписаны с помощью оговорённого ассиметричного алгоритма и приватного ключа отправителя.
|
||||
|
||||
### Шифрованное соединение/сессия
|
||||
|
||||
Соединение между двумя _узлами_, все _события_ в котором шифруется с помощью оговорённого симметричного алгоритма и ключа. Требует _подписанное соединение_ для установки.
|
||||
Соединение между двумя _узлами_, все _события_ в котором шифруются с помощью оговорённого симметричного алгоритма и ключа, а также подписываются с помощью известного приватного ключа подписи отправителя.
|
||||
|
||||
### Событие
|
||||
|
||||
@ -36,88 +32,53 @@ _Событие_ предопределённой категории, имеющ
|
||||
|
||||
### LBM
|
||||
|
||||
Аббревиатура наименования способа форматирования данных, используемого для полезной нагрузки _события_, которая расшифровывается как "Linear Binary Map". Подробнее - в [LBM.md](LBM.md).
|
||||
Аббревиатура наименования способа форматирования (сериализации) данных, используемого для полезной нагрузки _события_, которая расшифровывается как "Linear Binary Map". Подробнее - в [LBM.md](LBM.md).
|
||||
|
||||
### Шумовые данные
|
||||
|
||||
Случайно-сгенерированные данные, помещённые в ячейку полезной нагрузки _события_.
|
||||
Случайно-сгенерированные данные, помещённые в специализированную ячейку полезной нагрузки _события_.
|
||||
|
||||
|
||||
|
||||
## Пример коммуникации двух узлов
|
||||
|
||||
Допустим, что у нас есть два неизвестных друг-другу _узла_ - `p1` и `p2`. Тогда полная коммуникация по шагам (от подключения неизвестного для `p2` _узла_ - до "правильного" уничтожения сессии и закрытия соединения) будет выглядеть так: <!--TODO: предстоит переделать, ввиду предстоящих нововведений-->
|
||||
Допустим, что у нас есть два неизвестных\* друг-другу _узла_ - `p1` и `p2`. Тогда полная коммуникация по шагам (от подключения неизвестного для `p2` _узла_ - до "правильного" уничтожения сессии и закрытия соединения) будет выглядеть так:
|
||||
|
||||
1. `p1` подключается с помощью соответствующего транспорта к `p2`
|
||||
2. `p1` запрашивает рукопожатие с какими-то параметрами подключения
|
||||
3. `p2` отвечает принятием со своей частью параметров подключения
|
||||
4. `p1` запрашивает публичный ключ подписи у `p2`\*
|
||||
5. `p2` отвечает своим публичным ключом и данными об использующемся алгоритме
|
||||
6. `p1` сохраняет публичный ключ сервера в своём хранилище
|
||||
7. `p1` отправляет _событие_ с запросом установки публичного ключа сессионной подписи, подписанное с помощью публичного ключа `p2`\*\*
|
||||
8. `p2` принимает запрос и устанавливает полученный ключ в качестве сессионного для подключения `p1`, если подпись валидна
|
||||
9. `p2` отвечает _событием_ с кодом успешности операции. С этого момента установлено _подписанное соединение_, т.е. узлы **обязаны** подписывать каждое _событие_ и отклонять любые неподписанные/с ложной подписью
|
||||
10. `p1` отправляет _событие_ с запросом _шифрованного соединения_, симметричным ключом, зашифрованным с помощью публичного ключа сервера, и используемым алгоритмом шифрования\*\*\*
|
||||
11. `p2` принимает запрос и устанавливает текущий симметричный ключ сессии
|
||||
12. `p2` отвечает _событием_ с кодом успешности операции. С этого момента установлено _шифрованное соединение_, т.е. узлы **должны** шифровать _события_ с использованием обозначенного ключа
|
||||
13. `p1` отправляет зашифрованное _событие_ с запросом какого-то объекта
|
||||
14. `p2` отвечает зашифрованным _событием_, содержащее этот объект
|
||||
15. `p1` отправляет _событие_ с сообщением о намерении уничтожить сессию и ждёт в течении n времени, по истечению которого может разорвать соединение "насильно"
|
||||
16. `p2` принимает запрос и прекращает любой параллельный обмен данными
|
||||
17. `p2` отвечает _событием_ с кодом успешности операции
|
||||
18. `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` закрывает соединение
|
||||
|
||||
И в виде схемы:
|
||||
|
||||
```
|
||||
Handshake:
|
||||
[p1] --------[transport connect]------> [p2]
|
||||
[p1] --------[handshake request]------> [p2]
|
||||
[p1] <-------[handshake accept]-------- [p2]
|
||||
|
||||
Get p2's public key:
|
||||
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]: saves p2's public key at local storage
|
||||
|
||||
Make signed connection:
|
||||
[p1]: sign event
|
||||
[p1] --------[set session sign]-------> [p2]
|
||||
[p2]: check event signature
|
||||
[p2]: associates p1's public key with this connection
|
||||
[p2]: sign event
|
||||
[p1] <--------[status code OK]--------- [p2]
|
||||
[p1]: check event signature
|
||||
|
||||
Make encrypted connection:
|
||||
[p1]: sign event
|
||||
[p1] ---[set session symmetric key]---> [p2]
|
||||
[p2]: check event signature
|
||||
[p2]: associates symmetric key with this connection
|
||||
[p2]: sign and encrypt event
|
||||
[p1] <--------[status code OK]--------- [p2]
|
||||
[p1]: decrypt and check event signature
|
||||
|
||||
Request some object:
|
||||
[p1]: sign and encrypt event
|
||||
[p1] ------[request some object]------> [p2]
|
||||
[p2]: decrypt and check event signature
|
||||
[p2]: sign and encrypt event
|
||||
[p1] <-------[some object data]-------- [p2]
|
||||
[p1]: decrypt and check event signature
|
||||
|
||||
Close session:
|
||||
[p1]: sign and encrypt event
|
||||
[p1] ---------[close session]---------> [p2]
|
||||
[p2]: decrypt and check event signature
|
||||
[p2]: sign and encrypt event
|
||||
[p1] <--------[status code OK]--------- [p2]
|
||||
[p2]: close connection
|
||||
[p1]: decrypt and check event signature
|
||||
|
||||
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]
|
||||
```
|
||||
|
||||
\* - _стоит уточнить, что в реальных сценариях использования этот публичный ключ должен быть уже известен <!--(см. `TODO`)-->, либо коммуникация должна производиться через транспорт, гарантирующий достоверность передаваемых данных._
|
||||
\* - _стоит уточнить, что в реальных сценариях использования публичный ключ целевого узла скорее всего уже известен, либо коммуникация должна производиться через транспорт, гарантирующий достоверность передаваемых данных. `p1` может узнать о существовании таковых, путём отправки события специального типа. В данном примере сей шаг опущен._
|
||||
|
||||
\*\* - _это может быть публичный ключ подписи `p1`, а может быть и сгенерированный отдельно, в зависимости от сценария использования._
|
||||
<!--TODO: таки описать этот шаг ^^^-->
|
||||
|
||||
\*\*\* - _установка шифрованного соединения полностью опциональна и его отсутствие не накладывает каких-либо ограничений, в рамках этой версии протокола. Формат события в таком соединении см. в [Events.md](Events.md)._
|
||||
\*\* - _"разрыв" соединения предполагает обмен между узлами событиями с информацией о завершении сессии; в данном пункте эти шаги опущены, но упомянуты ниже._
|
||||
|
@ -1,20 +1,18 @@
|
||||
# Спецификация протокола Stadium версии 1.0
|
||||
|
||||
Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения (_SPX - Stadium Protocol eXtension_) для более конкретных нужд. Помимо прочего, данный протокол служит основой для полнофункционального мессенджера Marafon<!--, спецификация расширения которого находится в папке `SPX/Marafon/`-->.
|
||||
Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта и архитектурно не зависящий от оного. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения (_SPX - Stadium Protocol eXtension_) для более конкретных нужд. Помимо прочего, данный протокол служит основой для полнофункционального мессенджера Marafon<!--, спецификация расширения которого находится в папке `SPX/Marafon/`-->.
|
||||
|
||||
Основной фокус при работе над сим проектом идёт на:
|
||||
|
||||
- Возможность функционирования в условиях низкой пропускной способности канала;
|
||||
- Устойчивость к цензуре;
|
||||
- Поддержка широкого спектра транспортных протоколов;
|
||||
- Построение децентрализованных (федеративных и P2P) сетей;
|
||||
- Построение децентрализованных меш-сетей (как одноуровневых, так и двухуровневых);
|
||||
- Гибкое сквозное шифрование;
|
||||
- Расширяемость и возможность подстраивания под конкретные задачи.
|
||||
|
||||
<!--В сей спецификации вы можете встретить примеры кода и упоминание типов данных языка C++.-->
|
||||
|
||||
|
||||
|
||||
**ПРОЕКТ В АКТИВНОЙ РАЗРАБОТКЕ/PROJECT UNDER ACTIVE DEVELOPMENT**
|
||||
|
||||
All text will be translated to english later.
|
||||
All text will be translated to english later.
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Зарезервированные типы событий
|
||||
|
||||
Некоторые категории _событий_ зарезервированы под нужды базового протокола или просто для _событий_ определённого класса. Второе носит рекомендательный характер; вы также можете использовать иные диапазоны для тех-же целей. Ниже приведены диапазоны зарезервированных значений в виде шестнадцатеричных чисел. Конкретный перечень всех зарезервированных событий, описание их структуры - есть в папке `Reserved events/`.
|
||||
Некоторые категории _событий_ зарезервированы под нужды базового протокола или просто для _событий_ определённого класса. Второе носит рекомендательный характер; вы также можете использовать иные диапазоны для тех-же целей. Ниже приведены диапазоны зарезервированных значений в виде шестнадцатеричных чисел. Конкретный перечень всех зарезервированных событий и описание их структуры - есть в папке `Reserved events/`.
|
||||
|
||||
|
||||
Зарезервировано для нужд протокола и запрещено к использованию в сторонних расширениях:
|
||||
@ -11,10 +11,7 @@
|
||||
2. Категория `0x01`
|
||||
- Все субкатегории: выделены для базовых _событий_, связанных с менджментом сессии.
|
||||
|
||||
3. Категория `0x02`
|
||||
- Все субкатегории: выделены для базовых _событий_, которые могут быть приняты _узлом_ вне _подписанного соединения_.
|
||||
|
||||
4. Категория `0x11`
|
||||
3. Категория `0x11`
|
||||
- Все субкатегории: выделены для базовых кодов ответа, ошибок и предупреждений.
|
||||
|
||||
|
||||
@ -22,8 +19,3 @@
|
||||
|
||||
1. Категории `0x12`-`0x1F` (включительно)
|
||||
- Все субкатегории: для кодов ответа, ошибок и предупреждений сторонних реализаций.
|
||||
|
||||
2. Категории `0x20`-`0x2F` (включительно)
|
||||
- Все субкатегории: для _событий_, которые могут быть приняты _узлом_ вне _подписанного соединения_.
|
||||
|
||||
<!-- TODO: событие запроса всех сервисов на сервере -->
|
||||
|
Loading…
Reference in New Issue
Block a user