From 08001d7aaadad404da65751d3dd332634e4ce4a2 Mon Sep 17 00:00:00 2001 From: shr3dd3r Date: Wed, 24 Apr 2024 20:23:22 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=BA=D0=BE=D0=BB=D0=BE-=D0=B3=D0=BE?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D0=B0=20=D0=BD=D0=B5=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D0=B0=D1=8F=20=D0=B2=D0=B5=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=81=D0=BF=D0=B5=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 6 ++--- SPX.md | 32 ++++++++++++++++++++++ Криптография.md | 2 -- Оглавление.txt | 4 +-- Пакет.md | 26 ++++++++++++++++++ Поток.md | 6 +++-- Рукопожатие.md | 2 ++ Сериализация (LBM).md | 59 +++++++++++++++++++++++++++++++++++++++++ Сессия.md | 3 +++ Событие.md | 2 +- Транспортный адаптер.md | 3 +++ 12 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 SPX.md create mode 100644 Пакет.md create mode 100644 Сериализация (LBM).md create mode 100644 Сессия.md create mode 100644 Транспортный адаптер.md diff --git a/.gitignore b/.gitignore index b94ca36..2a86e25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ _old/* +schemes/ Терминология.md diff --git a/README.md b/README.md index 804188a..ec4fade 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Неформальная спецификация протокола Stadium версии 1.0 -Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта и архитектурно не зависящий от оного. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения (_SPX - Stadium Protocol eXtension_) для более конкретных нужд. +Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта и архитектурно не зависящий от оного. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения для более конкретных нужд. Основной фокус при работе над этим проектом идёт на: -- Минимизация оверхэда и возможность функционирования в условиях низкой пропускной способности канала; +- Минимизацию оверхэда и возможность функционирования в условиях низкой пропускной способности канала; - Приемлимое функционирование в условиях больших потерь пакетов; -- Поддержка широкого спектра транспортных протоколов "из коробки"; +- Поддержку широкого спектра транспортных протоколов "из коробки"; - Гибкое и кастомизируемое шифрование; - Расширяемость и возможность подгонки под конкретные задачи. diff --git a/SPX.md b/SPX.md new file mode 100644 index 0000000..caa20f3 --- /dev/null +++ b/SPX.md @@ -0,0 +1,32 @@ +# Stadium Protocol eXtension + +Протокол поддерживает различного рода расширения и надстройки, которые могут использоваться в совместимой между собой манере. Под совместимостью подразумевается, что: + +- все корректные пакеты, отправленные узлом без расширения узлу с расширением, будут корректно разобраны и интерпретированы; +- все корректные для базового протокола пакеты, отправленные узлом с расширением узлу без расширения, будут корректно разобраны и интерпретированы; +- расширения не используют конфликтующие элементы функциональности; +- в рамках одной сессии может быть использована любая произвольная комбинация расширений. + +У каждого расширения есть свой уникальный идентификатор/-ы (SPXI) и дескриптор/-ы (SPXD). Идентификатор является либо целым семибитным числом без знака, либо строкой в кодировке ASCII, оканчивающейся нулевым байтом, либо целым числом без знака произвольного размера (1-64 байт). Два последних варианта являются расширенным идентификатором, т.е. e(xtended)SPXI. Обычный идентификатор может использоваться лишь для "официальных" расширений, а расширенный для "официальных" и пользовательских. С расширением может быть ассоциировано вплоть до двух идентификаторов разного типа. Дескриптор расширения предназначен для обмена на этапе рукопожатия и имеет следующую структуру: + +```text +B: byte(s) +b: bit(s) + +|------------------------| +| Extension flag: 1b | +|------------------------| +| eSPXI type or SPXI: 7b | +|------------------------| +| Extended SPXI: ~B | +|------------------------| +``` + +- **Extension flag**: 0 если используется обычный SPXI, 1 если юзается eSPXI. +- **eSPXI type or SPXI**: если флаг 0, то простой идентификатор расширения (SPXI), если флаг 1, то тип расширенного идентификатора (eSPXI). Допустимые типы: + - `0b0000001`: ASCII-строка оканчивающаяся нулём. + - `0b0000010`: целое число произвольного размера. +- **Extended SPXI**: + - Если флаг 0, то отсутствует. + - Если тип eSPXI это строка, то строка, оканчивающаяся нулевым байтом. + - Если тип eSPXI это число, то: `[1 byte: number size in bytes][>0 bytes: number]` diff --git a/Криптография.md b/Криптография.md index 67e2ae3..5ee599d 100644 --- a/Криптография.md +++ b/Криптография.md @@ -18,8 +18,6 @@ - **Private Identity Key**: долговременный приватный ключ. Хранится у сервера и используется для расшифровки полученных запросов рукопожатия. - **Public Identity Key**: долговременный публичный ключ. Ассоциирован с сервером и используется для шифрования запроса рукопожатия при создании шифрованного потока. -Значительная часть функциональности протокола, в том числе касающаяся криптографии, опциональна в том смысле, что может не использоваться в рамках отдельного потока. К примеру, в нём может быть не только настроено количество шума, но и полностью отключен. Таким-же образом, коммуникация может происходить вовсе без шифрования, что может быть полезно, например, для снижения нагрузки на железо, когда протокол транспортного уровня уже обеспечивает требуемый уровень приватности. - ## Пример коммуникации двух узлов diff --git a/Оглавление.txt b/Оглавление.txt index 0ba3d95..11a1408 100644 --- a/Оглавление.txt +++ b/Оглавление.txt @@ -38,8 +38,8 @@ 7. Пакет 7.1. Заголовок пакета 7.1.1. Код аутентификации [Packet Authentication Code, PAC, CltPAC, SrvPAC; проверка целостности и достоверности] - 7.1.2. Флаги - 7.1.3. Идентификатор ответа [RespId; мб стоит сделать PacketID и обязательным для всех, дабы перезапрашивать в случае повреждения] + 7.1.2. Флаги [сжатие, наличие шума, наличие идентификатора] + 7.1.3. Идентификатор [PacketID; присутствует только если включены подтверждения доставки или требуется ответ] 7.2. Полезная нагрузка 7.2.1. Шум в полезной нагрузке пакета 7.3. Структура и шифрование diff --git a/Пакет.md b/Пакет.md new file mode 100644 index 0000000..68a3923 --- /dev/null +++ b/Пакет.md @@ -0,0 +1,26 @@ +# Пакет + +Пакет это физическая единица информации протокола стадиум. Пакет состоит из идентификатора потока, заголовка и тела. Применимость шифрования как такового, криптографические алгоритмы и алгоритмы сжатия - определяются потоком, по которому передаётся пакет. В шифрованном потоке, заголовок шифруется вместе с телом. + +В заголовке пакета находятся такие данные как: код аутентификации пакета (Packet Authentication Code), который представляет из себя хэш от обработанных данных и если пакет передаётся по шифрованному потоку, то он дополнительно подписан; флаги наличия сжатия, шумовых данных и идентификатора; и идентификатор пакета, который присутствует лишь в случае, если в потоке включено подтверждение доставки и/или к данному пакету предполагается ответ. + +В теле пакета содержится произвольное событие и шум (если включен на уровне потока). Ограничения на максимальный размер тела пакета протокола стадиум нет, но оно может опционально подстраиваться под максимальный размер пакета протокола транспортного уровня. В таком случае, если событие не помещается в лимит транспорта - оно разбивается на несколько стадиумных пакетов, которые представляют из себя пачку пакетов. + + +## Ориентировочная схема структуры пакета + +```text +B: byte(s) + +|-------------------------| +| StreamId: 4B | +|-------------------------| +| PAC: >=8B | +|-------------------------| +| Flags: 1B | +|-------------------------| +| PacketId (optional): 2B | +|-------------------------| +| Body: >0B | +|-------------------------| +``` diff --git a/Поток.md b/Поток.md index 1ae0e01..c44b505 100644 --- a/Поток.md +++ b/Поток.md @@ -1,7 +1,9 @@ # Поток -Поток - это логический канал для передачи пакетов, существующий в пределах конкретной сессии. Потоки могут создаваться и уничтожаться по инициативе клиента, сервер может только ограничивать создание новых потоков или уничтожать потоки исходя из соображений защиты от DoS-атак. При создании новой сессии всегда создаётся как минимум один поток. +Поток - это логический канал для передачи пакетов, существующий в пределах конкретной сессии. Потоки могут создаваться и уничтожаться по инициативе клиента, сервер может только ограничивать создание новых потоков или уничтожать потоки исходя из соображений защиты от DoS-атак. При создании сессии всегда создаётся как минимум один поток. Клиенты могут создавать потоки только в пределах собственной сессии. -У потока есть некий набор параметров, часть из которых он разделяет с сессией. У каждого потока есть свой уникальный идентификатор. Поток может быть как "шифрованным", так и "нешифрованным", что влияет на формат пакетов: в нешифрованном потоке, идентификатор потока статичен, а в шифрованном - обновляется и уникален для каждого пакета. Шифрованный поток может находиться в одном из двух состояний: "работает" или "рассинхронизирован", а нешифрованный только в первом. Поток может гарантировать последовательность отправки пакетов и информирование в случае недоставки или повреждения пакета, но это остаётся на усмотрение клиента и отключаемо в случае ненадобности. +У потока есть некий набор параметров, часть из которых он разделяет с сессией. У каждого потока есть свой уникальный идентификатор (StreamId) и секрет (StreamSecret), последний задаётся на этапе создания нового потока. Поток может быть как "шифрованным", так и "нешифрованным", что влияет на формат пакетов: в нешифрованном потоке, идентификатор потока статичен, а в шифрованном - обновляется и уникален для каждого пакета. Шифрованный поток может находиться в одном из двух состояний: "работает" или "рассинхронизирован", а нешифрованный только в первом. В случае непредвиденного нарушения работоспособности шифрованного потока, он переходит в состояние "рассинхронизирован", а вернуть его обратно в состояние "работает" клиент может путём отправки серверу пакета со специальным видом рукопожатия, содержащим StreamSecret. + +Значительная часть функциональности протокола, в том числе касающаяся криптографии, опциональна в том смысле, что может не использоваться в рамках отдельного потока. К примеру, в нём может быть не только настроено количество шума, но и полностью отключен. Таким-же образом, коммуникация может происходить вовсе без шифрования, что может быть полезно, например, для снижения нагрузки на железо, когда протокол транспортного уровня уже обеспечивает требуемый уровень приватности. Поток также может гарантировать последовательность отправки пакетов и информирование в случае недоставки или повреждения пакета, но это остаётся на усмотрение клиента и отключаемо в случае ненадобности. Поток привязан к транспортному протоколу, по которому осуществляется физическая передача пакетов и существует в рамках жизни сессии. Один транспортный протокол может использоваться сразу несколькими потоками. Все потоки двунаправленны, т.е. пакеты могут отправляться как от клиента к серверу, так и наоборот. diff --git a/Рукопожатие.md b/Рукопожатие.md index 13f77b4..6e35a04 100644 --- a/Рукопожатие.md +++ b/Рукопожатие.md @@ -1,5 +1,7 @@ # Рукопожатие +**ВНИМАНИЕ!** _Стиль данного файла не вполне соответствует статусу "неформальной" версии спецификации и слишком заостряет внимание на деталях реализации. Следует иметь ввиду, что в конечном счёте всё может и будет изменено._ + На *рукопожатие* возложена задача создать между *клиентом* и *сервером* новый *поток* на взаимно согласованных условиях. Это включает в себя определение готовности коммуникации по *протоколу*, согласование версии *протокола* в пределах *сессии* (если создаётся новая), а также согласование различных параметров *потока*. *Рукопожатие* может быть "открытое", то есть в котором тело пакета представлено в нешифрованном виде и которое ведёт к созданию нешифрованного *потока*, и "шифрованное", в котором тело пакета зашифровано, подписано, и которое ведёт к созданию шифрованного *потока*. При выполнении этой процедуры используются уникальные форматы пакетов, несоответствующие формальному определению *события*. Формат пакетов использующийся в *рукопожатии* представлен ниже. Существуют следующие типы *рукопожатия*: diff --git a/Сериализация (LBM).md b/Сериализация (LBM).md new file mode 100644 index 0000000..4518381 --- /dev/null +++ b/Сериализация (LBM).md @@ -0,0 +1,59 @@ +# Сериализация и формат LBM + +Данный формат сериализации используются в теле событий зарезервированных типов. Данные сериализованные в формат *LBM* (AKA "данные в формате *LBM*") являются расположенными последовательно ячейками с ключом, длинной значения и значением, в неопределённом порядке относительно друг-друга. Положение ячеек относительно друг-друга не детерминированно и они могут быть намеренно перемешаны. Отсутствие каких-либо ячеек вообще обозначается единичным нулевым байтом. + +Ключ является однобайтным числом без знака. Ключ всегда больше нуля. В контексте протокола и событий зарезервированного типа, некоторые ключи имеют особое значение. Длинна значения является двухбайтным числом без знака. Если ячейка пуста, то длинна нулевая. Значением является произвольная последовательность байт. + +Одна ячейка имеет следующий вид: + +```text +B: byte(s) + +|------------| +| Key: 1B | +|------------| +| Length: 2B | +|------------| +| Value: ~B | +|------------| +``` + +Пример в шестнадцатеричном представлении: + +```text + Length in bytes + | + VVVV +0xDA00080123456789ABCDEF + ^^ ^^^^^^^^^^^^^^^^ + | | + Key Value +``` + +Следовательно, форматированные данные целиком имеют вид: + +```text +|------------| +| Cell 1: ~B | +|------------| +| Cell 2: ~B | +|------------| +| ... | +|------------| +| Cell N: ~B | +|------------| +``` + +Пример в шестнадцатеричном представлении: + +```text + Cell #4 (1B) + Cell #2 (4B) | + | | + VVVVVVVVVVVVVV VVVVVVVV +0xDA00080123456789ABCDEFF10004FEDCBA98220000340001FF... (and so on) + ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ + | | + Cell #1 (8 bytes length) | + Cell #3 (empty cell) +``` diff --git a/Сессия.md b/Сессия.md new file mode 100644 index 0000000..a00e484 --- /dev/null +++ b/Сессия.md @@ -0,0 +1,3 @@ +# Сессия + +Сессия является связующим звеном для потоков, созданных одним узлом. У каждой сессии есть свой набор параметров, задаваемый в момент её создания. Этот набор включает в себя: используемую версия протокола, набор расширений и секрет сессии (SessionSecret), нужный для создания новых потоков в пределах текущей сессии. Сессия создаётся при первом рукопожатии клиента с сервером. При уничтожении сессии - уничтожаются все ассоциированные с ней потоки. diff --git a/Событие.md b/Событие.md index 0381909..be3dbf9 100644 --- a/Событие.md +++ b/Событие.md @@ -1,5 +1,5 @@ # Событие -Событие представляет из себя минимальную смысловую единицу, которой могут обмениваться узлы в соединении. Событиями из зарезервированного диапазона типов (см. `6.2.`) оперирует протокол для управления соединением, все остальные события могут использоваться уровнем приложения для прочих нужд. Событие содержит тип и тело. Тип описывает способ интерпретации тела, а тело содержит произвольные данные, размер которых ограничен значением, обозначенным на этапе хэндшейка. При попытке отправки приложением данных, превышающих этот лимит, на стороне клиента стадиум должна возникнуть ошибка. Сервер не должен предполагать, что получает данные валидной длинны и должен производить проверки самостоятельно. +Событие представляет из себя минимальную смысловую единицу, которой могут обмениваться узлы в соединении. Событиями из зарезервированного диапазона типов оперирует протокол, с целью управления соединением, все остальные события могут использоваться уровнем приложения для прочих нужд. Событие содержит тип и тело. Тип описывает способ интерпретации тела, а тело содержит произвольные данные, размер которых ограничен значением, обозначенным на этапе хэндшейка. При попытке отправки приложением данных, превышающих этот лимит, на стороне отправляющего узла должна возникнуть ошибка. Узел-получатель не должен предполагать, что получает данные валидной длинны и должен производить проверки самостоятельно. Тип события является двухбайтным целым числом без знака. Событие может предполагать ответ от противоположного узла или не требовать оный. Наличие необходимости ответа определяется типом, в каждом случае индивидуально. Корректный тип события никогда не равен нулю. diff --git a/Транспортный адаптер.md b/Транспортный адаптер.md new file mode 100644 index 0000000..3157ff5 --- /dev/null +++ b/Транспортный адаптер.md @@ -0,0 +1,3 @@ +# Транспортный адаптер + +Адаптер представляет из себя нечто, способное вести коммуникацию в рамках конкретного транспортного протокола, преобразовывать передаваемый ему произвольный набор байт в форму, приемлимую транспортным протоколом и корректно воспринимаемую другим адаптером того-же вида, а также выполнять обратное преобразование. В рамках базового протокола определены лишь несколько адаптеров, предназначенные для использования в качестве транспорта протоколы UDP, TCP, HTTP/1.1 и HTTP/1.1+TLS1.3.