Этот перевод был создан с помощью машинного обучения и может быть не на 100% точным. Просмотреть английскую версию

ECIES-X25519-AEAD-Ratchet

Proposal 144
Закрыто
Author zzz, chisana, orignal
Created 2018-11-22
Last Updated 2025-03-05
Target Version 0.9.46
Implemented In 0.9.46

Примечание

Развертывание и тестирование сети в процессе. Возможны незначительные правки. См. SPEC для официальной спецификации.

Следующие функции не реализованы по состоянию на 0.9.46:

  • Блоки MessageNumbers, Options и Termination
  • Ответы на уровне протокола
  • Нулевой статический ключ
  • Мультикаст

Обзор

Это предложение по первому новому типу сквозного шифрования с момента начала I2P, заменяющему ElGamal/AES+SessionTags Elg-AES .

Оно опирается на предыдущую работу следующим образом:

Цель — поддержка нового шифрования для сквозной, коммуникации от пункта назначения до пункта назначения.

Дизайн будет использовать рукопожатие Noise и фазу передачи данных с использованием двойного зажима Signal.

Все ссылки на Signal и Noise в этом предложении приведены только для справки. Знание протоколов Signal и Noise не требуется для понимания или реализации этого предложения.

Текущее использование ElGamal

В качестве обзора, 256-байтные открытые ключи ElGamal могут находиться в следующих структурах данных. См. спецификацию общих структур.

  • В идентификаторе маршрутизатора Это ключ шифрования маршрутизатора.

  • В пункте назначения Открытый ключ пункта назначения использовался для старого шифрования i2cp-to-i2cp, которое было отключено в версии 0.6, в настоящее время не используется, за исключением IV для шифрования LeaseSet, что устарело. Вместо этого используется открытый ключ в LeaseSet.

  • В LeaseSet Это ключ шифрования пункта назначения.

  • В LS2 Это ключ шифрования пункта назначения.

Типы шифрования в сертификатах ключей

В качестве обзора, мы добавили поддержку типов шифрования, когда добавили поддержку типов подписей. Поле типа шифрования всегда равно нулю, как в пунктах назначения, так и в RouterIdentities. Будет ли оно когда-либо изменено — TBD. См. спецификацию общих структур Common Structures .

Использование асимметричной криптографии

В качестве обзора, мы используем ElGamal для:

  1. Сообщений построения туннеля (ключ находится в RouterIdentity) Замена не рассматривается в этом предложении. См. предложение 152 Proposal 152 .

  2. Шифрования маршрутизатор-маршрутизатор для netdb и других сообщений I2NP (ключ находится в RouterIdentity) Зависит от этого предложения. Требуется предложение для 1), или помещение ключа в опции RI.

  3. Сквозного шифрования клиента ElGamal+AES/SessionTag (ключ находится в LeaseSet, ключ пункта назначения не используется) Замена РАССМАТРИВАЕТСЯ в этом предложении.

  4. Эфемерный DH для NTCP1 и SSU Замена не рассматривается в этом предложении. См. предложение 111 для NTCP2. Нет текущего предложения для SSU2.

Цели

  • Обратная совместимость
  • Требует и основывается на LS2 (предложение 123)
  • Использование новой криптографии или примитивов, добавленных для NTCP2 (предложение 111)
  • Не требует новых криптографических примитивов для поддержки
  • Поддержание развязки криптографии и подписи; поддержка всех текущих и будущих версий
  • Включение новой криптографии для пунктов назначения
  • Включение новой криптографии для маршрутизаторов, но только для сообщений чеснока — построение туннеля будет отдельным предложением
  • Не нарушать ничего, что зависит от 32-байтных бинарных хэшей пунктов назначения, например, bittorrent
  • Поддержка доставки сообщений 0-RTT с использованием эфемерно-статического DH
  • Не требовать буферизации / очередей сообщений на этом уровне протокола; продолжать поддерживать неограниченную доставку сообщений в обоих направлениях без ожидания ответа
  • Обновление до эфемерно-эфемерного DH после 1 RTT
  • Поддержка обработки сообщений в неправильном порядке
  • Поддержание 256-битной безопасности
  • Добавление сквозной секретности
  • Добавление аутентификации (AEAD)
  • Гораздо более эффективное использование CPU по сравнению с ElGamal
  • Не полагаться на Java jbigi для эффективности DH
  • Минимизация операций DH
  • Гораздо более эффективное использование полосы пропускания по сравнению с ElGamal (514-байтный блок ElGamal)
  • Поддержка одновременного использования новой и старой криптографии в одном туннеле, если необходимо
  • Получатель может эффективно различать новую и старую криптографию, приходящую по одному туннелю
  • Другие не могут различать новую и старую или будущую криптографию
  • Устранение классификации по длине новой и существующей сессии (поддержка заполнения)
  • Не требуются новые сообщения I2NP
  • Замена контрольной суммы SHA-256 в полезной нагрузке AES на AEAD
  • Поддержка привязки сеансов передачи и приема, чтобы подтверждения могли происходить внутри протокола, а не исключительно вне полосы. Это также позволит ответам иметь сквозную секретность немедленно.
  • Включение сквозного шифрования определенных сообщений (хранилища RouterInfo), которые мы в настоящее время не используем из-за накладных расходов CPU.
  • Не изменять сообщение I2NP Garlic Message или формат инструкций по доставке Garlic Message.
  • Устранение неиспользуемых или избыточных полей в форматах Garlic Clove Set и Clove.

