Используемый в настоящее время протокол ElGamal/AES имеет ряд существенных недостатков и является одной из причин относительно медленной работы сети I2P. Рассмотренный в статье протокол призван повысить скорость и надежность сети и открывает новые возможности, в том числе передачу потокового аудио и видео.
На основе протокола Noise и алгоритмов обмена сообщениями Signal. Подробное описание Здесь .
Особо следует отметить, что новый протокол можно использовать с существующими адресами I2P в сочетании с ElGamal/AES. Статья посвящена реализации в i2pd
Новая криптография и эллигатор
По сути, используется та же криптография, что и в NTCP2 : x25519 заменяет ElGamal, а AEAD/Chacha20/Poly1305 заменяет AES. Кроме того, добавлен HKDF-SHA256, создающий ключи длиной 32 или 64 байта и доступный в OpenSSL версии 1.1.1; более ранние версии используют собственную реализацию с использованием HMAC-SHA256. В отличие от временного открытого ключа Эль-Гамаля, который представляет собой случайные 256 байт, открытый ключ x25519 представляет собой точку на эллиптической кривой, и злоумышленник может выяснить, являются ли 32 байта ключом x25519, и сделать определенные выводы.Чтобы этого не произошло, публичный ключ подвергается преобразованию под названием Эллигатор, которое само по себе сложное и заслуживает отдельной статьи.
Подробно описано, как и почему это работает. Здесь .
Однако практическая реализация на базе OpenSSL выглядит не такой уж сложной:
- Для конвертации подходит только половина ключей.
Пригодность определяется путем вычисления символа Лежандра.
- Действительный ключ можно преобразовать в 254-битную случайную последовательность и восстановить из нее путем обратного преобразования.
- Произвольные 254 бита можно преобразовать обратно в какой-нибудь ключ x25519.
- В I2P старшие 2 бита заполняются случайными значениями вплоть до полных 32 байтов.
Сквозное I2P-шифрование
I2P-адреса обмениваются друг с другом I2NP-сообщениями типа 11 — Garlic («чеснок»), содержимое которых представляет собой полностью зашифрованные данные, зашифрованные адресом отправителя и расшифрованные адресом получателя.Более подробно описаны принципы работы.
Здесь .
В отношении Эль-Гамаля/AES следует отметить следующие основные моменты:
- Первое сообщение шифруется открытым ключом Эль-Гамаля получателя из его LeaseSet. Вместе с ним передаются AES-ключ и набор 32-байтовых тегов для последующих сообщений.
Шифрование Эль-Гамаля и особенно дешифрование очень медленные.
- Каждый тег используется один раз.
Получатель сначала сравнивает первые 32 байта сообщения с известными тегами и, если они найдены, использует соответствующий ключ AES для расшифровки остальной части сообщения.
Таким образом, при использовании метки отправитель должен быть уверен, что метка известна получателю, периодически отправлять новые метки и ждать подтверждения получения.
Поэтому довольно часто возникает ситуация, что подтвержденных тегов больше нет и приходится снова использовать ЭльГамаль.
- Получатель не знает, откуда пришло сообщение.
- Длина сообщения, зашифрованного AES, всегда кратна 16 байтам, а для шифрования Эль-Гамаля остается остаток 2.
Между парой ключей может быть только одна сессия, сессии двунаправленные, при получении пакета сессия определяет отправителя.
Все пакеты, кроме первого, начинаются с 8-байтового тега, который связывает пакет с набором тегов и сеансом.
Теги не передаются , и рассчитываются одновременно на обеих сторонах сеанса.
Пакет зашифрован AEAD/Chacha20/Poly1305, ключ шифрования уникален для каждого пакета и рассчитывается с обеих сторон на основе предыдущего с использованием HKDF.
i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK);
Установление соединения
При установке соединения происходит обмен двумя сообщениями и задействованы 4 пары ключей x25519: две пары ключей шифрования адреса и две пары временных ключей.Публичный ключ шифрования сервера (Боб) берется из LeaseSet его адреса, публичные временные ключи передаются вместе со скрытыми с помощью Эллигатора сообщениями, публичный ключ шифрования клиента (Алиса) передается отдельным зашифрованным блоком.
NewSession(NS) -----------> Боб
Алиса < — NewSessionReply(NSR)
В процессе подключения ключ ck (ключ цепочки) рассчитывается по протоколу Noise на основе вычисленного общего ключа x25519 (общий секрет), в качестве операции MixKey используется HKDF. i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK);
После успешного согласования создается первый набор тегов с ключом ck. Первый набор тегов
uint8_t keydata[64];
i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
// k_ab = keydata[0:31], k_ba = keydata[32:63]
auto receiveTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
receiveTagset->DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab)
receiveTagset->NextSessionTagRatchet ();
m_SendTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
m_SendTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
m_SendTagset->NextSessionTagRatchet ();
Алиса отправляет NS-сообщения до тех пор, пока не получит NSR от Боба, первый полученный NSR определяет текущий сеанс, если сеанс уже существует, то обрабатывается только содержимое пакета.
С каждым NS создается отдельный временный набор тегов, предназначенный исключительно для приема и расшифровки NSR. Боб создает новый сеанс после получения первого NS и продолжает отправлять NSR с ключами и тегами, пока не получит первое сообщение установленного сеанса.
Структура сообщения чеснока
Незашифрованное сообщение Garlic в новом протоколе имеет другую структуру, чем в ElGamal/AES. Вместо «чесноков», которые по сути представляют собой сообщения I2NP с инструкциями по их доставке, новый протокол использует блоки разных типов, аналогично NTCP2. Каждый блок состоит из заголовка с указанием типа и длины, а также содержимого.В настоящее время используются следующие типы блоков:
- Зубчик чеснока — содержит сообщение I2NP с инструкциями по доставке.
Обычно данные или LeaseSet. Инструкции по доставке в i2pd на данный момент не используются и игнорируются при получении, но заполняются при отправке для совместимости с Java-маршрутизаторами.
Заголовок I2NP изменен для уменьшения объема передаваемых данных.
- Следующий ключ — используется для согласования ключей нового набора тегов.
- ACK Request – запрос на подтверждение получения сообщения.
Обычно запрашивается вместе с отправкой нового LeaseSet.
- ACK — ответ на запрос ACK.
- Заполнение — это блок случайной длины 0-16 байт. Всегда последний
Наборы тегов и создание новых ключей
Ранее упомянутый набор тегов представляет собой генератор троек (число, тег, ключ) для каждого нового пакета.Числа идут по порядку, начиная с 0. Число передается как двухбайтовое число, поэтому в одном наборе тегов может быть сгенерировано не более 65535 тегов, после чего требуется новый набор тегов.
На практике используется гораздо меньшее значение, в частности в i2pd новый набор тегов создается после отправки 4К пакетов.
Набор тегов начинается с операции DH_INITIALIZE, основанной на общем ключе и результате DH_INITIALIZE предыдущего набора тегов.
DH_INITIALIZE
// DH_INITIALIZE(rootKey, k)
uint8_t keydata[64];
i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64)
memcpy (m_NextRootKey, keydata, 32); // nextRootKey = keydata[0:31]
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_KeyData.buf);
// [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64)
memcpy (m_SymmKeyCK, m_KeyData.buf + 32, 32);
Затем рассчитывается SSESTAG_CONSTANT, который используется для расчета тегов.
SSESTAG_CONSTANT и теги
i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), nullptr, 0, "STInitialization", m_KeyData.buf); // [sessTag_ck, sesstag_constant] = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64)
memcpy (m_SessTagConstant, m_KeyData.GetSessTagConstant (), 32);
Фактический расчет тега представляет собой простой HKDF из предыдущего.
[sessTag_ck, tag] = HKDF(sessTag_ck, SSESTAG_CONSTANT, "SessionTagKeyGen", 64) Если необходимо создать новый набор тегов, отправитель создает новый ключ x25519 и добавляет в следующий пакет блок Next Key с открытым ключом, получатель также создает новый ключ и отправляет в ответ Next Key. После успешного согласования стороны начинают использовать новый набор тегов, в противном случае они продолжают отправлять следующий ключ, используя предыдущий набор тегов.
Новый протокол уже реализован и используется в последних выпусках I2P: 0.9.46 Java и 2.32.0 i2pd. Чтобы его включить, необходимо добавить параметры i2cp.leaseSetType=3 и i2cp.leaseSetEncType=0.4 для взаимодействия с адресами как со старым, так и с новым шифрованием, или i2cp.leaseSetType=3 и i2cp.leaseSetEncType=4 только для нового шифрования.
Также возможна совместная работа с зашифрованными LeaseSets с параметром i2cp.leaseSetType=5. Теги: #информационная безопасность #C++ #криптография #i2p #openssl #i2pd #ratchet #elligator
-
Скайп
19 Oct, 24 -
Nokia N900 + Q-Steer = Развлечение
19 Oct, 24 -
Дайджест Microsoft Ignite
19 Oct, 24 -
Надежность Go В Инфраструктуре Dropbox
19 Oct, 24 -
Очередной Сюрприз От Typograph
19 Oct, 24 -
Ваучер На Бесплатные Экзамены Microsoft
19 Oct, 24