Криптография
August 20, 2024

Blinded ID в Session и что с ними не так

Blinded ID (aka "слепые" айди и т.п) - алгоритм деривации ID пользователя, который является публичным ключом Curve25519, для открытых групп в Session, для того чтобы скрыть настоящий ID пользователя.

Всего существует две версии данного алгоритма:

  1. Legacy версия (ID начинается с префикса 15)
  2. Новая версия (ID начинается с префикса 25)

На данный момент полностью реализованной является legacy версия, а поддержка новой версии есть только в libsession и вроде как планируется в pysogs.

Важно: Все математические операции выполняются в поле Fp кривой ed25519, манипуляции со скалярами (редуцирование, инвертирование) выполняются в поле Fn (order field)

Один ключ -> два ключа. Legacy версия.

Алгоритм

Для работы алгоритма нам понадобится:

  • ID пользователя
  • Публичный ключ сервера

Сам алгоритм:

  1. Генерируем т.н "blinding factor": хэшируем с помощью Blake2B публичный ключ сервера и редуцируем результат.
    Обозначим, как k.
  2. Из ID пользователя убираем префикс 05 и переводим его в ed25519.
    Обозначим, как A.
  3. Умножаем k на A и получаем ключ ed25519, который является одним из возможных "слепых" id.
    Обозначим, как kA.
Примерная запись алгоритма

Сломанное условие

Как следует из заголовка, legacy версия генерирует 2 возможных "слепых" ID.

Второй возможный ID (kA2) генерируется на основе kA, только с изменённым (XOR на 128) sign битом.

И для того чтобы выяснить какой из двух ключей следует использовать, pysogs предлагает следующий код:

if kA[31] & 0x80:
    return kA[0:31] + bytes([kA[31] & 0x80])

Однако это условие совершенно не работает, поэтому в реализации клиентов пошли другим путём - получение "слепого" id из приватного ключа, вместо того чтобы получать его из публичного ключа. Таким образом сервер не знает наверняка, какой ключ из двух следует использовать, и надеется на клиент в результате чего в теории может произойти раздвоение пользователя.

Примерная запись условия

Обратимая необратимость

Так же немало важным является то, что legacy версия (а фактически единственная версия на момент написания статьи) является обратимой вопреки всем заявлениям.

Для этого достаточно инвертировать полученный ранее "blinding factor", умножить его на слепой id, полученный ключ перевести в Curve25519 и в результате мы имеем ID пользователя.

Примерная запись алгоритма

Один ключ -> один ключ. Новая версия

На момент написания статьи эта версия реализована только в libsession, и поэтому может поменяться.

Самое главное отличие этой версии от legacy в том, что в процессе генерации "blinding factor" принимает участие ID пользователя вместе с публичным ключом сервера, что, в свою очередь, исключает возможность обратимости, как это было с legacy версией.

Т.е алгоритм следующий:

  1. Генерируем "blinding factor": хэшируем с помощью Blake2B ID пользователя (вместе с префиксом) и публичный ключ сервера и редуцируем результат.
    Обозначим, как k.
  2. Переводим ID пользователя из Curve25519 в ed25519.
    Обозначим, как A.
  3. Умножаем скаляр k на A

На выходе получаем единственный Blinded ID для конкретного пользователя на конкретном сервере.

Примерная запись алгоритма

Ссылки

Моя библиотека "Session ID"

Проект Session.js

Проект bunsogs