SHA256
152 lines
10 KiB
Markdown
152 lines
10 KiB
Markdown
# Преобразование 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`, нужно использовать их вместо самодельной реализации.
|