Устранение нескольких проблем с тегами сессий, включая:

  • Невозможность использовать AES до первого ответа
  • Ненадежность и задержки при предполагаемой доставке тегов
  • Неэффективность по полосе пропускания, особенно при первой доставке
  • Огромная неэффективность по памяти для хранения тегов
  • Огромные накладные расходы по полосе пропускания для доставки тегов
  • Высокая сложность, трудность реализации
  • Сложность настройки для различных вариантов использования (потоковая передача против датаграмм, сервер против клиента, высокая против низкой полосы пропускания)
  • Уязвимости к исчерпанию памяти из-за доставки тегов

Нецели / Вне сферы действия

  • Изменения формата LS2 (предложение 123 выполнено)
  • Новый алгоритм вращения DHT или генерация общего случайного числа
  • Новое шифрование для построения туннеля. См. предложение 152 Proposal 152 .
  • Новое шифрование для шифрования на уровне туннеля. См. предложение 153 Proposal 153 .
  • Методы шифрования, передачи и приема сообщений I2NP DLM / DSM / DSRM. Не меняются.
  • Не поддерживается связь LS1-to-LS2 или ElGamal/AES-to-this-proposal. Это предложение является двунаправленным протоколом. Пункты назначения могут обеспечивать обратную совместимость, публикуя два leaseset с использованием одних и тех же туннелей, или помещая оба типа шифрования в LS2.
  • Изменения модели угроз
  • Детали реализации здесь не обсуждаются и остаются на усмотрение каждого проекта.
  • (Оптимистично) Добавление расширений или хуков для поддержки мультикаста

Обоснование

ElGamal/AES+SessionTag был нашим единственным сквозным протоколом около 15 лет, по сути, без изменений протокола. Сейчас существуют криптографические примитивы, которые быстрее. Нам нужно усилить безопасность протокола. Мы также разработали эвристические стратегии и обходные пути для минимизации накладных расходов по памяти и полосе пропускания протокола, но эти стратегии хрупки, трудны для настройки и делают протокол еще более склонным к сбоям, вызывая обрыв сессии.

Примерно за тот же период спецификация ElGamal/AES+SessionTag и связанная документация описывали, насколько дорого по полосе пропускания доставлять теги сессий, и предлагали заменить доставку тегов сессий «синхронизированным PRNG». Синхронизированный PRNG детерминированно генерирует одни и те же теги на обоих концах, полученные из общего семени. Синхронизированный PRNG также может называться «зажимом». Это предложение (наконец) определяет механизм зажима и устраняет доставку тегов.

Используя зажим (синхронизированный PRNG) для генерации тегов сессий, мы устраняем накладные расходы на отправку тегов сессий в сообщении New Session и последующих сообщениях при необходимости. Для типичного набора тегов из 32 тегов это 1 КБ. Это также устраняет хранение тегов сессий на стороне отправителя, тем самым сокращая требования к хранению вдвое.

Полное двунаправленное рукопожатие, аналогичное шаблону Noise IK, необходимо для предотвращения атак «Компрометация ключа и имитация» (KCI). См. таблицу «Свойства безопасности полезной нагрузки» в NOISE . Дополнительную информацию о KCI см. в статье https://www.usenix.org/system/files/conference/woot15/woot15-paper-hlauschek.pdf

Модель угроз

Модель угроз несколько отличается от NTCP2 (предложение 111). Узлы-посредники — это OBEP и IBGW, и предполагается, что они имеют полный доступ к текущей или исторической глобальной NetDB, сотрудничая с floodfill.

Цель — предотвратить эти MitM от классификации трафика как новые и существующие сообщения сессии, или как новая криптография против старой криптографии.

Подробное предложение

Это предложение определяет новый сквозной протокол для замены ElGamal/AES+SessionTags. Дизайн будет использовать рукопожатие Noise и фазу передачи данных с использованием двойного зажима Signal.

Краткое описание криптографического дизайна

Есть пять частей протокола, которые необходимо переработать:

    1. Форматы контейнеров новых и существующих сессий заменяются новыми форматами.
    1. ElGamal (256-байтные открытые ключи, 128-байтные закрытые ключи) заменяется на ECIES-X25519 (32-байтные открытые и закрытые ключи)
    1. AES заменяется на AEAD_ChaCha20_Poly1305 (сокращенно ChaChaPoly ниже)
    1. SessionTags заменяются зажимами, что по сути является криптографическим синхронизированным PRNG.
    1. Полезная нагрузка AES, как определено в спецификации ElGamal/AES+SessionTags, заменяется форматом блока, аналогичным формату в NTCP2.

Каждое из пяти изменений имеет свой собственный раздел ниже.

Новые криптографические примитивы для I2P

Существующим реализациям маршрутизаторов I2P потребуются реализации следующих стандартных криптографических примитивов, которые не требуются для текущих протоколов I2P:

  • ECIES (но это по сути X25519)
  • Elligator2

Существующим реализациям маршрутизаторов I2P, которые еще не реализовали NTCP2 (Proposal 111 ), также потребуются реализации для:

  • Генерации ключей X25519 и DH
  • AEAD_ChaCha20_Poly1305 (сокращенно ChaChaPoly ниже)
  • HKDF

Тип криптографии

Тип криптографии (используется в LS2) — 4. Это указывает на 32-байтный открытый ключ X25519 в формате little-endian, и сквозной протокол, указанный здесь.

Тип криптографии 0 — ElGamal. Типы криптографии 1-3 зарезервированы для ECIES-ECDH-AES-SessionTag, см. предложение 145 Proposal 145 .

Фреймворк протокола Noise

Это предложение предоставляет требования на основе фреймворка протокола Noise NOISE (Revision 34, 2018-07-11). Noise имеет схожие свойства с протоколом Station-To-Station STS , который является основой для протокола SSU . В терминологии Noise, Алиса — инициатор, а Боб — ответчик.

