Как работает шифрование на NoMSG
Каждый клиент генерирует пару ключей ECDH P-256 прямо в браузере. Приватный ключ никогда не покидает устройство — на сервер уходит только публичный ключ, случайный nonce и версия протокола.
Установка общего секрета
После обмена публичными ключами обе стороны независимо собирают одинаковый «транскрипт» сессии: версия протокола, код комнаты, nonce обоих участников и оба публичных ключа. От этого транскрипта берётся SHA-256 — он привязывает ключи именно к этой комнате и этому рукопожатию.
Затем через ECDH deriveBits() получается общий секрет, из которого HKDF-SHA-256 выводит три отдельных значения:
- messageKey — для шифрования сообщений через AES-256-GCM.
- SAS-код — для голосовой сверки между участниками.
- Fingerprint — для дополнительной верификации.
Шифрование сообщений
Каждое сообщение шифруется AES-GCM со случайным 12-байтовым IV. В AAD включаются версия протокола, код комнаты, хэш транскрипта и порядковый номер сообщения. Подмена любого из этих полей ломает проверку тега — сообщение не расшифруется.
Что видит сервер
Сервер — это relay-узел. Он видит только метаданные: код комнаты, IP, публичные ключи и события подключения, а также зашифрованные пакеты в виде seq, iv и ciphertext. Plaintext и приватные ключи на сервер не попадают.
История сообщений не хранится: у проекта нет базы данных, а комнаты живут только в памяти процесса.
Где остаются риски
MITM через подмену ключей. Сервер передаёт публичные ключи между участниками, и злонамеренный сервер теоретически мог бы их подменить. Защита от этого — сверка SAS-кодов по внешнему каналу: голосом, лично или другим доверенным способом. Если оба участника реально сверили коды, MITM невозможен.
Подмена клиентского JS. Это ограничение любого браузерного E2EE: оператор сервера может отдать изменённый JavaScript, который украдёт данные до шифрования. Сам протокол защищён, но доверие к доставленному коду остаётся отдельным вопросом.
Итог в одном абзаце
Из серверного трафика и логов получить plaintext нельзя. Полная конфиденциальность держится на двух условиях: пользователи действительно сверяют SAS-коды и доверяют клиентскому коду, который загрузил браузер.