Compare commits

...

26 Commits

Author SHA1 Message Date
77127fecb4 Конкретные типы сист. событий и таймаут потока
Описаны некоторые типы системных событий; добавлено понятие категории системных событий; у потоков теперь есть таймауты.
2024-06-09 17:45:33 +03:00
437cfddbbc Правки опечаток 2024-06-09 16:25:31 +03:00
06f7bb56ad Довкид к прошлому коммиту 2024-06-07 22:08:55 +03:00
e87ac9369c Несколько мелких правок формулировок 2024-06-07 22:06:21 +03:00
8f13e6854d Множественные правки и добавления
Добавлено упоминание генерации шума на уровне транспортного адаптера; уточнения касательно разбиения пакетов; у шума можно настроить его характер, т.е. статистические характеристики не касающиеся его количества; формат LBM теперь формат KLV; у транспортных адаптеров теперь есть кодовое имя, определён базовый интерфейс и добавлено перечисление обязательных и рекомендуемых к имплементации видов адаптеров.
2024-06-06 23:58:25 +03:00
a9cbbc5482 Множественные исправления
Правки, внесённые в связи с последними изменениями, уточнениями и пожеланиями.
2024-05-24 00:06:47 +03:00
08001d7aaa Около-готова неформальная версия спеки 2024-04-24 20:23:22 +03:00
c27ecd812d Описан поток и мелкие правки 2024-04-22 23:25:33 +03:00
310d7e9372 Описание событий и общих положений на тему криптографии 2024-04-16 22:43:02 +03:00
ed54ecb7f9 Тотальный передел, глава вторая 2024-03-11 21:30:22 +03:00
07a2413612 Пример файла с описанием типа события готов 2023-12-21 04:35:13 +03:00
999514abec Основа касательно потоков готова 2023-12-19 06:08:43 +03:00
0c4e6cfcd1 Таки нужна поддержка нескольких потоков событий 2023-12-15 21:07:25 +03:00
812465ec2e Продолжаем новое 2023-12-09 00:19:16 +03:00
acae23fe35 Давай по новой (c) 2023-11-20 05:25:05 +03:00
75630f92cf Правки по сессии и структуре пакета 2023-10-28 05:05:32 +03:00
c6b88359f9 Правки касательно ХШ, криптографии и пр. мелочь 2023-10-03 03:10:20 +03:00
29348a49d4 Изменения касательно серверных сессий и пр. правки 2023-09-08 03:25:47 +03:00
dbfe40bc02 Множественные правки и добавления 2023-09-06 06:01:23 +03:00
7384806403 Забыл, что именно, но типа чото добавил 2023-07-17 05:29:20 +03:00
476dda2e30 Сессии, ID, аутентификация и прочее 2023-07-11 04:43:24 +03:00
8e70978778 Do i rly need to comment this sheat? 2023-07-08 04:39:56 +03:00
c38d674031 Marafon Protocol -> Stadium 2023-07-04 23:22:39 +03:00
b38e0bc616 Ну чо, теперь делаем более жирную тему. 2023-07-04 06:30:55 +03:00
72bfaea76d Множественные изменения и +3 события 2023-07-01 05:31:44 +03:00
2ab79a3523 The beginning. 2023-06-30 00:54:02 +03:00
11 changed files with 317 additions and 2 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
_old/*
schemes/

View File

@ -1,3 +1,13 @@
# marafon-proto-specs
# Неформальная спецификация протокола Stadium версии 1.0
Спецификация протокола "Марафона".
Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта и архитектурно не зависящий от оного.
Основной фокус при работе над этим проектом идёт на:
- Минимизацию оверхэда и возможность функционирования в условиях низкой пропускной способности канала;
- Приемлимое функционирование в условиях больших потерь пакетов;
- Поддержку широкого спектра транспортных протоколов "из коробки";
- Гибкое и кастомизируемое шифрование;
- Расширяемость и возможность подгонки под конкретные задачи.
**Внимание!** В данный момент проект находится в стадии активного проектирования. Данная версия спецификации абстрактно описывает общие, преимущественно фундаментальные идеи и концепции, не вдаваясь в детали и местами может противоречить конечному результату, потому и является *неформальной*.

View File

@ -0,0 +1,49 @@
# Криптография
Перед данным протоколом стоит задача обеспечить гибкое шифрование с минимальным ущербом для совместимости между реализациями. Достигается это путём наличия возможности шифрования "в несколько слоёв" и широкого спектра поддерживаемых "из коробки" криптографических алгоритмов и их комбинаций. Реализуемая стадиумом криптографическая система, помимо базового свойства (сокрытие передаваемых данных от третьих лиц), обеспечивает следующие несколько вещей:
- **Достоверность данных**: передаваемые по протоколу данные подписываются криптографическим алгоритмом, выбранным на этапе подключения, что исключает возможность их подмены.
- **Исключение атак повторного воспроизведения**: каждый пакет снабжён уникальными идентификатором, что приводит к невозможности проведения replay-атак.
- **Forward Secrecy**: компрометация долговременного ключа или сессионных ключей не приводит к компрометации прошлых сессионных ключей.
- **Future Secrecy**: компрометация сессионных ключей не приводит к компрометации будущих сессионных ключей.
- **Исключение различных вариаций статистического анализа**: сессионные ключи регулярно проходят ротацию, в соединение подмешиваются "шумовые" пакеты, а в пакеты с реальными данными подмешиваются "шумовые данные", что размывает статистические характеристики и затрудняет анализ, предотвращая разные формы атак на основе шифротекста. Также шум может быть добавлен на уровне транспортного адаптера.
В рамках криптографической системы стадиума существуют несколько понятий, таких как:
- **StreamId**: идентификатор потока. В зашифрованном потоке уникален для каждого отдельного пакета, в незашифрованном - статичен на протяжении всей жизни потока. Используется для определения принадлежности пакета к потоку данных и, в контексте зашифрованного потока, исключения reply-атак. К одному потоку всегда привязаны ровно два идентификатора, один для использования клиентом и другой для сервера. В случае с зашифрованным потоком, обновляется с помощью KDF, в которой подаётся прошлое значение StreamId и константа.
- **Packet Authentication Code**: код аутентификации пакета. Используется для проверки целостности и достоверности пакета, создаётся путём вычисления хэша из тела события и последующей его подписи с помощью SSK отправителя. Непрошедшие проверку целостности пакеты отбрасываются. При избыточном количестве пакетов с ложным PAC, сервер имеет права прервать коммуникацию в одностороннем порядке.
- **Stream Signing Key**: сессионный ключ для подписывания пакетов в шифрованном потоке. У сервера и клиента свой ключ.
- **Packet Encryption Key**: сессионный ключ для шифрования содержимого пакетов в шифрованном потоке с помощью симметричного алгоритма. У сервера и клиента свой ключ. Обновляется с помощью KDF, в которой подаётся прошлое значение PEK и константа.
- **Private Identity Key**: долговременный приватный ключ. Хранится у сервера и используется для расшифровки полученных запросов рукопожатия.
- **Public Identity Key**: долговременный публичный ключ. Ассоциирован с сервером и используется для шифрования запроса рукопожатия при создании шифрованного потока.
## Пример коммуникации двух узлов
Ниже приведена схема коммуникации двух узлов (Алиса - клиент, Боб - сервер), при условии, что PEK обновляются каждый пакет (т.е. уникальны для каждого отдельного пакета).
```text
1: Alice -- request handshake --> Bob
2: Alice <-- accept handshake -- Bob
3: Alice -- send encrypted packet --> Bob
4: Alice and Bob updates Alice's PEK and StreamId using KDFs
5: Alice <-- send encrypted packet -- Bob
6: Bob and Alice updates Bob's PEK and StreamId using KDFs
7: Alice -- update PEK KDF const --> Bob
8: Alice and Bob updates Alice's PEK using KDF with new const and StreamId
9: Alice -- update StreamId KDF const --> Bob
10: Alice and Bob updates Alice's PEK and StreamId using KDF with new const
```
Более детальное описание схемы:
1. Алиса отправляет Бобу зашифрованный с помощью публичного IK запрос рукопожатия с целью создания новой сессии и шифрованного потока, содержащий SSK Алисы; инициализационное значение и константу для KDF, отвечающей за обновление PEK Алисы; инициализационное значение и константу для KDF, генерирующего StreamId Алисы; а также прочие параметры создаваемых сессии и потока.
2. Боб принимает шифрованный запрос рукопожатия, расшифровывает с помощью своего приватного IK и отвечает Алисе своим SSK; инициализационным значением и константой KDF, отвечающей за обновление PEK Боба; инициализационное значение и константу для KDF, генерирующего StreamId Боба; а также прочей своей частью параметров, зашифровав их с помощью SSK Алисы.
3. Алиса шифрует пакет с помощью своего PEK, подписывает с помощью своего SSK, снабжает текущим StreamId и отправляет Бобу.
4. Боб получает пакет, проверяет его с помощью SSK Алисы и расшифровывает с помощью PEK Алисы. После этого Алиса и Боб обновляют PEK и StreamId Алисы с помощью двух KDF.
5. Боб шифрует пакет с помощью своего PEK, подписывает с помощью своего SSK, снабжает текущим StreamId и отправляет Алисе.
6. Алиса получает пакет, проверяет его с помощью SSK Боба и расшифровывает с помощью PEK Боба. После этого Боб и Алиса обновляют PEK и StreamId Боба с помощью двух KDF.
7. Алиса запрашивает обновление константы KDF, генерирующей её PEK, помещая в пакет новое значение константы, после чего повторяя шаги из пункта 3.
8. Боб получает пакет, проверяет его с помощью SSK Алисы и расшифровывает с помощью PEK Алисы. Затем Алиса и Боб обновляют константу для KDF генерирующей PEK Алисы, а также сам PEK и StreamId Алисы с помощью двух KDF.
9. Алиса запрашивает обновление константы KDF, генерирующей её StreamId, помещая в пакет новое значение константы, после чего повторяя шаги из пункта 3.
10. Боб повторяет шаги из пункта 8, но вместо обновления константы KDF для генерации PEK - обновляет уже константу для генерации StreamId Алисы.

8
Оглавление.txt Normal file
View File

@ -0,0 +1,8 @@
1. Криптография
2. Рукопожатие
3. Сессия
4. Поток
5. Пакет
6. Системное событие
7. Транспортный адаптер
8. Сериализация данных

26
Пакет.md Normal file
View File

@ -0,0 +1,26 @@
# Пакет
Пакет это логическая единица информации протокола стадиум. Пакет состоит из идентификатора потока, заголовка и тела. Применимость шифрования как такового, криптографические алгоритмы и алгоритмы сжатия - определяются потоком, по которому передаётся пакет. В шифрованном потоке, заголовок шифруется вместе с телом.
В заголовке пакета находятся такие данные как: код аутентификации пакета (Packet Authentication Code), который представляет из себя хэш от обработанных данных и если пакет передаётся по шифрованному потоку, то он дополнительно подписан; флаги наличия сжатия, шумовых данных, идентификатора и флаг системного события; и идентификатор пакета, который присутствует лишь в случае, если в потоке включено подтверждение доставки и/или к данному пакету предполагается ответ.
В теле пакета содержутся произвольные данные и шум (если включен на уровне потока). Ограничения на максимальный размер тела пакета в рамках протокола нет, но оно может быть опционально задано на этапе рукопожатия, в том числе оно может быть подстроено под максимальный размер пакета транспортного адаптера. Таким-же образом может быть опционально задано максимально количество суб-пакетов. Если данные не помещаются в лимит адаптера - они разбиваются на несколько суб-пакетов, которые представляют из себя пачку и логически являются одним пакетом протокола стадиум. При попытке отправки приложением данных, превышающих лимит размера тела пакета, на стороне отправляющего узла должна возникнуть ошибка. Узел-получатель не должен предполагать, что получает данные валидной длинны/допустимое число суб-пакетов и должен производить проверки самостоятельно.
## Ориентировочная схема структуры пакета
```text
B: byte(s)
|-------------------------|
| StreamId: 4B |
|-------------------------|
| PAC: >=8B |
|-------------------------|
| Flags: 1B |
|-------------------------|
| PacketId (optional): 2B |
|-------------------------|
| Body: >0B |
|-------------------------|
```

11
Поток.md Normal file
View File

@ -0,0 +1,11 @@
# Поток
Поток - это логический канал для передачи пакетов, существующий в пределах конкретной сессии. Потоки создаются и уничтожаются по инициативе клиента. Сервер может ограничивать создание новых потоков и в нормальных условиях не должен уничтожать потоки. При создании сессии всегда создаётся один поток. Клиенты могут создавать потоки только в пределах собственной сессии.
У потока есть некий набор параметров, часть из которых он разделяет с сессией. У каждого потока есть свой уникальный идентификатор (StreamId) и секрет (StreamSecret), последний задаётся на этапе создания нового потока. У потока есть параметры криптографии и шума. Поток может быть как "шифрованным", так и "нешифрованным", что влияет на формат пакетов: в нешифрованном потоке, идентификатор потока статичен, а в шифрованном - обновляется и уникален для каждого пакета. Шифрованный поток может находиться в одном из двух состояний: "работает" или "рассинхронизирован", а нешифрованный только в первом. В случае непредвиденного нарушения работоспособности шифрованного потока, он переходит в состояние "рассинхронизирован", а вернуть его обратно в состояние "работает" клиент может путём отправки серверу пакета со специальным видом рукопожатия, содержащим StreamSecret. <!--TODO: мб написать чуть подробнее, что за "непредвиденное нарушение"-->
У каждого потока также есть собственный таймаут. Таймер запускается узлом сразу после получения любого валидного пакета. Если новый валидный пакет получен до его истечения, то таймер сбрасывается и начинает отсчёт с начала. Если по истечению таймера не было получено валидных пакетов, то узел молча уничтожает поток. Таймаут может быть в любой момент изменён клиентом, о чём должен быть оповещён сервер.
Значительная часть функциональности протокола, в том числе касающаяся криптографии, опциональна в том смысле, что может не использоваться в рамках отдельного потока. К примеру, в нём может быть не только настроено количество шума, но и полностью отключен. Таким-же образом, коммуникация может происходить вовсе без шифрования, что может быть полезно, например, для снижения нагрузки на железо, когда протокол используемый транспортным адаптером уже обеспечивает требуемый уровень приватности. У шума может быть настроен "характер", т.е. его статистические характеристики. Поток также может гарантировать последовательность отправки пакетов и информирование в случае недоставки или повреждения пакета, но это остаётся на усмотрение клиента и отключаемо в случае ненадобности.
Поток привязан к транспортному адаптеру, по которому осуществляется физическая передача пакетов и существует в рамках жизни сессии. Один транспортный адаптер может использоваться сразу несколькими потоками. Все потоки двунаправленны, т.е. пакеты могут отправляться как от клиента к серверу, так и наоборот.

68
Рукопожатие.md Normal file
View File

@ -0,0 +1,68 @@
# Рукопожатие
На рукопожатие возложена задача создать между клиентом и сервером новый поток или восстановить существующий (из десинхронизированного состояния в рабочее), на взаимно согласованных условиях. Это включает в себя определение готовности коммуникации по протоколу, согласование версии протокола в пределах сессии (если создаётся новая), а также согласование различных параметров потока. Рукопожатие может быть "открытое", то есть в котором тело пакета представлено в нешифрованном виде и которое ведёт к созданию нешифрованного потока, и "шифрованное", в котором тело пакета зашифровано, подписано, и которое ведёт к созданию шифрованного потока. При выполнении этой процедуры используются данные в уникальном формате, несоответствующие формальному определению пакета. Формат данных использующийся в рукопожатии представлен ниже.
Существуют следующие типы рукопожатия:
- Первый тип: создаёт новую сессию
- Второй тип: создаёт новый поток в рамках существующей сессии
- Третий тип: восстанавливает существующий поток из десинхронизированного состояния в рабочее
Рукопожатие любого типа выполняется ровно в два действия:
1. Клиент запрашивает рукопожатие с избранными параметрами
2. Сервер отвечает клиенту либо своей частью параметров, либо ошибкой
Пакет рукопожатия состоит из заголовка и тела. В заголовок входят магическое число протокола и флаг шифрования. Тело представляет из себя данные сериализованные в формат KLV.
Флаг шифрования является восьмибитным целым числом и может принимать одно из двух значений:
1. `0x00` - шифрования нет.
2. `0x80` - шифрование включено.
Формат пакета рукопожатия следующий:
```text
B: byte(s)
|----------------------|
| Magic number: 8B |
|----------------------|
| Encryption flag: 1B |
|----------------------|
| Handshake body: >=1B |
|----------------------|
```
## Базовые параметры
Базовые параметры, использующиеся в рукопожатии:
- Параметры шума в потоке
- Версия протокола
- Секрет потока
- Максимальный размер полезной нагрузки пакета
- Код ошибки сервера
- Детальное описание ошибки
## Криптографические параметры
Тоже самое, что и базовые параметры, только связанные с криптографией.
- Алгоритм хэширования пакета
- Алгоритм шифрования события
- KDF для генерации ключей шифрования для пакетов
- Значение для инициализации KDF ключей пакетов
- Константа для использования KDF ключей пакетов
- Алгоритм подписи сервера
- Публичный ключ подписи сервера
- Алгоритм подписи клиента
- Публичный ключ подписи клиента
- KDF для генерации Server StreamId
- Значение для инициализации KDF SSId
- Константа для KDF SSId
- KDF для генерации Client StreamId
- Значение для инициализации KDF CSId
- Константа для KDF CSId

View File

@ -0,0 +1,59 @@
# Сериализация и формат KLV
Аббревиатура KLV расшифровывается как "Key-Length-Value" и используются в теле системных событий и рукопожатии. Данные сериализованные в формат KLV (AKA "данные в формате KLV") являются расположенными последовательно ячейками с ключом, длинной значения и значением, в неопределённом порядке относительно друг-друга. Положение ячеек относительно друг-друга не детерминированно и они могут быть намеренно перемешаны. Отсутствие каких-либо ячеек вообще обозначается единичным нулевым байтом.
Ключ является однобайтным числом без знака. Ключ всегда больше нуля. В каждом контексте (контекст системных событий и контекст рукопожатия) есть свой набор выделенных ключей. Все остальные, неиспользуемые ключи при парсинге опускаются. Длинна значения является двухбайтным числом без знака. Если ячейка пуста, то длинна нулевая. Значением является произвольная последовательность байт.
Одна ячейка имеет следующий вид:
```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)
```

3
Сессия.md Normal file
View File

@ -0,0 +1,3 @@
# Сессия
Сессия является связующим звеном для потоков, созданных одним узлом. Пакет, полученный из любого потока, принадлежащего одной сессии интерпретируется как пакет от одного и того-же клиента. У каждой сессии есть свой набор параметров, задаваемый в момент её создания. Этот набор включает в себя используемую версию протокола. Сессия создаётся при первом рукопожатии клиента с сервером. При уничтожении сессии - уничтожаются все ассоциированные с ней потоки.

View File

@ -0,0 +1,58 @@
# Системное событие
Системное событие представляет из себя смысловую единицу в определённом формате, помещаемую в пакеты с установленным флагом системного события и предназначенную для управления соединением. Событие состоит из типа и тела. Тип описывает способ интерпретации тела, а тело содержит данные в формате KLV.
Тип события является однобайтным целым числом без знака. Событие может предполагать ответ от противоположного узла или не требовать оный. Наличие необходимости ответа определяется типом, в каждом случае индивидуально. Корректный тип события никогда не равен нулю.
У каждого типа события есть категории: Client-to-Server (C2S) и Server-to-Client (S2C). Один тип события может находится сразу в двух категориях. Первая категория подразумевает, что событие этого типа должен обрабатывать только сервер, второе - только клиент. Если тип события находится в обоих категориях, то оно должно обрабатываться как сервером, так и клиентом.
Структура события может быть представлена следующим образом:
```text
B: byte(s)
|----------|
| Type: 1B |
|----------|
| Body: ~B |
|----------|
```
### Список конкретных типов системных событий
Для справки: представленный перечень не является исчерпывающим, а также тут не будут описаны поля и соответствия между ними и KLV-ключами, что будет сделано в полной версии спецификации.
#### EnumerateTransport
**Категория**: C2S
Запрос на выдачу списка адаптеров, по которым можно подключиться к текущему серверу. Ответ содержит либо ошибку, либо перечень адресов транспортных адаптеров. В содержимом события могут быть указаны критерии фильтрации выдачи, например, конкретный вид транспортного адаптера.
#### UpdateStreamParams
**Категория**: C2S
Запрос на обновление параметров потока. Ответ содержит либо ошибку с указанием на конкретный её источник, либо сообщение об успешности операции. В содержимом события указаны лишь те параметры, которые предполагается изменить.
#### CreateStream
**Категория**: C2S
Запрос на создание нового потока с избранными параметрами. Ответ содержит либо ошибку, либо сообщение об успехе.
#### TerminateStream
**Категория**: C2S
Запрос на уничтожение существующего потока. Ответ содержит либо ошибку об отсутствии указанного потока, либо сообщение об успехе.
#### TerminateSession
**Категория**: C2S, S2C
Запрос на уничтожение сессии. Так как в протоколе существует понятие таймаута, для корректного завершения сессии требуется оповещение противоположного узла. После получения события этого типа узлом - он обязан ответить сообщением об успешности операции, после доставки которого оба узла должны уничтожить все потоки в сессии и саму сессию.
#### Answer
Ответ на любой из запросов. Содержит код ответа (успеха или ошибки), описание ошибки (опционально) и произвольные данные (опционально).

View File

@ -0,0 +1,21 @@
# Транспортный адаптер
Адаптер представляет из себя нечто, способное вести коммуникацию в рамках конкретного транспортного протокола, преобразовывать передаваемый ему произвольный набор байт в форму, приемлимую транспортным протоколом и корректно воспринимаемую другим адаптером того-же вида, а также выполнять обратное преобразование. У каждого транспортного адаптера есть собственное кодовое имя, которое позволяет его однозначно идентифицировать.
Транспортный адаптер предоставляет интерфейс для передачи данных в виде блоков, т.е. массивов байт известного размера. У каждого транспортного адаптера есть собственный лимит на максимальный размер блока данных, вне зависимости от того, является ли низлежащий протокол потоковым.
Транспортный адаптер, в силу своей природы, может также обеспечивать дополнительный уровень шифрования и добавлять "шумовые пакеты" в траффик. Адаптеры должны согласовать эти параметры (если нужно) самостоятельно.
В рамках базового протокола предписана реализация нескольких адаптеров, реализующих наивные варианты передачи данных по нижележащим протоколам. Предписанных к реализации адаптеров, перечень которых приведён ниже, существует два типа: обязательные и рекомендуемые. Первые обязаны присутствовать в любой реализации, соответствующей спецификации протокола, вторыми допускается пренебречь.
### Обязательные
- DumbU: реализует передачу поверх протокола UDP
- DumbT: передаёт данные по TCP
### Рекомендуемые
- FirstClass: использует для передачи минималистичный сабсет HTTP/1.1
- TrashBox: использует FTP (RFC 959)
- TLSimp: использует TLS 1.3 (RFC 8446 и пр.)
- Pissle: использует ICMP <!-- Да, название прекрасно, цепочка ассоциаций была следующей: ICMP -> ICBM -> Missle -> Ping Missle -> ... -->