Это предложение основано на протоколе Noise Noise_IK_25519_ChaChaPoly_SHA256. (Фактический идентификатор для начальной функции вывода ключа — “Noise_IKelg2_25519_ChaChaPoly_SHA256”, чтобы указать расширения I2P — см. раздел KDF 1 ниже) Этот протокол Noise использует следующие примитивы:

  • Интерактивный шаблон рукопожатия: IK Алиса немедленно передает свой статический ключ Бобу (I) Алиса уже знает статический ключ Боба (K)

  • Односторонний шаблон рукопожатия: N Алиса не передает свой статический ключ Бобу (N)

  • Функция DH: X25519 X25519 DH с длиной ключа 32 байта, как указано в RFC-7748 .

  • Функция шифрования: ChaChaPoly AEAD_CHACHA20_POLY1305, как указано в RFC-7539 раздел 2.8. 12-байтный nonce, первые 4 байта которого установлены в ноль. Идентично тому, что в NTCP2 .

  • Хэш-функция: SHA256 Стандартный 32-байтный хэш, уже широко используемый в I2P.

Дополнения к фреймворку

Это предложение определяет следующие улучшения для Noise_IK_25519_ChaChaPoly_SHA256. Эти улучшения, как правило, следуют рекомендациям в NOISE раздел 13.

  1. Открытые эфемерные ключи кодируются с помощью Elligator2 .

  2. Ответ предваряется открытым тегом.

  3. Определяется формат полезной нагрузки для сообщений 1, 2 и фазы передачи данных. Конечно, это не определено в Noise.

Все сообщения включают заголовок I2NP Garlic Message. Фаза передачи данных использует шифрование, аналогичное, но несовместимое с фазой передачи данных Noise.

Шаблоны рукопожатия

Рукопожатия используют шаблоны Noise .

Используется следующее буквенное соответствие:

  • e = одноразовый эфемерный ключ
  • s = статический ключ
  • p = полезная нагрузка сообщения

Одноразовые и неограниченные сессии аналогичны шаблону Noise N.


<- s
  ...
  e es p ->

Ограниченные сессии аналогичны шаблону Noise IK.


<- s
  ...
  e es s ss p ->
  <- tag e ee se
  <- p
  p ->

Сессии

Текущий протокол ElGamal/AES+SessionTag односторонний. На этом уровне получатель не знает, откуда пришло сообщение. Исходящие и входящие сессии не связаны. Подтверждения находятся вне полосы с использованием DeliveryStatusMessage (обернутого в GarlicMessage) в clove.

Существует значительная неэффективность в одностороннем протоколе. Любой ответ также должен использовать дорогостоящее сообщение ‘New Session’. Это вызывает более высокое использование полосы пропускания, CPU и памяти.

Также есть уязвимости безопасности в одностороннем протоколе. Все сессии основаны на эфемерно-статическом DH. Без обратного пути Боб не может «зажать» свой статический ключ в эфемерный ключ. Не зная, откуда пришло сообщение, невозможно использовать полученный эфемерный ключ для исходящих сообщений, поэтому начальный ответ также использует эфемерно-статический DH.

Для этого предложения мы определяем два механизма создания двунаправленного протокола — «сопряжение» и «привязка». Эти механизмы обеспечивают повышенную эффективность и безопасность.

Контекст сессии

Как и в ElGamal/AES+SessionTags, все входящие и исходящие сессии должны находиться в заданном контексте, либо в контексте маршрутизатора, либо в контексте для конкретного локального пункта назначения. В Java I2P этот контекст называется Session Key Manager.

Сессии не должны разделяться между контекстами, так как это позволит корреляцию между различными локальными пунктами назначения, или между локальным пунктом назначения и маршрутизатором.

Когда данный пункт назначения поддерживает как ElGamal/AES+SessionTags, так и это предложение, оба типа сессий могут разделять контекст. См. раздел 1c) ниже.

Сопряжение входящих и исходящих сессий

Когда исходящая сессия создается у инициатора (Алисы), создается новая входящая сессия и сопрягается с исходящей сессией, если только ответ не ожидается (например, сырые датаграммы).

Новая входящая сессия всегда сопрягается с новой исходящей сессией, если только ответ не запрашивается (например, сырые датаграммы).

Если ответ запрашивается и привязан к удаленному пункту назначения или маршрутизатору, эта новая исходящая сессия привязывается к этому пункту назначения или маршрутизатору, и заменяет любую предыдущую исходящую сессию к этому пункту назначения или маршрутизатору.

Сопряжение входящих и исходящих сессий обеспечивает двунаправленный протокол с возможностью зажима ключей DH.

Привязка сессий и пунктов назначения

Существует только одна исходящая сессия к данному пункту назначения или маршрутизатору. Может быть несколько текущих входящих сессий от данного пункта назначения или маршрутизатора. Как правило, когда создается новая входящая сессия, и трафик получается на этой сессии (что служит подтверждением), другие будут помечены для быстрого истечения, в течение минуты или около того. Проверяется значение предыдущих отправленных сообщений (PN), и если нет не полученных сообщений (в пределах размера окна) в предыдущей входящей сессии, предыдущая сессия может быть немедленно удалена.

Когда исходящая сессия создается у инициатора (Алисы), она привязывается к удаленному пункту назначения (Бобу), и любая сопряженная входящая сессия также будет привязана к удаленному пункту назначения. По мере того как сессии зажимаются, они продолжают быть привязанными к удаленному пункту назначения.

