50 lines
9.6 KiB
Markdown
50 lines
9.6 KiB
Markdown
# Криптография
|
||
|
||
Перед данным протоколом стоит задача обеспечить гибкое шифрование с минимальным ущербом для совместимости между реализациями. Достигается это путём наличия возможности шифрования "в несколько слоёв" и широкого спектра поддерживаемых "из коробки" криптографических алгоритмов и их комбинаций. Реализуемая стадиумом криптографическая система, помимо базового свойства (сокрытие передаваемых данных от третьих лиц), обеспечивает следующие несколько вещей:
|
||
|
||
- **Достоверность данных**: передаваемые по протоколу данные подписываются криптографическим алгоритмом, выбранным на этапе подключения, что исключает возможность их подмены.
|
||
- **Исключение атак повторного воспроизведения**: каждый пакет снабжён уникальными идентификатором, что приводит к невозможности проведения 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 Алисы.
|