Как устроен Mirage.
Что делает криптография, что инфраструктура видит и чего не видит, и как движок встраивается в другой продукт. Прямо о том, какие части готовы, а какие — нет.
Начнём с того, чего система не делает.
Любой мессенджер от чего-то защищает, а что-то оставляет открытым. Оценить устройство можно, только когда на столе обе половины.
Против чего работает
- Провайдер или оператор сети, читающий содержимое сообщений или звонков
- Оператор relay, читающий что-либо из того, что он передаёт, — включая нас
- Попытка прочитать ваш список контактов на наших серверах: его там нет
- Расшифровка прошлого трафика после того, как ключ позже скомпрометирован
- Подмена сообщения в пути: она обнаруживается, а не просто маловероятна
От чего не защищает
- Скомпрометированное устройство: вредоносная программа или программа, считывающая экран, на вашем же устройстве
- Собеседник, который всегда может сохранить или переслать то, что вы отправили
- Глобальный противник, сопоставляющий тайминги по всей сети
- Человек, получивший вашу фразу восстановления
- Наблюдатель на вашем локальном канале, который узнаёт, что вы вообще подключены
Аккаунта нет — есть только ключ.
Ни номера телефона, ни почты, ни регистрации. Пользователь — это открытый ключ, а идентификатор, который видят другие, выводится из него. Чтобы идентичность существовала, сервер не нужен.
Идентичность спроектирована в два уровня, чтобы потеря устройства не означала потерю аккаунта. Корневой ключ (Ed25519) никогда ничего не шифрует; его единственная задача — подписывать версионированный roster, список устройств, которые сейчас принадлежат вам. Украденное устройство отзывается публикацией новой версии roster. Несколько устройств — в работе
Проверка устроена так, как должна: сверьте отпечаток по независимому каналу. Приложение показывает его короткими группами, чтобы его можно было прочитать вслух. Если вы потеряете все устройства, аккаунт вернёт фраза восстановления BIP-39.
Ключи движутся вперёд, никогда — назад.
Разговор начинается с согласования ключей X3DH поверх X25519 — оно позволяет отправить первое сообщение, даже пока собеседник офлайн. Дальше сессия работает на Double Ratchet: каждое сообщение продвигает ключевой материал, поэтому ключ, украденный сегодня, не открывает вчерашний трафик, а сессия восстанавливается, как только скомпрометированный ключ выходит из употребления.
У звонков свой ratchet, отдельный от текстового, потому что медиаключи ротируются в другом ритме. Содержимое запечатывается ChaCha20-Poly1305 или AES-256-GCM. Оба — аутентифицированное шифрование, поэтому подмена обнаруживается, а не просто маловероятна.
Несколько маршрутов наперегонки.
NAT — причина, по которой большинство P2P-программ незаметно откатываются на сервер. Mirage пробует несколько стратегий сразу и берёт ту, что сработает первой, поэтому прямой путь используется всегда, когда он существует.
Напрямую к пиру
Если адрес уже известен из обмена пирами (peer exchange), QUIC-соединение открывается сразу, и сервер не участвует.
Знакомство через mesh ранняя стадия
Когда доступны другие десктопные узлы, они могут помочь обеим сторонам пробить NAT вместо центрального relay.
Hole punching через relay
Relay синхронизирует UDP-рандеву двух сторон. Он их знакомит, но саму сессию не переносит.
Через relay, по-прежнему запечатано
Когда прямого пути нет, relay пересылает пакеты, которые не может открыть. Фолбэк на TCP/443 для сетей, которые полностью режут UDP, — в планах
Что relay видит и чего не видит.
Relay нужен для обнаружения, обхода NAT и хранения сообщений для тех, кто офлайн. Аккаунтов пользователей он не хранит, а всё, что он передаёт, запечатано ещё до того, как к нему попадёт. Вот честная опись.
Строки «да» — вот о чём стоит спорить, и именно поэтому устройство так настойчиво стремится к прямым соединениям: то, что relay никогда не передаёт, у него никогда нельзя потребовать выдать.
Запечатанные конверты у того, кто не может их открыть.
Если получатель офлайн, сообщение шифруется в конверт и оставляется у relay. Конверт аутентифицирован, поэтому хранитель не может его изменить, и непрозрачен, поэтому хранитель не может его прочитать. Он доставляется, когда получатель возвращается; relay узнаёт только, что что-то ждало.
Сейчас конверты хранятся в памяти relay до суток. Хранение их на десктопных узлах mesh вместо relay и зашифрованный бэкап истории спроектированы и в работе
Сделано для сетей, которые мешают.
Всё идёт поверх QUIC на UDP/443 с TLS 1.3 внутри, поэтому сертификаты и метаданные сессии не видны анализатору на пути. Служебный трафик (обмен ключами, обнаружение пиров, присутствие) идёт в том же туннеле, что и сообщения. Второго канала, за которым можно следить, нет.
Кроме того, транспорт может формировать собственный поток пакетов так, чтобы он не нёс статистического отпечатка мессенджера. Это усиление — опция для развёртываний во враждебных или сильно фильтруемых сетях, а не требование протокола.
Механизм здесь сознательно не описан. Публикация подробностей помогла бы в основном тем, кто строит классификаторы. С криптографией ровно наоборот: её стойкость никогда не должна зависеть от секретности, поэтому она описана полностью.
Одна идея для чатов и звонков: комната.
Текстовый разговор и звонок внутри движка — один и тот же объект: комната. Внутри QUIC-соединения каждая комната использует независимые потоки — один для управления, один для исходящего медиа и отдельный входящий поток на каждого участника, — поэтому один медленный пир не может застопорить всех остальных.
Маршрутизаторы слепы: они пересылают запечатанные пакеты, не имея ключей ни к одному из них. Чаты и звонки один на один уже доступны. Небольшие групповые звонки используют общий ключ, согласованный между участниками, и находятся в тестировании для групп до восьми человек. Групповые чаты — в работе
Управление групповыми ключами переводится на MLS (RFC 9420) через мост на Rust вокруг openmls. Мост построен и прошёл нагрузочное тестирование; подключение его к движку — работа, которая идёт сейчас.
Пять слоёв, ничего на диске.
Всё описанное выше живёт в ядре на C++20. Интерфейс поверх него заменяем; десктопный мессенджер — просто первое, что на нём стоит.
Ядро ничего не хранит на диске. Ни базы данных, ни файлов конфигурации, ни хранилища ключей. Это сетевой движок в памяти, который порождает события, а всё постоянное принадлежит приложению, в которое он встроен. Правило существует ради восстанавливаемости, и заодно благодаря ему движок легко разместить внутри чужого продукта.
То же ядро — внутри вашего продукта.
Mirage — проприетарная разработка, права на которую принадлежат нам целиком. Если вам нужна приватная связь внутри того, что вы уже строите, ядро можно лицензировать и интегрировать, а не писать заново. Мессенджер — его эталонное приложение, а не единственное, чем оно может быть.
Версионированный C ABI
Вызывается из чего угодно с FFI: Node, Python, Go, Rust, C#, Swift. В разработке ABI 2.0 — с владением через контекст и семантическим версионированием; именно за эту поверхность мы возьмём на себя обязательства.
Управление через колбэки
Регистрируете обработчики сообщений, состояния комнат, событий звонков и декодированного медиа. Движок сам вызывает ваше приложение и не навязывает собственный цикл событий.
Хранение и UI — ваши
Ключи, история и интерфейс остаются внутри вашего продукта — по вашим правилам комплаенса и хранения данных, а не по нашим.
Ваша инфраструктура
Relay — небольшой сервис на Go в одном контейнере. Запустите его в своей сети и своей юрисдикции; в нём нет пользовательских аккаунтов, которые пришлось бы переносить или выдавать по судебному запросу.
/* ABI 2.0 (в разработке): так выглядит интеграция, имена ещё могут измениться */ mirage_abi_version(…); /* major должен совпадать, minor — не меньше вашего */ mirage_context_create(…); /* один движок на контекст, несколько на процесс */ mirage_set_callbacks(…); /* сообщения, комнаты, звонки, медиа */ mirage_room_create(…); mirage_room_send_text(…); mirage_room_leave(…); mirage_context_stop(…); mirage_context_destroy(…);
Где это реально подходит: клиники и консультационные приложения, полевые и промышленные инструменты, которые должны работать в трудных сетях, оборудование, которому нужен зашифрованный канал управления, и продукты, которые не хотят отдавать переписку своих пользователей поставщику мессенджера.
Хотите разобрать устройство вместе?
Мы с радостью пройдёмся по протоколу, коду или интеграции вместе с вашими инженерами. Дизайн-партнёры получают ранний доступ и реальное влияние на то, что будет дальше.
Записаться на технический разборИли прочитайте о программе дизайн-партнёров.