SHA256
Документировать новый DM-протокол и формат (в коде пока не реализовано)
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# Преобразование Ed25519 в X25519
|
||||
|
||||
## Назначение
|
||||
|
||||
Этот документ фиксирует единое правило проекта SHiNE:
|
||||
|
||||
- публичная идентичность пользователя задаётся одним `clientKey` в формате `Ed25519`;
|
||||
- подпись пользовательских сообщений и команд выполняется ключом `Ed25519`;
|
||||
- шифрование личных сообщений использует ключ `X25519`, получаемый детерминированно из того же ключевого материала;
|
||||
- для преобразования используется только стандартное преобразование `Ed25519 <-> X25519`;
|
||||
- самодельные формулы, альтернативные хэши и нестандартные схемы преобразования в проекте не допускаются.
|
||||
|
||||
Цель документа: исключить путаницу между ключом подписи и ключом шифрования и зафиксировать один общий способ преобразования для клиента, сервера и будущих реализаций.
|
||||
|
||||
## Краткое правило
|
||||
|
||||
Если у пользователя есть:
|
||||
|
||||
- приватный ключ `Ed25519 private`;
|
||||
- публичный ключ `Ed25519 public` (`clientKey`);
|
||||
|
||||
то для шифрования личных сообщений из них получаются:
|
||||
|
||||
- `X25519 private` для расшифровки своих копий;
|
||||
- `X25519 public` для шифрования сообщений на этого пользователя.
|
||||
|
||||
При этом:
|
||||
|
||||
- в профиле пользователя по-прежнему публикуется только `clientKey`;
|
||||
- отдельный публичный `dmEncKey` не требуется;
|
||||
- владелец устройства локально может использовать один и тот же исходный секрет и для подписи, и для вывода ключа шифрования.
|
||||
|
||||
## Что считается стандартным преобразованием
|
||||
|
||||
Под "стандартным преобразованием" в проекте понимается совместимое с общепринятой практикой libsodium/NaCl преобразование:
|
||||
|
||||
- из `Ed25519 private` получается `X25519 private` через стандартную процедуру на основе SHA-512 и clamping;
|
||||
- из `Ed25519 public` получается `X25519 public` через стандартное преобразование точки Edwards в точку Montgomery.
|
||||
|
||||
Иными словами:
|
||||
|
||||
- приватный ключ шифрования должен получаться из приватного ключа подписи стандартным способом;
|
||||
- публичный ключ шифрования должен получаться из публичного `clientKey` стандартным способом;
|
||||
- обе стороны должны получать одинаковый `X25519 public` по одному и тому же `clientKey`.
|
||||
|
||||
## Преобразование приватного ключа
|
||||
|
||||
Исходные данные:
|
||||
|
||||
- `Ed25519 private` в SHiNE рассматривается как 32-байтный seed приватного ключа.
|
||||
|
||||
Стандартная процедура:
|
||||
|
||||
1. Вычислить `SHA-512(seed32)`.
|
||||
2. Взять первые 32 байта результата.
|
||||
3. Применить стандартный clamping для `X25519 private`.
|
||||
4. Полученный результат использовать как `X25519 private`.
|
||||
|
||||
Замечания:
|
||||
|
||||
- нельзя использовать для `X25519 private` просто исходный 32-байтный `Ed25519 seed` без преобразования;
|
||||
- нельзя заменять `SHA-512` на `SHA-256`, `HMAC`, `HKDF` или произвольную пользовательскую формулу;
|
||||
- clamping обязателен.
|
||||
|
||||
## Преобразование публичного ключа
|
||||
|
||||
Исходные данные:
|
||||
|
||||
- `clientKey` пользователя в формате `Ed25519 public` (32 байта).
|
||||
|
||||
Стандартная процедура:
|
||||
|
||||
1. Декодировать публичную точку Edwards из `Ed25519 public`.
|
||||
2. Выполнить стандартное преобразование Edwards -> Montgomery.
|
||||
3. Полученное значение использовать как `X25519 public`.
|
||||
|
||||
На уровне математики используется стандартное отображение:
|
||||
|
||||
- `u = (1 + y) / (1 - y)`
|
||||
|
||||
где `y` берётся из публичной точки Ed25519, а результат `u` кодируется как публичный ключ `X25519`.
|
||||
|
||||
Замечания:
|
||||
|
||||
- нельзя получать `X25519 public` простым хэшированием `clientKey`;
|
||||
- нельзя получать `X25519 public` "через приватный ключ на сервере";
|
||||
- любой клиент должен уметь вывести `X25519 public` другого пользователя, имея только его `clientKey`.
|
||||
|
||||
## Что хранится в проекте
|
||||
|
||||
На текущем архитектурном уровне:
|
||||
|
||||
- в публичном профиле пользователя хранится только `clientKey` (`Ed25519 public`);
|
||||
- приватная часть `clientKey` хранится только у владельца устройства;
|
||||
- `X25519 private` и `X25519 public` считаются производными величинами и могут вычисляться по мере необходимости;
|
||||
- отдельный `keyId` для DM пока не вводится.
|
||||
|
||||
Это означает:
|
||||
|
||||
- если в будущем пользователь сменит `clientKey`, старые DM должны будут быть перешифрованы;
|
||||
- массовая перешифровка истории рассматривается как отдельная функция более позднего этапа;
|
||||
- текущая архитектура должна оставлять возможность такой перешифровки, но не обязана реализовывать её прямо сейчас.
|
||||
|
||||
## Как это применяется в DM
|
||||
|
||||
Для личных сообщений SHiNE:
|
||||
|
||||
- входящая копия сообщения шифруется на `X25519 public`, полученный из `clientKey` получателя;
|
||||
- исходящая копия сообщения шифруется на `X25519 public`, полученный из `clientKey` отправителя;
|
||||
- расшифровать входящую копию может только владелец приватного ключа получателя;
|
||||
- расшифровать исходящую копию может только владелец приватного ключа отправителя.
|
||||
|
||||
Следствия:
|
||||
|
||||
- `encryptedBody` у входящей и исходящей копии одного логического сообщения обычно разный;
|
||||
- сервер не должен требовать побайтного совпадения ciphertext у пары;
|
||||
- сервер не должен уметь расшифровывать содержимое DM;
|
||||
- подпись и шифрование используют один корневой секрет пользователя, но разные стандартно выведенные представления ключа.
|
||||
|
||||
## Ограничения и компромиссы
|
||||
|
||||
Эта архитектура осознанно имеет следующие свойства:
|
||||
|
||||
- компрометация приватного `clientKey` одновременно даёт злоумышленнику возможность и подписывать от имени пользователя, и расшифровывать его личные сообщения;
|
||||
- отдельное разделение ключа подписи и ключа шифрования пока не используется;
|
||||
- простота пользовательской модели и минимизация числа публичных ключей считаются в проекте более важными, чем разделение этих ролей на текущем этапе.
|
||||
|
||||
Если позже проекту понадобится более строгая модель безопасности, допускается переход на отдельный публичный ключ шифрования, но только как отдельная версия протокола.
|
||||
|
||||
## Что запрещено
|
||||
|
||||
В проекте запрещено:
|
||||
|
||||
- придумывать собственное "детерминированное преобразование" `Ed25519 -> X25519`;
|
||||
- хэшировать `clientKey` произвольным образом и считать результат `X25519 public`;
|
||||
- использовать `Ed25519 public` напрямую как ключ ECDH;
|
||||
- использовать сырой `Ed25519 seed` как `X25519 private` без стандартной процедуры;
|
||||
- смешивать разные способы преобразования в разных клиентах.
|
||||
|
||||
## Требование к реализациям
|
||||
|
||||
Любая реализация SHiNE, которая:
|
||||
|
||||
- подписывает DM;
|
||||
- шифрует DM;
|
||||
- расшифровывает DM;
|
||||
- проверяет совместимость личных сообщений между устройствами;
|
||||
|
||||
обязана использовать именно этот подход.
|
||||
|
||||
Если библиотека уже предоставляет готовые совместимые функции преобразования `Ed25519 -> X25519`, нужно использовать их вместо самодельной реализации.
|
||||
Reference in New Issue
Block a user