Как работает Clavenzo
В общих чертах, простыми словами и без пропущенного важного. Если коротко: телефон или компьютер создаёт ключ, ключ и есть ваш адрес, а всё, что идёт между двумя устройствами, зашифровано ключами, которые есть только у этих двух.
Ваша личность — это ключ, а не аккаунт
Большинство мессенджеров начинают с просьбы дать номер телефона. Этот номер выдан оператором, привязан к паспортному имени, может быть переоформлен любым, кто сумеет убедить продавца в салоне, и пробивается всяким, у кого он есть. Это плохой фундамент для частного разговора.
Clavenzo начинает иначе. При первом запуске приложение создаёт на устройстве пару криптографических ключей. Открытая половина становится вашим адресом. Закрытая остаётся на устройстве. Она никогда не копируется ни в какое облако и никогда не оказывается у нас. Она покидает устройство, только если вы сами её экспортируете, и тогда она запечатана одноразовым кодом.
Ваш адрес показывается двумя способами: кодом из 16 символов, который можно продиктовать или вставить, и QR-кодом, который можно отсканировать. Есть ещё короткий код — только для проверки, что вы говорите с нужным человеком: слишком короткий, чтобы кого-то по нему добавить, и достаточно длинный, чтобы сверить вслух.
Что происходит, когда вы звоните
Двум телефонам нужно найти друг друга, а потом договориться о ключе. Clavenzo делает вторую часть так, что первая перестаёт быть интересной для подслушивающего.
- Найти друг друга. Если вы звоните тому, кто виден в разделе «Поблизости» в той же сети Wi-Fi, телефоны соединяются напрямую и сервер не участвует. Иначе небольшая служба встреч доставляет запечатанное предложение, и телефоны пытаются построить прямой путь между собой. Для этого каждый телефон сообщает другому свои сетевые адреса, поэтому приложение собеседника узнаёт ваш IP-адрес.
- Договориться о ключе. Два устройства выполняют подписанный эфемерный обмен X25519, а через мгновение после соединения добавляют поверх постквантовый обмен ключами, ML-KEM-768. «Эфемерный» — главное слово: ключи создаются для одного этого звонка и уничтожаются, когда он заканчивается.
- Говорить. Речь кодируется в 33 байта каждые 20 миллисекунд, и каждый такой пакет шифруется и аутентифицируется отдельно. Для наблюдателя в сети содержимое выглядит как случайный шум, хотя по ритму пакетов всё ещё можно понять, когда кто-то говорит.
- Проверить. Оба телефона выводят четыре слова из фактически согласованного ключа. Прочитайте их вслух. Если на обоих экранах они совпали — посередине никого нет.
Последний шаг — тот, который пропускают, и тот, который важнее всего. Шифрование гарантирует, что вас прочтёт тот, у кого есть второй ключ. Само по себе оно не скажет, кто это. Четыре слова — способ это выяснить.
Почему запись сегодняшнего звонка останется нечитаемой
Есть распространённая и вполне реальная атака, требующая терпения: записать зашифрованный трафик сейчас, получить ключ позже — по постановлению суда, кражей, взломав устройство спустя годы — и спокойно расшифровать запись.
Эфемерные ключи её ломают. Ключ, которым в действительности был зашифрован ваш звонок, существовал ровно столько, сколько шёл звонок, на двух устройствах, и был уничтожен в конце. Ваш долговременный ключ личности только подписывает обмен; он не шифрует ни секунды звука. Скомпрометировав его завтра, можно выдать себя за вас завтра. Открыть то, что записали вчера, — нельзя.
Это свойство называется прямой секретностью и является самым ценным, что может быть у зашифрованного звонка.
Кроме того, каждый звонок заново вырабатывает ключи с ML-KEM-768, постквантовым алгоритмом, через долю секунды после соединения, если оба приложения это поддерживают. Это ответ тому же терпеливому противнику с инструментом получше: трафик записан сейчас, а вскрыт позже квантовым компьютером. С сообщениями и файлами пока иначе. Они запечатываются сразу RSA и ML-KEM-768, но сегодня ключ ML-KEM выводится из ключа RSA, поэтому мы пока не называем их постквантовыми. А у сообщения, которое ждёт на сервере, пока телефон получателя выключен, нет прямой секретности: тот, кто его записал и позже заполучил ключ личности получателя, смог бы его открыть.
Что сервер делает и чего не может
Есть одна задача, с которой одноранговое приложение в самом деле не справится само: разбудить телефон, в котором приложение закрыто. Для этого существует служба встреч, устроенная так, чтобы знать как можно меньше и при этом справляться.
- Она никогда не видит содержимого. Предложения и офлайн-сообщения запечатываются ключом получателя ещё до того, как покинут ваш телефон. Служба хранит байты, которые не может открыть.
- Он не знает вашего имени. В его каталоге хранятся адрес каждого устройства, его открытые ключи и платформа, а для телефона ещё и push-токен. В нём нет ни имён, ни номеров телефонов, ни адресов почты, потому что приложение их никогда не спрашивает. Любой, у кого есть адрес, может спросить, зарегистрирован ли он.
- Её уведомления не содержат ни отправителя, ни содержимого. Сигнал, будящий телефон, сообщает только, звонок это или сообщение. На iPhone уведомление о сообщении выглядит как «New message» и «Tap to read». Apple и Google видят, что что-то было отправлено и когда, но не видят, что это было и от кого.
- Она быстро забывает. Приглашение к звонку живёт 60 секунд. Запечатанное офлайн-сообщение — не больше 72 часов. Регистрация устройства истекает через 30 дней без продления.
- Он видит, кто кому звонит, пока приглашение или сообщение ждёт. Приглашение к звонку или офлайн-сообщение должно назвать ключ, для которого оно, и ключ, от которого оно, поэтому сервер видит оба. Никакой записи об этой паре он не хранит после того, как приглашение или сообщение исчезло: приглашение забывается через 60 секунд, а сообщение самое позднее через 72 часа. Скрыть ещё и отправителя (запечатанный отправитель) у нас в планах. Наши серверы стоят за Cloudflare, который видит те же сведения, но никогда не видит содержимого.
Когда звонок не может пройти напрямую, обычно потому, что обе сети этого не дают (так бывает у некоторых мобильных операторов), зашифрованные пакеты пересылает ретранслятор: наш собственный по UDP, затем по TCP, затем ретрансляторы Cloudflare. Ретранслятор только передаёт данные дальше. Ключа у него нет, и получить его он не может. IP-адреса обоих устройств он при этом видит. Сегодня нет настройки, которая отправляла бы каждый звонок через ретранслятор, а при любом звонке, через ретранслятор или нет, каждое устройство узнаёт IP-адрес другого.
Звонки в одной сети Wi-Fi
Два устройства в одной сети Wi-Fi или на одной точке доступа могут найти друг друга и провести полноценный зашифрованный разговор без подключения к интернету и без сервера. Сегодня это работает на Android после того, как на вызываемом телефоне нажали Готов принимать звонки, на iPhone, пока на нём открыт Clavenzo, и на компьютере всё время, пока Clavenzo запущен; iPhone может попросить разрешение на доступ к локальной сети. Сообщения и файлы передаются так же, в зашифрованном виде, пока приложение открыто на обоих устройствах.
Это не запасной режим с урезанной безопасностью. Это то же шифрование и те же слова безопасности, только шаг встречи заменён локальным обнаружением. Пригодится в самолёте, в здании без связи, на объекте с частной сетью и везде, где интернет ненадёжен или нежелателен.
Когда что-то ломается
Clavenzo спроектирован вокруг трудного вопроса: что продолжает работать, когда всё идёт не так? Буря выводит из строя дата-центр. Страна душит соединения. Провайдер исчезает. Вышки отказывают, и остаётся только локальная сеть. На каждый из этих случаев ниже есть ответ.
- Совсем без интернета. Телефоны в одной сети Wi-Fi или на одной точке доступа могут звонить друг другу напрямую, с ограничениями, описанными выше. Без сервера, без чего-либо за пределами комнаты.
- Серверы маленькие, и их несколько. Они только знакомят два телефона и хранят запечатанные сообщения. Звук и видео через них не идут, если не нужен ретранслятор, поэтому весь сервис работает на горстке маленьких машин у разных провайдеров в разных местах.
- Ни один из них не незаменим. Ваш телефон регистрируется на каждом сервере и забирает почту с каждого. Если один падает, остальные продолжают работу, а звонок принимается через тот сервер, который его доставил.
- Список серверов подписан. Телефоны получают его с самих серверов и проверяют ключом, который никогда не касается сервера. Новые серверы можно добавлять без обновления приложения, а старый список никогда не удастся подсунуть повторно, чтобы отправить телефоны туда, куда им не надо.
- Без DNS — не беда. В списке есть прямые сетевые адреса с закреплёнными сертификатами, так что телефоны доберутся до сервера, даже если сервер имён лежит или лжёт или отказала сеть доставки контента, не доверяя никакому удостоверяющему центру.
- Два ретранслятора, одна лестница. Когда две сети не пускают прямой путь, зашифрованный звонок несёт ретранслятор: наш собственный по UDP, затем по TCP, затем ретрансляторы Cloudflare. Если любой из них откажет, вы потеряете ступеньку, а не звонок.
- Тонкие и ненадёжные каналы. Речи нужно 13,2 кбит/с. Буфер джиттера измеряет сеть и подстраивается под неё, потерянные пакеты маскируются, а не щёлкают, а большие файлы сами встают на паузу и продолжаются.
- Мешающие сети. Встроены прокси SOCKS5 и HTTP CONNECT — для сетей, которые требуют прокси, или где местный резолвер заблокирован или подделан.
Сообщения, фото, файлы и голосовые
Переписка построена на том же шифровании. Текст, фотографии, файлы и голосовые сообщения зашифрованы для получателя, а разговор хранится в приватном хранилище приложения на вашем телефоне. Это хранилище защищено собственным шифрованием и экраном блокировки телефона и исключено из резервных копий Google и iCloud. На компьютере переписки хранятся в собственной папке приложения в вашей учётной записи.
Сообщение для человека с выключенным телефоном запечатывается его ключом и остаётся в службе встреч, которая держит его не дольше 72 часов, не имея возможности прочитать ни байта.
Файлы больше 1 МБ — намеренное исключение: они идут только от телефона к телефону и никогда через сервер. Если прямого пути пока нет, передача ждёт и возобновляется сама, а не отправляет ваш большой файл тихо через чужую машину.
Есть также исчезающие сообщения — отдельно для каждого разговора, с отсчётом от момента отправки у вас и от момента прочтения у собеседника; отчёты о прочтении, которые отключаются сразу в обе стороны; и состояние запроса на переписку, чтобы тот, кого нет у вас в контактах, не мог узнать, дошло ли его сообщение и прочитано ли оно, пока вы его не примете.
Что можно включить
- Блокировка приложения — экран блокировки телефона (PIN, графический ключ, отпечаток пальца или лицо) при возвращении в Clavenzo, а в Windows — Windows Hello. Звонки по-прежнему звонят; уведомления перестают показывать текст сообщений. В Linux её пока нет.
- Защита экрана. На Android блокирует снимки и запись экрана приложения и скрывает его в списке недавних приложений. На iPhone, где ни одно приложение не может запретить снимок экрана, скрывает приложение в переключателе приложений. В Windows не пускает окно в снимки экрана, записи экрана и демонстрацию экрана; в Linux это обеспечить нельзя. Коды резервной копии и переноса защищены всегда, что бы ни стояло в этой настройке.
- Клавиатура инкогнито (только Android). Просит клавиатуру не запоминать то, что вы печатаете. Это именно просьба, и некоторые клавиатуры её игнорируют, поэтому приложение так и пишет. На iPhone у приложений нет возможности о таком попросить.
- Поддержка прокси — SOCKS5 или HTTP CONNECT, для сетей, где это обязательно, или где локальный резолвер заблокирован либо врёт.
- Беззвучные звонки от несохранённых — они не звонят. Они всё равно появляются как пропущенные, и на них можно перезвонить.
Переезд на новый телефон
Два отдельных экспорта, намеренно разделённых, потому что они несут разное.
Зашифрованная резервная копия хранит переписку, фотографии, историю звонков и контакты одним файлом, который вы кладёте куда хотите. Он открывается только кодом, показанным один раз при экспорте и нигде не сохранённым. Импорт добавляет недостающее и никогда не перезаписывает уже имеющееся.
Экспорт личности переносит ключ, который и есть ваш адрес. Он запечатан собственным одноразовым кодом переноса, стоит за экраном блокировки телефона и является единственным способом, которым этот ключ вообще покидает устройство. Импорт заставляет новый телефон отвечать под этой личностью.
Где эта конструкция заканчивается
У любой конструкции есть пределы. Вот наши.
- Кто с кем говорит. Приглашение к звонку или офлайн-сообщение называет два адреса, между которыми оно идёт, поэтому сервер, а также стоящий перед ним Cloudflare, видят эту пару, пока оно хранится. Кроме того, начальное рукопожатие прямого звонка несёт оба ключа личности открытым текстом, так что наблюдатель в этой сети может понять, какие две личности разговаривают. Ни то ни другое не раскрывает ни слова из сказанного. Это метаданные, и оба пункта в списке на исправление.
- Время и метаданные. Сервер неизбежно видит, когда ваше устройство отмечается. Ритм пакетов во время звонка может выдать, когда кто-то говорит, даже если сказанное никогда не покидает шифрования.
- Ваш IP-адрес. При любом звонке, даже если в итоге он пойдёт через ретранслятор, приложение собеседника узнаёт ваш IP-адрес, потому что два устройства обмениваются сетевыми адресами, чтобы найти прямой путь. По нему можно примерно понять, где вы находитесь. Ретранслятор тоже видит оба IP-адреса.
- Ваше устройство — слабое место. У кого в руках ваш разблокированный телефон, у того и ваши сообщения. Вредоносная программа на телефоне читает то, что вы печатаете, ещё до всякого шифрования. Это верно для всех когда-либо написанных мессенджеров.
- Независимого аудита не было. Сделано аккуратно и тщательно протестировано. Это не одно и то же, и мы не будем делать вид, что одно.
Если в вашей модели угроз есть противник, способный наблюдать целую сеть, поймите эти пределы, используйте поддержку прокси и не ставьте ни на один-единственный инструмент — включая этот — ничего, что не можете позволить себе потерять.