Когда входящая сессия создается у получателя (Боба), она может быть привязана к удаленному пункту назначения (Алисе), по желанию Алисы. Если Алиса включает информацию о привязке (ее статический ключ) в сообщение New Session, сессия будет привязана к этому пункту назначения, и будет создана исходящая сессия, привязанная к тому же пункту назначения. По мере того как сессии зажимаются, они продолжают быть привязанными к удаленному пункту назначения.

Преимущества привязки и сопряжения

Для обычного случая потоковой передачи мы ожидаем, что Алиса и Боб будут использовать протокол следующим образом:

  • Алиса сопрягает свою новую исходящую сессию с новой входящей сессией, обе привязаны к удаленному пункту назначения (Бобу).
  • Алиса включает информацию о привязке и подпись, а также запрос ответа, в сообщение New Session, отправленное Бобу.
  • Боб сопрягает свою новую входящую сессию с новой исходящей сессией, обе привязаны к удаленному пункту назначения (Алисе).
  • Боб отправляет ответ (подтверждение) Алисе в сопряженной сессии, с зажимом к новому ключу DH.
  • Алиса зажимает к новой исходящей сессии с новым ключом Боба, сопряженной к существующей входящей сессии.

Привязывая входящую сессию к удаленному пункту назначения и сопрягая входящую сессию с исходящей сессией, привязанной к тому же пункту назначения, мы достигаем двух основных преимуществ:

  1. Начальный ответ от Боба к Алисе использует эфемерно-эфемерный DH

  2. После того как Алиса получает ответ Боба и зажимает, все последующие сообщения от Алисы к Бобу используют эфемерно-эфемерный DH.

Подтверждения сообщений

В ElGamal/AES+SessionTags, когда LeaseSet упаковывается как чесночный clove, или теги доставляются, отправляющий маршрутизатор запрашивает подтверждение. Это отдельный чесночный clove, содержащий сообщение DeliveryStatus Message. Для дополнительной безопасности сообщение DeliveryStatus Message обернуто в Garlic Message. Этот механизм находится вне полосы с точки зрения протокола.

В новом протоколе, поскольку входящие и исходящие сессии сопряжены, мы можем иметь подтверждения в полосе. Отдельный clove не требуется.

Явное подтверждение — это просто сообщение Existing Session без блока I2NP. Однако в большинстве случаев явное подтверждение можно избежать, так как есть обратный трафик. Может быть желательно для реализаций подождать короткое время (возможно, сотню мс) перед отправкой явного подтверждения, чтобы дать время потоковому или прикладному уровню ответить.

Реализациям также необходимо отложить отправку любого подтверждения до тех пор, пока блок I2NP не будет обработан, так как Garlic Message может содержать сообщение Database Store Message с lease set. Актуальный lease set будет необходим для маршрутизации подтверждения, и удаленный пункт назначения (содержащийся в lease set) будет необходим для проверки статического ключа привязки.

Тайм-ауты сессий

Исходящие сессии всегда должны истекать до входящих сессий. Когда исходящая сессия истекает и создается новая, новая сопряженная входящая сессия также будет создана. Если существовала старая входящая сессия, ей будет разрешено истечь.

Мультикаст

TBD

Определения

Мы определяем следующие функции, соответствующие используемым криптографическим строительным блокам.

ZEROLEN нулевой байтовый массив

CSRNG(n) n-байтный вывод из криптографически безопасного генератора случайных чисел.

H(p, d) хэш-функция SHA-256, которая принимает строку персонализации p и данные d, и производит вывод длиной 32 байта. Как определено в NOISE . || ниже означает объединение.

Используйте SHA-256 следующим образом::

    H(p, d) := SHA-256(p || d)

MixHash(d) хэш-функция SHA-256, которая принимает предыдущий хэш h и новые данные d, и производит вывод длиной 32 байта. || ниже означает объединение.

Используйте SHA-256 следующим образом::

    MixHash(d) := h = SHA-256(h || d)

STREAM ChaCha20/Poly1305 AEAD, как указано в RFC-7539 . S_KEY_LEN = 32 и S_IV_LEN = 12.

ENCRYPT(k, n, plaintext, ad)
    Шифрует открытый текст с использованием ключа шифрования k и nonce n, который ДОЛЖЕН быть уникальным для
    ключа k.
    Сопутствующие данные ad являются необязательными.
    Возвращает шифротекст, размер которого равен размеру открытого текста + 16 байт для HMAC.

    Весь шифротекст должен быть неотличим от случайного, если ключ секретен.

DECRYPT(k, n, ciphertext, ad)
    Расшифровывает шифротекст с использованием ключа шифрования k и nonce n.
    Сопутствующие данные ad являются необязательными.
    Возвращает открытый текст.

DH Система агрегирования открытых ключей X25519. Закрытые ключи длиной 32 байта, открытые ключи длиной 32 байта, производит выходные данные длиной 32 байта. Имеет следующие функции:

GENERATE_PRIVATE()
    Генерирует новый закрытый ключ.

DERIVE_PUBLIC(privkey)
    Возвращает открытый ключ, соответствующий данному закрытому ключу.

GENERATE_PRIVATE_ELG2()
    Генерирует новый закрытый ключ, который отображается на открытый ключ, подходящий для кодирования Elligator2.
    Обратите внимание, что половина случайно сгенерированных закрытых ключей не будет подходящей и должна быть отброшена.

ENCODE_ELG2(pubkey)
    Возвращает открытый ключ, закодированный с помощью Elligator2, соответствующий данному открытому ключу (обратное отображение).
    Закодированные ключи — little endian.
    Закодированный ключ должен быть 256 бит, неотличимых от случайных данных.
    См. раздел Elligator2 ниже для спецификации.

