Сквозное шифрование: протокол Signal
Как переписка остаётся секретной даже от сервера мессенджера — и даже если один ключ утёк.
Сквозное шифрование (E2EE) — модель, при которой сообщение шифруется на устройстве отправителя и расшифровывается только на устройстве получателя; промежуточный сервер видит лишь нечитаемый шифротекст.
Протокол Signal лежит в основе сквозного шифрования Signal, WhatsApp и многих других мессенджеров. Его задача — обеспечить не просто секретность, а две сильные гарантии: forward secrecy (утечка сегодняшнего ключа не раскроет вчерашние сообщения) и post-compromise security (после компрометации система сама «лечится» и снова становится безопасной). Достигается это связкой двух механизмов: X3DH для установления первого секрета и Double Ratchet для постоянного обновления ключей.
Зачем это знать защитнику
Понимание E2EE объясняет, что именно гарантирует и чего не гарантирует «защищённый мессенджер». E2EE прячет содержимое от сервера, но не прячет метаданные (кто, когда, как часто) и бессилен, если скомпрометировано само устройство — там сообщения уже расшифрованы. Это знание помогает корректно оценивать риски и не переоценивать защиту.
X3DH: начало диалога
Чтобы зашифровать первое сообщение, нужен общий секрет. Но в мессенджере собеседник может быть офлайн. X3DH (Extended Triple Diffie-Hellman) решает это так: каждый пользователь заранее выкладывает на сервер набор публичных ключей — долговременный ключ личности, подписанный «предключ» и пачку одноразовых предключей. Отправитель забирает эти публичные ключи и выполняет несколько обменов Диффи-Хеллмана сразу, комбинируя их в один общий секрет. Получателю даже не надо быть онлайн — он восстановит тот же секрет, когда зайдёт.
У получателя на сервере лежат публичные:
IK — Identity Key (долговременный)
SPK — Signed PreKey (обновляется периодически, подписан IK)
OPK — One-Time PreKey (одноразовый)
Отправитель считает несколько DH и смешивает их в общий секрет:
DH1 = DH(своя IK, чужой SPK)
DH2 = DH(своя эфемерная, чужой IK)
DH3 = DH(своя эфемерная, чужой SPK)
DH4 = DH(своя эфемерная, чужой OPK)
секрет = KDF(DH1 || DH2 || DH3 || DH4)
Несколько обменов нужны, чтобы связать секрет одновременно с личностью обеих сторон и с одноразовыми значениями — это даёт и аутентификацию, и forward secrecy с самого первого сообщения.
Double Ratchet: ключ на каждое сообщение
Дальше начинается «двойной храповик». Идея: ключ обновляется так часто, что у каждого сообщения он свой, и старые ключи восстановить нельзя. Храповик двойной, потому что крутится по двум осям.
Симметричный храповик
Есть «ключ цепочки». Из него функция KDF выводит ключ конкретного сообщения, а затем продвигает сам ключ цепочки вперёд. Назад процесс необратим: зная сегодняшний ключ цепочки, нельзя вычислить вчерашний. Покажем этот шаг на стандартной библиотеке Python:
import hashlib, hmac
def kdf(chain_key, label):
return hmac.new(chain_key, label, hashlib.sha256).digest()
ck = b'initial-chain-key-32-bytes-long!' # ключ цепочки (32 байта)
for i in range(3):
mk = kdf(ck, b'\x01') # ключ сообщения
ck = kdf(ck, b'\x02') # продвигаем ключ цепочки
print('сообщение', i, 'ключ:', mk.hex()[:16], '...')
Вывод:
сообщение 0 ключ: 7cb4c4759efe0980 ... сообщение 1 ключ: db9f6387687cf923 ... сообщение 2 ключ: 40d302e13a9bb151 ...
Каждое сообщение получило уникальный ключ; ключ предыдущего по новому состоянию не вычислить.
DH-храповик
Симметричный храповик идёт только вперёд, поэтому если злоумышленник украл текущий ключ цепочки, он сможет читать будущие сообщения. Чтобы «вылечиться», в дело вступает вторая ось: при каждом ответе стороны подмешивают новый эфемерный обмен Диффи-Хеллмана и пересоздают корневой ключ. После такого «поворота» украденного состояния уже недостаточно — это и есть post-compromise security.
Forward secrecy и post-compromise security
Эти два свойства — зеркальные. Forward secrecy смотрит в прошлое: компрометация сейчас не раскрывает старые сообщения, потому что их ключи уже стёрты. Post-compromise security смотрит в будущее: после компрометации, как только пройдёт новый DH-поворот, связь снова становится защищённой. Вместе они означают, что окно ущерба от утечки одного ключа максимально узкое.
Сравним с обычным шифрованием на одном долговременном ключе. Там утечка ключа раскрывает всю переписку — и прошлую, и будущую, — пока ключ не сменят вручную. Double Ratchet же меняет ключи автоматически на каждом сообщении и на каждом ответе, поэтому даже разовый доступ к памяти устройства даёт атакующему в худшем случае узкое окно, а не весь архив. Именно поэтому современные мессенджеры выбирают эту схему, а не «зашифровать всё одним ключом канала».
Сравнение с шифрованием «точка-точка»
Важно не путать E2EE со «шифрованием транспорта», как в TLS. TLS защищает участок «клиент — сервер»: на сервере мессенджера трафик расшифровывается, и теоретически сервер видит содержимое. E2EE же шифрует «отправитель — получатель», и сервер выступает лишь почтальоном, передающим запечатанные конверты. Поэтому претензия «мы используем TLS» не равна «у нас сквозное шифрование» — это разные уровни защиты, и защитнику важно различать их при оценке мессенджера.
Как это работает под капотом
Состояние сессии — это несколько ключей: корневой ключ, ключ цепочки отправки и ключ цепочки приёма. Корневой ключ обновляется DH-храповиком, ключи цепочек — симметричным. Каждое сообщение несёт в заголовке новый публичный DH-ключ отправителя, чтобы собеседник мог провернуть свой храповик и синхронизироваться. Сообщения, пришедшие не по порядку, обрабатываются за счёт сохранения «пропущенных» ключей до их использования.
Как защититься
- Сверяйте отпечатки ключей. E2EE защищает от сервера, но не от подмены при первом контакте — сравните «код безопасности»/QR с собеседником по другому каналу.
- Помните про метаданные. Содержимое скрыто, но факт, время и участники переписки — нет; для их защиты нужны отдельные меры.
- Берегите устройство. На конечной точке сообщения уже расшифрованы — блокировка экрана, шифрование диска и контроль вредоносного ПО критичны.
- Реагируйте на смену ключей. Уведомление «ключ безопасности изменился» — повод перепроверить, не подменён ли собеседник, а не просто нажать «ок».
Итоги
- X3DH устанавливает общий секрет даже с офлайн-собеседником, комбинируя несколько обменов Диффи-Хеллмана.
- Double Ratchet выдаёт уникальный ключ на каждое сообщение: симметричный храповик — forward secrecy, DH-храповик — post-compromise security.
- E2EE прячет содержимое от сервера, но не метаданные и не данные на скомпрометированном устройстве.
- Сверка отпечатков ключей — обязательный шаг защиты от подмены при первом контакте.