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