DECODE_ELG2(pubkey)
    Возвращает открытый ключ, соответствующий данному закодированному с помощью Elligator2 открытому ключу.
    См. раздел Elligator2 ниже для спецификации.

DH(privkey, pubkey)
    Генерирует общий секрет из данных закрытого и открытого ключей.

HKDF(salt, ikm, info, n) Криптографическая функция вывода ключа, которая принимает некоторый входной ключевой материал ikm (который должен иметь хорошую энтропию, но не обязательно должен быть равномерно случайной строкой), соль длиной 32 байта и контекстно-зависимое значение ‘info’, и производит выходные данные длиной n байт, подходящие для использования в качестве ключевого материала.

Используйте HKDF, как указано в [RFC-5869](https://tools.ietf.org/html/rfc5869), используя хэш-функцию HMAC SHA-256,
как указано в [RFC-2104](https://tools.ietf.org/html/rfc2104). Это означает, что SALT_LEN максимум 32 байта.

MixKey(d) Используйте HKDF() с предыдущим chainKey и новыми данными d, и установите новый chainKey и k. Как определено в NOISE .

Используйте HKDF следующим образом::

    MixKey(d) := output = HKDF(chainKey, d, "", 64)
                 chainKey = output[0:31]
                 k = output[32:63]

1) Формат сообщения

Обзор текущего формата сообщения

Сообщение Garlic Message, как указано в I2NP , выглядит следующим образом. Поскольку цель дизайна — чтобы промежуточные узлы не могли различать новую и старую криптографию, этот формат не может измениться, даже несмотря на то, что поле длины избыточно. Формат показан с полным 16-байтным заголовком, хотя фактический заголовок может быть в другом формате, в зависимости от используемого транспорта.

После расшифровки данные содержат серию Garlic Cloves и дополнительных данных, также известных как Clove Set.

См. I2NP для деталей и полной спецификации.


+----+----+----+----+----+----+----+----+
  |type|      msg_id       |  expiration
  +----+----+----+----+----+----+----+----+
                           |  size   |chks|
  +----+----+----+----+----+----+----+----+
  |      length       |                   |
  +----+----+----+----+                   +
  |          encrypted data               |
  ~                                       ~
  ~                                       ~
  |                                       |
  +----+----+----+----+----+----+----+----+

Обзор формата зашифрованных данных

Текущий формат сообщения, используемый более 15 лет, — ElGamal/AES+SessionTags. В ElGamal/AES+SessionTags есть два формата сообщений:

  1. Новая сессия:
  • 514-байтный блок ElGamal
  • Блок AES (минимум 128 байт, кратно 16)
  1. Существующая сессия:
  • 32-байтный тег сессии
  • Блок AES (минимум 128 байт, кратно 16)

Минимальное дополнение до 128 реализовано в Java I2P, но не применяется при приеме.

Эти сообщения инкапсулируются в сообщение I2NP garlic, которое содержит поле длины, поэтому длина известна.

Обратите внимание, что не определено дополнение до длины, не кратной 16, поэтому Новая сессия всегда (mod 16 == 2), а Существующая сессия всегда (mod 16 == 0). Нам нужно это исправить.

Получатель сначала пытается найти первые 32 байта как тег сессии. Если найден, он расшифровывает блок AES. Если не найден, и данные не менее (514+16) байт, он пытается расшифровать блок ElGamal, и если успешно, расшифровывает блок AES.

Новые теги сессий и сравнение с Signal

В Signal Double Ratchet заголовок содержит:

  • DH: Текущий открытый ключ зажима
  • PN: Длина предыдущей цепочки сообщений
  • N: Номер сообщения

«Отправляющие цепочки» Signal примерно эквивалентны нашим наборам тегов. Используя тег сессии, мы можем устранить большую часть этого.

В Новой сессии мы помещаем только открытый ключ в незашифрованный заголовок.

В Существующей сессии мы используем тег сессии для заголовка. Тег сессии ассоциируется с текущим открытым ключом зажима, и номером сообщения.

В обоих случаях Новой и Существующей сессии PN и N находятся в зашифрованном теле.

В Signal вещи постоянно зажимаются. Новый открытый ключ DH требует от получателя зажать и отправить новый открытый ключ обратно, что также служит подтверждением полученного открытого ключа. Это было бы слишком много операций DH для нас. Поэтому мы разделяем подтверждение полученного ключа и передачу нового открытого ключа. Любое сообщение, использующее тег сессии, сгенерированный из нового открытого ключа DH, считается подтверждением. Мы передаем новый открытый ключ только тогда, когда хотим сменить ключ.

Максимальное количество сообщений до того, как DH должен зажать, — 65535.

При доставке ключа сессии мы выводим «Набор тегов» из него, вместо того чтобы также доставлять теги сессий. Набор тегов может содержать до 65536 тегов. Однако получатели должны реализовать стратегию «предварительного просмотра», а не генерировать все возможные теги сразу. Генерируйте не более N тегов после последнего хорошего полученного тега. N может быть максимум 128, но 32 или даже меньше может быть лучшим выбором.

1a) Формат новой сессии

Одноразовый открытый ключ новой сессии (32 байта) Зашифрованные данные и MAC (оставшиеся байты)

Сообщение Новой сессии может содержать или не содержать статический открытый ключ отправителя. Если он включен, обратная сессия привязывается к этому ключу. Статический ключ должен быть включен, если ожидается ответ, т.е. для потоковой передачи и ответных датаграмм. Он не должен включаться для сырых датаграмм.

Сообщение Новой сессии аналогично одностороннему шаблону Noise NOISE «N» (если статический ключ не отправляется), или двунаправленному шаблону «IK» (если статический ключ отправляется).

1b) Формат новой сессии (с привязкой)

