|
|
Принцип работы шифрования.
Зашифрованное общение между сервером и клиентом в DMconnect происходит на 42440-м
порту по стандарту. Для шифрования используется шифр AES-256-CBC и протокол
Диффи-Хеллмана для обмена ключами. Ниже идёт математическое объяснение шифрования,
но далее мы перейдём к самому обмену пакетами.
Расчёт секретного ключа.
Перед началом общения с сервером, нам нужно высчитать наш секретный ключ.
Секретный ключ - это просто любое 256-битное число. Представим наш
секретный ключ в виде переменной b.
Параметры для протокола Диффи-Хеллмана.
Перед расчётом, нам необходимо создать две переменные. Первая - 2048-битное
простое число. Я не хочу захламлять страницу, поэтому вы можете посмотреть данное
число здесь. Запишем наше 2048-битное число в виде
константы P.
И создадим ещё одну константу - G, она равна 2.
Расчёт публичного ключа.
Сейчас нам понадобятся сразу все наши значения - b (наш секретный ключ),
P (2048-битное простое число) и G (генератор, равен 2).
А теперь посчитаем публичный ключ. Расчёт происходит так:
1. Берём число G.
2. Возводим G в степень b.
3. Делим результат на P и берём остаток.
Вот и всё, мы получили публичный ключ! Запомним его в виде переменной B.
Преобразование в байты.
Чтобы B можно было удобно передавать по сети, превратим его в обычную
последовательность байтов.
Это делается вот так:
1. Превращаем B в число в шестнадцатеричной системе. Например, если
B = 1024, то в шестнадцатеричной записи B = 400.
2. Делаем так, чтобы каждые две цифры соответствовали одному байту.
В шестнадцатеричной системе 2 цифры = 1 байт (от 00 до FF).
Если цифр нечётное количество (например, 400, т. е. три цифры), то
добавляем спереди ноль: 0400.
3. Разбиваем строку на пары цифр и превращаем их в байты.
04 - байт со значением 4.
00 - байт со значанием 0.
Получился набор байтов: 04 00.
Обмен публичными ключами.
Теперь перейдём непосредственно к обмену пакетами. Сразу же после подключения
на 42440-й порт, сервер отпрваляет клиенту сообщение вида
[2 байта: длина ключа][256 байт: публичный ключ]
При этом длина ключа указывается в формате big-endian.
Наш клиент должен после этого отправить серверу свой публичный ключ:
[2 байта: длина ключа][256 байт: публичный ключ]
Формат зашифрованных сообщений.
Структура пакета каждого зашифрованного сообщения выглядит так:
[4 байта: длина данных][16 байт: IV][зашифрованные данные][32 байта: HMAC]
При этом:
1. Длина данных указывается, опять же, в big-endian формате (общая длина
пакета без учёта самого поля длины)
2. IV - это 16 случайных байт для каждого сообщения.
3. Зашифрованные данные представляют собой исходное сообщение, зашифрованное с
помощью AES-256-CBC.
4. HMAC - 32 байта для проверки целостности.
Процесс шифрования сообщения (на стороне отправителя).
Создадим ещё одну константу - общий секрет. Он считается так:
K = A^b mod P
Где:
A - публичный ключ сервера, который мы получили ранее.
b - наш секретный ключ
P - 2048-битное число, которое можно найти здесь.
Теперь перейдём к самому процессу:
1. Генерируется случайный IV.
2. Сообщение дополняется до кратного 16 байтам (PKCS7 padding).
3. Данные шифруются AES-256-CBC с ключом шифрования K.
4. Вычисляется HMAC от зашифрованных данных
5. Формируется пакет: [длина][IV][зашифрованные_данные][HMAC]
Процесс шифрования сообщения (на стороне получателя).
1. Читается длина данных (4 байта).
2. Читается весь пакет данных.
3. Извлекается IV (первые 16 байт).
4. Извлекается HMAC (последние 32 байта).
5. Проверяется HMAC для аутентификации.
6. Данные расшифровываются AES-256-CBC с ключом K.
7. Удаляется padding.
Небольшой пример клиента.
Вот и всё! здесь вы можете посмотреть
пример простейшего клиента, использующего шифрование.
Клиент написан на Python 2.7.
| |
|
|
|
|