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

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

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

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

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

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

Один ключ -> два ключа. 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) MSB битом.

И для того чтобы выяснить какой из двух ключей следует использовать, 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