Длина 96 + длина полезной нагрузки. Зашифрованный формат:


+----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   Новый эфемерный открытый ключ      |
  |       сессии (32 байта)               |
  +                                       +
  |     Закодирован с помощью Elligator2  |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +         Статический ключ              +
  |       Зашифрованные данные ChaCha20   |
  +            32 байта                   +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +    (MAC) для раздела статического ключа|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +            Раздел полезной нагрузки   +
  |       Зашифрованные данные ChaCha20   |
  ~                                       ~
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +         (MAC) для раздела полезной нагрузки|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+

  Открытый ключ :: 32 байта, little endian, Elligator2, открытый текст

  Зашифрованные данные статического ключа :: 32 байта

  Зашифрованные данные раздела полезной нагрузки :: оставшиеся данные минус 16 байт

  MAC :: Код аутентификации сообщения Poly1305, 16 байт

Эфемерный ключ новой сессии

Эфемерный ключ — 32 байта, закодированный с помощью Elligator2. Этот ключ никогда не повторно используется; новый ключ генерируется с каждым сообщением, включая повторные передачи.

Статический ключ

После расшифровки — статический ключ X25519 Алисы, 32 байта.

Полезная нагрузка

Зашифрованная длина — остаток данных. Расшифрованная длина — на 16 байт меньше зашифрованной длины. Полезная нагрузка должна содержать блок DateTime и обычно будет содержать один или несколько блоков Garlic Clove. См. раздел полезной нагрузки ниже для формата и дополнительных требований.

1c) Формат новой сессии (без привязки)

Если ответ не требуется, статический ключ не отправляется.

Длина 96 + длина полезной нагрузки. Зашифрованный формат:


+----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |   Новый эфемерный открытый ключ      |
  |       сессии (32 байта)               |
  +                                       +
  |     Закодирован с помощью Elligator2  |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +           Раздел флагов               +
  |       Зашифрованные данные ChaCha20   |
  +            32 байта                   +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +         (MAC) для вышеуказанного раздела|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +            Раздел полезной нагрузки   +
  |       Зашифрованные данные ChaCha20   |
  ~                                       ~
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +         (MAC) для раздела полезной нагрузки|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+

  Открытый ключ :: 32 байта, little endian, Elligator2, открытый текст

  Зашифрованные данные раздела флагов :: 32 байта

  Зашифрованные данные раздела полезной нагрузки :: оставшиеся данные минус 16 байт

  MAC :: Код аутентификации сообщения Poly1305, 16 байт

Эфемерный ключ новой сессии

Эфемерный ключ Алисы. Эфемерный ключ — 32 байта, закодированный с помощью Elligator2, little endian. Этот ключ никогда не повторно используется; новый ключ генерируется с каждым сообщением, включая повторные передачи.

Расшифрованные данные раздела флагов

Раздел флагов не содержит ничего. Он всегда 32 байта, потому что должен быть такой же длины, как статический ключ для сообщений Новой сессии с привязкой. Боб определяет, является ли это статическим ключом или разделом флагов, проверяя, являются ли 32 байта нулями.

TODO нужны ли здесь какие-либо флаги?

Полезная нагрузка

Зашифрованная длина — остаток данных. Расшифрованная длина — на 16 байт меньше зашифрованной длины. Полезная нагрузка должна содержать блок DateTime и обычно будет содержать один или несколько блоков Garlic Clove. См. раздел полезной нагрузки ниже для формата и дополнительных требований.

1d) Формат одноразового (без привязки или сессии)

Если ожидается отправка только одного сообщения, настройка сессии или статический ключ не требуются.

Длина 96 + длина полезной нагрузки. Зашифрованный формат:


+----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |       Эфемерный открытый ключ         |
  +             32 байта                  +
  |     Закодирован с помощью Elligator2  |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +           Раздел флагов               +
  |       Зашифрованные данные ChaCha20   |
  +            32 байта                   +
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +         (MAC) для вышеуказанного раздела|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +            Раздел полезной нагрузки   +
  |       Зашифрованные данные ChaCha20   |
  ~                                       ~
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +         (MAC) для раздела полезной нагрузки|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+

  Открытый ключ :: 32 байта, little endian, Elligator2, открытый текст

  Зашифрованные данные раздела флагов :: 32 байта

  Зашифрованные данные раздела полезной нагрузки :: оставшиеся данные минус 16 байт

  MAC :: Код аутентификации сообщения Poly1305, 16 байт

Одноразовый ключ новой сессии

Одноразовый ключ — 32 байта, закодированный с помощью Elligator2, little endian. Этот ключ никогда не повторно используется; новый ключ генерируется с каждым сообщением, включая повторные передачи.

Расшифрованные данные раздела флагов

Раздел флагов не содержит ничего. Он всегда 32 байта, потому что должен быть такой же длины, как статический ключ для сообщений Новой сессии с привязкой. Боб определяет, является ли это статическим ключом или разделом флагов, проверяя, являются ли 32 байта нулями.

TODO нужны ли здесь какие-либо флаги?


+----+----+----+----+----+----+----+----+
  |                                       |
  +                                       +
  |                                       |
  +             Все нули                 +
  |              32 байта                 |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+

  нули:: Все нули, 32 байта.

Полезная нагрузка

Зашифрованная длина — остаток данных. Расшифрованная длина — на 16 байт меньше зашифрованной длины. Полезная нагрузка должна содержать блок DateTime и обычно будет содержать один или несколько блоков Garlic Clove. См. раздел полезной нагрузки ниже для формата и дополнительных требований.

1f) KDF для сообщения Новой сессии

KDF для начального ChainKey

