Собственная Реализация Https С Использованием Crypto++ Для Начальной Загрузки I2P

Каждый новый узел I2P при первом запуске должен откуда-то получить первоначальный список узлов.

Для этого существуют специальные серверы (reseed), адреса которых жестко зашиты в коде.

Раньше закачка осуществлялась по http, но в последнее время ресиды стали переходить на https. Для успешной работы «фиолетовый» I2P также необходимо было внести соответствующие изменения.

Используемая там криптографическая библиотека крипто++ не поддерживает SSL. Вместо использования дополнительной библиотеки типа openssl, которая фактически дублирует криптографию, был выбран вариант, обсуждаемый ниже.

Bootstrap — единственное место в I2P, где используется https. С другой стороны, статья будет интересна тем, кому интересно понять, как работает ssl, и попробовать его самостоятельно.



Изобретение колеса заново

Наша цель — получить файл i2pseeds.su3 размером около 100 КБ с одного из повторно заполняемых узлов I2P. Этот файл подписан отдельным сертификатом, независимым от сертификата хоста, поэтому проверку сертификата можно исключить.

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

Будет использоваться исключительно ТЛС 1.2 и набор шифров TLS_RSA_WITH_AES_256_CBC_SHA256. Другими словами, AES256 в режиме CBC используется для шифрования данных, а RSA — для согласования ключей.

Этот выбор обусловлен тем, что AES256-CBC является наиболее используемым шифрованием в I2P, а RSA упрощает реализацию протокола за счет уменьшения количества сообщений, необходимых для согласования ключей.

Помимо RSA и AES, вам также потребуются следующие криптографические функции из crypto++:

  • HMAC для вычисления контрольных сумм зашифрованных сообщений и псевдослучайных функций.

    Обратите внимание, что используется стандартная реализация HMAC, а не I2P.

  • Хэш SHA256 для использования с HMAC и для расчета контрольной суммы всех сообщений, участвующих в установлении соединения.

  • Функции для работы с описаниями на языке ASN.1 в кодировке DER. Требуется для извлечения открытого ключа из сертификата X.509.
Используется реализация RSA на базе PKCS v1.5. Длина ключа может быть любой и определяется сертификатом.



Собственная реализация https с использованием crypto++ для начальной загрузки I2P



Передача сообщений через SSL

Абсолютно все передаваемые сообщения начинаются с 5-байтового заголовка, первый байт которого содержит тип сообщения, следующие 2 байта — номер версии протокола (0x03, 0x03 для TSL 1.2) и далее длину оставшейся части (контента).

сообщения - 2 байта в Big Endian, тем самым определяя границы сообщений.

Таким образом, при получении новых данных сначала следует прочитать 5 байт заголовка, а затем сколько байт содержится в поле длины.

Существует 4 типа сообщений:

  1. 0x17 — данные.

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

    Размер данных должен быть кратен 16 байтам.

  2. 0x16 – установление соединения.

    Несколько типов, определяемых соответствующим полем внутри контента.

    Незашифрованное, за исключением «законченного» сообщения, отправленного последним.

  3. 0x15 — предупреждение.

    Сообщение о том, что «что-то пошло не так».

    Закрываем соединение.

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

  4. 0x14 — изменить шифр.

    Отправлено сразу после согласования ключей.

    Содержимое составляет 1 байт и всегда содержит 0x01. На самом деле это часть процесса установления соединения.

В нашей реализации зашифрованные данные выглядят так: 16 байт IV для CBC, в TSL 1.2 каждое сообщение имеет свой IV; длина данных до 64К – длина заголовков; 32-байтовый MAC-адрес рассчитывается по 13-байтовому заголовку и данным, причем заголовок состоит из 8-байтового порядкового номера, начинающегося с нуля, типа сообщения (0x17 или 0x16), версии и длины данных.

Все в BigEndian. Ключ для HMAC также рассчитывается во время установки соединения; заполнитель, так что длина зашифрованных данных кратна 16 байтам, последний байт содержит количество байт заполнителя без учета самого заполнителя.

Если длина сообщения кратна 16 байтам, то к этому последнему байту длины будут добавлены еще 16 байтов.



Установление соединения

В процессе установки нам предстоит решить две задачи:
  1. Согласование и вычисление ключей для шифрования и HMAC.
  2. Отправьте правильную последовательность сообщений, чтобы другая сторона не закрыла соединение, а перешла в режим обмена данными.

В нашем случае последовательность сообщений выглядит так: КлиентПривет --> (0x01) <--ServerHello (0x02) <--Certificate (0x0B) <--ServerHelloDone (0x0E) --> ClientKeyExchange (0x10) --> Изменить Спецификацию Шифра --> Завершено (0x14) <--ChangeCipherSpec <--Finished (0x14) где "--> " означает отправку сообщения, а "<--" means receiving it. Все сообщения, кроме ChangeChiperSpec, имеют тип сообщения 0x16 — установление соединения.

Содержимое сообщения этого типа начинается с собственного 4-байтового заголовка, первый байт которого представляет собой тип сообщения установки соединения, как указано выше, и 3 байта длины оставшегося сообщения, самый старший байт которого в наш случай всегда равен нулю.

Давайте рассмотрим эти сообщения подробно.



КлиентПривет
Первое сообщение, которое мы отправляем на сервер после успешного подключения.

Поскольку мы используем один конкретный набор шифров, в нашем случае он будет постоянным.

Так:

   

static uint8_t clientHello[] = {

Теги: #i2p #tls 1.2 #HTTPS #C++ #crypto #programming #i2p
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.