Это стандартный NOISE для IK с измененным именем протокола. Обратите внимание, что мы используем один и тот же инициализатор как для шаблона IK (ограниченные сессии), так и для шаблона N (неограниченные сессии).

Имя протокола изменено по двум причинам. Во-первых, чтобы указать, что эфемерные ключи закодированы с помощью Elligator2, во-вторых, чтобы указать, что MixHash() вызывается перед вторым сообщением для смешивания значения тега.


Это шаблон сообщения «e»:

  // Определите protocol_name.
  Установите protocol_name = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"
   (40 байт, кодировка US-ASCII, без завершающего NULL).

  // Определите Hash h = 32 байта
  h = SHA256(protocol_name);

  Определите ck = 32-байтный цепочечный ключ. Скопируйте данные h в ck.
  Установите chainKey = h

  // MixHash(null prologue)
  h = SHA256(h);

  // до этого момента, все может быть предварительно рассчитано Алисой для всех исходящих соединений

KDF для зашифрованного содержимого раздела флагов/статического ключа


Это шаблон сообщения «e»:

  // Статические ключи X25519 Боба
  // bpk публикуется в leaseset
  bsk = GENERATE_PRIVATE()
  bpk = DERIVE_PUBLIC(bsk)

  // Статический открытый ключ Боба
  // MixHash(bpk)
  // || ниже означает объединение
  h = SHA256(h || bpk);

  // до этого момента, все может быть предварительно рассчитано Бобом для всех входящих соединений

  // Эфемерные ключи X25519 Алисы
  aesk = GENERATE_PRIVATE_ELG2()
  aepk = DERIVE_PUBLIC(aesk)

  // Эфемерный открытый ключ Алисы
  // MixHash(aepk)
  // || ниже означает объединение
  h = SHA256(h || aepk);

  // h используется в качестве сопутствующих данных для AEAD в сообщении Новой сессии
  // Сохраните Hash h для KDF Ответа Новой сессии
  // eapk отправляется в открытом виде в
  // начале сообщения Новой сессии
  elg2_aepk = ENCODE_ELG2(aepk)
  // Как раскодировано Бобом
  aepk = DECODE_ELG2(elg2_aepk)

  Конец шаблона «e».

  Это шаблон сообщения «es»:

  // Noise es
  sharedSecret = DH(aesk, bpk) = DH(bsk, aepk)

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  // Параметры ChaChaPoly для шифрования/расшифровки
  keydata = HKDF(chainKey, sharedSecret, "", 64)
  chainKey = keydata[0:31]

  // Параметры AEAD
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, раздел флагов/статического ключа, ad)

  Конец шаблона «es».

  Это шаблон сообщения «s»:

  // MixHash(ciphertext)
  // Сохраните для KDF раздела полезной нагрузки
  h = SHA256(h || ciphertext)

  // Статические ключи X25519 Алисы
  ask = GENERATE_PRIVATE()
  apk = DERIVE_PUBLIC(ask)

  Конец шаблона «s».

KDF для раздела полезной нагрузки (со статическим ключом Алисы)


Это шаблон сообщения «ss»:

  // Noise ss
  sharedSecret = DH(ask, bpk) = DH(bsk, apk)

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  // Параметры ChaChaPoly для шифрования/расшифровки
  // chainKey из раздела статического ключа
  Установите sharedSecret = результат X25519 DH
  keydata = HKDF(chainKey, sharedSecret, "", 64)
  chainKey = keydata[0:31]

  // Параметры AEAD
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, полезная нагрузка, ad)

  Конец шаблона «ss».

  // MixHash(ciphertext)
  // Сохраните для KDF Ответа Новой сессии
  h = SHA256(h || ciphertext)

KDF для раздела полезной нагрузки (без статического ключа Алисы)

Обратите внимание, что это шаблон Noise «N», но мы используем тот же инициализатор «IK», что и для ограниченных сессий.

Сообщения Новой сессии не могут быть идентифицированы как содержащие статический ключ Алисы или нет, пока статический ключ не будет расшифрован и проверен на наличие всех нулей. Следовательно, получатель должен использовать конечный автомат «IK» для всех сообщений Новой сессии. Если статический ключ — все нули, шаблон «ss» должен быть пропущен.


chainKey = из раздела флагов/статического ключа
  k = из раздела флагов/статического ключа
  n = 1
  ad = h из раздела флагов/статического ключа
  ciphertext = ENCRYPT(k, n, полезная нагрузка, ad)

1g) Формат Ответа Новой сессии

Один или несколько Ответов Новой сессии могут быть отправлены в ответ на одно сообщение Новой сессии. Каждый ответ предваряется тегом, который генерируется из Набора тегов для сессии.

Ответ Новой сессии состоит из двух частей. Первая часть — завершение рукопожатия Noise IK с предваряющим тегом. Длина первой части — 56 байт. Вторая часть — полезная нагрузка фазы передачи данных. Длина второй части — 16 + длина полезной нагрузки.

Общая длина — 72 + длина полезной нагрузки. Зашифрованный формат:


+----+----+----+----+----+----+----+----+
  |       Тег сессии   8 байт             |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +        Эфемерный открытый ключ        +
  |                                       |
  +            32 байта                   +
  |     Закодирован с помощью Elligator2  |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +  (MAC) для раздела ключа (без данных)  |
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+
  |                                       |
  +            Раздел полезной нагрузки   +
  |       Зашифрованные данные ChaCha20   |
  ~                                       ~
  |                                       |
  +                                       +
  |                                       |
  +----+----+----+----+----+----+----+----+
  |  Poly1305 Код аутентификации сообщения |
  +         (MAC) для раздела полезной нагрузки|
  |             16 байт                   |
  +----+----+----+----+----+----+----+----+

  Тег :: 8 байт, открытый текст

  Открытый ключ :: 32 байта, little endian, Elligator2, открытый текст

  MAC :: Код аутентификации сообщения Poly1305, 16 байт
         Примечание: Открытый текст данных ChaCha20 пуст (ZEROLEN)

  Зашифрованные данные раздела полезной нагрузки :: оставшиеся данные минус 16 байт

  MAC :: Код аутентификации сообщения Poly1305, 16 байт

Тег сессии

Тег генерируется в KDF Тегов сессии, как инициализировано в KDF Инициализации DH ниже. Это коррелирует ответ с сессией. Ключ сессии из Инициализации DH не используется.

Эфемерный ключ Ответа Новой сессии

Эфемерный ключ Боба. Эфемерный ключ — 32 байта, закодированный с помощью Elligator2, little endian. Этот ключ никогда не повторно используется; новый ключ генерируется с каждым сообщением, включая повторные передачи.

Полезная нагрузка

Зашифрованная длина — остаток данных. Расшифрованная длина — на 16 байт меньше зашифрованной длины. Полезная нагрузка обычно будет содержать один или несколько блоков Garlic Clove. См. раздел полезной нагрузки ниже для формата и дополнительных требований.

KDF для Набора тегов Ответа

Один или несколько тегов создаются из Набора тегов, который инициализируется с использованием KDF ниже, с использованием chainKey из сообщения Новой сессии.


// Генерация набора тегов
  tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32)
  tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey)

KDF для зашифрованного содержимого раздела ключа Ответа


// Ключи из сообщения Новой сессии
  // Ключи X25519 Алисы
  // apk и aepk отправляются в исходном сообщении Новой сессии
  // ask = закрытый статический ключ Алисы
  // apk = открытый статический ключ Алисы
  // aesk = закрытый эфемерный ключ Алисы
  // aepk = открытый эфемерный ключ Алисы
  // Статические ключи X25519 Боба
  // bsk = закрытый статический ключ Боба
  // bpk = открытый статический ключ Боба

  // Генерация тега
  tagsetEntry = tagset_nsr.GET_NEXT_ENTRY()
  tag = tagsetEntry.SESSION_TAG

  // MixHash(tag)
  h = SHA256(h || tag)

  Это шаблон сообщения «e»:

  // Эфемерные ключи X25519 Боба
  besk = GENERATE_PRIVATE_ELG2()
  bepk = DERIVE_PUBLIC(besk)

  // Эфемерный открытый ключ Боба
  // MixHash(bepk)
  // || ниже означает объединение
  h = SHA256(h || bepk);

  // elg2_bepk отправляется в открытом виде в
  // начале сообщения Новой сессии
  elg2_bepk = ENCODE_ELG2(bepk)
  // Как раскодировано Бобом
  bepk = DECODE_ELG2(elg2_bepk)

  Конец шаблона «e».

  Это шаблон сообщения «ee»:

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  // Параметры ChaChaPoly для шифрования/расшифровки
  // chainKey из исходного раздела полезной нагрузки Новой сессии
  sharedSecret = DH(aesk, bepk) = DH(besk, aepk)
  keydata = HKDF(chainKey, sharedSecret, "", 32)
  chainKey = keydata[0:31]

  Конец шаблона «ee».

  Это шаблон сообщения «se»:

  // MixKey(DH())
  //[chainKey, k] = MixKey(sharedSecret)
  sharedSecret = DH(ask, bepk) = DH(besk, apk)
  keydata = HKDF(chainKey, sharedSecret, "", 64)
  chainKey = keydata[0:31]

  // Параметры AEAD
  k = keydata[32:63]
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, ZEROLEN, ad)

  Конец шаблона «se».

  // MixHash(ciphertext)
  h = SHA256(h || ciphertext)

  chainKey используется в зажиме ниже.

KDF для зашифрованного содержимого раздела полезной нагрузки

Это похоже на первое сообщение Существующей сессии, после разделения, но без отдельного тега. Кроме того, мы используем хэш из вышеуказанного, чтобы привязать полезную нагрузку к сообщению NSR.


// split()
  keydata = HKDF(chainKey, ZEROLEN, "", 64)
  k_ab = keydata[0:31]
  k_ba = keydata[32:63]
  tagset_ab = DH_INITIALIZE(chainKey, k_ab)
  tagset_ba = DH_INITIALIZE(chainKey, k_ba)

  // Параметры AEAD для полезной нагрузки Ответа Новой сессии
  k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
  n = 0
  ad = h
  ciphertext = ENCRYPT(k, n, полезная нагрузка, ad)

Примечания

Могут быть отправлены несколько сообщений NSR в ответ, каждое с уникальными эфемерными ключами, в зависимости от размера ответа.

Алиса и Боб обязаны использовать новые эфемерные ключи для каждого сообщения NS и NSR.

Алиса должна получить одно из сообщений NSR Боба до отправки сообщений Существующей сессии (ES), и Боб должен получить сообщение ES от Алисы до отправки сообщений ES.

chainKey и k из раздела полезной нагрузки NSR Боба используются в качестве входных данных для начальных зажимов DH ES (в обоих направлениях, см. KDF зажима DH).

Боб должен сохранять только Существующие сессии для сообщений ES, полученных от Алисы. Любые другие созданные входящие и исходящие сессии (для нескольких NSR) должны быть уничтожены сразу после получения первого сообщения ES Алисы для данной сессии.

1h) Формат Существующей сессии

Тег сессии (8 байт) Зашифрованные данные и MAC (см. раздел 3 ниже)

Формат

Зашифровано:


+----+----+----+----+----+----+