
Продолжаю изучать криптографию, делюсь опытом. Нашел интересную особенность дискретного логарифма, которая превращается в математический бэкдор протокола Диффи — Хеллмана (далее DH).
Пробежимся по теории
Вспомним дискретный логарифм (далее DLOG) https://ru.wikipedia.org/wiki/Дискретное_логарифмирование
Нам нужен вариант DLOG в конечном поле , где p - простое число https://ru.wikipedia.org/wiki/Конечное_поле
Общеизвестно что задача DLOG является односторонней функцией https://ru.wikipedia.org/wiki/Односторонняя_функция т.е. поиск является трудной задачей.
Кроме полного перебора, существует много алгоритмов решения данной задачи https://ru.wikipedia.org/wiki/Дискретное_логарифмирование#Алгоритмы_решения (не будем их рассматривать).
Иногда поиск является тривиальной задачей, например:
если , то
если , то
Следует сказать что является первообразным корнем или примитивом https://ru.wikipedia.org/wiki/Первообразный_корень_(теория_чисел)
Для примитив
, проверим:
Обращаем внимание на последнюю строку, т.е. если , то
или
Итак, у нас есть уже три случая, когда поиск тривиален:
Как правило для анализа DLOG строят таблицу логарифмов:

По таблице логарифмов нарисуем график:

На графике ничего интересного, только хаотичное изменение показателя
Криптографический протокол DH построен на задаче DLOG https://ru.wikipedia.org/wiki/Протокол_Диффи_—_Хеллмана
Посмотрим пример прямо из вики:

Ничего сложного.
Далее пойдет новая или непубличная информация.
Основная часть
Будем анализировать DLOG как таблицу степеней. Таблица степеней это перевернутая таблица логарифмов (см. рис. ниже), слева — таблица степеней, справа — таблица логарифмов. Об этом я писал в статье "Как сгенерировать порождающие полиномы для конечных полей." https://habr.com/ru/articles/844300

Таблица степеней удобнее, так как можно наблюдать сразу несколько примитивов (), синим подчеркнута строка для примитива
, колонка для
не обозначена.
Далее посмотрим несколько таблиц степеней и обратим внимание на среднюю колонку

Имея ввиду экстраполяцию, можно предположить, что данная особенность распространяется на все множество таблиц степеней .
В средней колонке число показывает строки с уникальными значениями, значит в начале строки - примитив, наблюдаем также:
не касается последней строки, там
;
- простое число, иначе, например для
- непростое, поэтому будут "лишние" строки:
.
Математически это выглядит так:
Математики знакомые с критериями Эйлера https://ru.wikipedia.org/wiki/Критерий_Эйлера и квадратичным вычетом https://ru.wikipedia.org/wiki/Квадратичный_вычет увидят знакомое:
но здесь вместо установлено
!
Надо вспомнить модулярную арифметику https://en.wikipedia.org/wiki/Modular_arithmetic (статья в en-вики более понятна), фактически в данном случае , вернее так:
Используя вышесказанное, можно находить все примитивы конечного поля:

Общее количество примитивов конечного поля равно , где
— функция Эйлера totient https://ru.wikipedia.org/wiki/Функция_Эйлера
Посмотрим на таблицу степеней в виде графика, добавил нулевое значение
для симметричности, похож на "паука":

Вернемся в протоколу DH, изменим наименования переменных:
для Алисы:,
- открытый ключ,
- закрытый ключ.
для Боба: ,
- открытый ключ,
- закрытый ключ.
- общий секретный ключ, используется для шифровки - расшифровки сообщений.
Алиса вычисляет
Боб вычисляет
Рассмотрим канонический пример:
Алиса выбирает закрытый ключ
Боб выбирает закрытый ключ
Алиса вычисляет открытый ключ
Боб вычисляет открытый ключ
Алиса и Боб обмениваются открытыми ключами
Алиса вычисляет общий секретный ключ
Боб вычисляет общий секретный ключ
Алиса и Боб получили один и тот-же секретный ключ
, не передавая его по сети.
Теперь пример, когда закрытый ключ равен :
Алиса выбирает закрытый ключ
Боб выбирает закрытый ключ
Алиса вычисляет открытый ключ
Боб вычисляет открытый ключ
Алиса и Боб обмениваются открытыми ключами
Алиса вычисляет общий секретный ключ
Боб вычисляет общий секретный ключ
Злоумышленник перехватил открытый ключ и вычисляет закрытый ключ той-же Алисы по формуле (1):
Далее, для получения секретного ключа есть два способа:
1 способ. С помощью открытого ключа Боба
2 способ. Сразу, если хотя бы один из открытых ключей равен , то
или
, по формуле:
Внимательно посмотрите на последнюю строку любого , например см. рис. выше "Несколько таблиц степеней".
Я не нашел в открытых источниках запрета на использование в качестве закрытого ключа .
Данное выражение упоминается в статье: S. C. Pohlig and M. E. Hellman, "An improved algorithm for computing logarithms in GF(p) and its cryptographic significance." https://ee.stanford.edu/~hellman/publications/28.pdf, IEEE Trans. Info. Theory 24 (1978), 106–111.
В статье указано что должно быть простым числом для повышения безопасности.
Еще в статье можно встретить упоминание тривиального случая : "Also, restrictions might be imposed on K (e.g.,
) to avoid simple but improbable transformations." В переводе: "Кроме того, на K могут быть наложены ограничения (например,
), чтобы избежать простых, но маловероятных преобразований." (
- ключ).
Решение: запретить использовать в качестве закрытого ключа , дополняем список тривиальных случаев:
Можно найти еще? Попробуем.
Рассмотрим внимательно "паука", см. рис. выше, почему он симметричен?
Примитивы сгруппированы парами:

Когда-то я неправильно предположил, что эти пары взаимно простые, на самом деле они мультипликативно обратны по модулю https://ru.wikipedia.org/wiki/Обратное_по_модулю_число
Проверим:
Посмотрим график первой пары

Симметрично, не правда ли? и в табличном виде:

Мы выяснили выше, что мультипликативно обратны, проверим остальные пары:
Все пары мультипликативно обратны по модулю .
Возвращаемся к DH, рассмотрим пример:
Алиса выбирает закрытый ключ
Боб выбирает закрытый ключ
Алиса вычисляет открытый ключ
Боб вычисляет открытый ключ
Алиса и Боб обмениваются открытыми ключами
Алиса вычисляет общий секретный ключ
Боб вычисляет общий секретный ключ
Вроде все нормально, но!
Нам известен примитив
, мы можем получить мультипликативно обратный
при помощи расширенного алгоритма Евклида https://ru.wikipedia.org/wiki/Расширенный_алгоритм_Евклида
Сравниваем
с открытыми ключами, у Боба открытый ключ
, значит закрытый ключ Боба равен
, см. рис. ниже
Вычисляем секретный ключ

Бинго - вот вторая "дырка", согласно формуле:
Эту формулу можно вывести из Малой теоремы Ферма https://ru.wikipedia.org/wiki/Малая_теорема_Ферма
.
- это и есть обратное число -
Дополняем список тривиальных случаев:
Больше уязвимостей пока не нашел.
Можно еще посмотреть график поля (симметричность также видна) и таблицу, см. рисунки ниже:


Заключение
Предупреждения о предполагаемой сложности задачи DLOG, например:
"Криптографическая стойкость алгоритма Диффи — Хеллмана (то есть сложность вычисления
по известным
) основана на предполагаемой сложности задачи дискретного логарифмирования." Форматирование сохранено, источник: https://ru.wikipedia.org/wiki/Протокол_Диффи_—_Хеллмана#Криптографическая_стойкость
"A cryptographic system is described which is secure if and only if computing logarithms over
is infeasible." (мой перевод: "Описывается криптографическая система, которая является безопасной тогда и только тогда, когда вычисление логарифмов по
невозможно.") Источник: S. C. Pohlig and M. E. Hellman, "An improved algorithm for computing logarithms in GF(p) and its cryptographic significance." https://ee.stanford.edu/~hellman/publications/28.pdf IEEE Trans. Info. Theory 24 (1978), 106–111.
Что касается описанных в данной статье уязвимостях, то проблемы не такие большие. Необходимо в программное обеспечение, генерирующее закрытые ключи, добавить исключения: , остальные были известны и ранее.
Математические уязвимости существуют и должны быть общеизвестны.
Если нашли ошибки, пишите камменты.
"Поиграться" с таблицами степеней и определить примитивы можно в сервисе https://dlog.vladlin.ru/ (AS IS)
На задаче DLOG, кроме протокола Диффи-Хеллмана, базируются и другие, например:
Надо проверить :-)
Комментарии (28)
wataru
16.06.2025 10:17Я правильно понимаю, что основная "новая не публичная информация" - это про то что задача обратного логарифма, оказывается, легко решается в для p-1 и p-2?
Я не нашел в открытых источниках запрета на использование в качестве закрытого ключа
.
На практике p очень большое. Очень-очень большое. Сотни бит. И выбрать в качестве ключа именно (p-1)/2 - практически не возможно. Выбираются же закрытые ключи случайно для каждой сессии.
Кроме того, этот косяк давно известен и проверяется во всех криптографических системах. Например, openssh: https://github.com/openssh/openssh-portable/blob/master/dh.c#L260
Что касается p-2 - то этот случай тоже давно известен. Там открытый ключ окажется маленьким и маленькие открытые ключи тоже исключаются: https://github.com/openssh/openssh-portable/blob/master/dh.c#L275
mvladlin Автор
16.06.2025 10:17Спасибо, для математики не важно - большое
или маленькое.
Проверять заранее невалидный закрытый ключ на уровне публичного ключа неверно, так как тратятся лишние ресурсы на ненужное вычисление того-же публичного ключа.
Что касается p-2 - то этот случай тоже давно известен. Там открытый ключ окажется маленьким
Сможете математически доказать?
wataru
16.06.2025 10:17Сначала не то написал, сейчас подумаю.
Нет, оно не маленькое. Там получается публичный ключ g^(-1) = (p+1)/2.
Это какой-то очень частный случай. Так-то, действительно, можно руками найти логарифм для какого-нибудь (p-1)/2 и тоже его записывать в запрещенные.
Шанс что кому-то выпадет именно этот ключ - ничтожен.
seregablog
16.06.2025 10:17Далее пойдет новая или непубличная информация
Информация далее не новая и известная
Я не нашел в открытых источниках запрета на использование в качестве закрытого ключа (p-1)/2.
Находится в гугле за минуту
Всю статью можно записать в одну строку: Если публичный ключ Алисы A = p-1, то её закрытый ключ a = (p-1)/2.Это, конечно, верно. В плане атаки на ключ с таким же успехом можно рассчитать A42 = g^42 mod p, и когда публичный ключ Алисы совпадёт A = A42, сказать, что её закрытый ключ a = 42
mvladlin Автор
16.06.2025 10:17Находится в гугле за минуту
Ccылку пришлите где вы нашли запрет на использование в качестве закрытого ключа (p-1)/2 ?
seregablog
16.06.2025 10:17mvladlin Автор
16.06.2025 10:17Спасибо, но это обсуждение с двумя минусовыми ответами, а не утверждение.
seregablog
16.06.2025 10:17В этих "минусовых ответах" (в отличие от вашей статьи) доказано, что g^((p - 1) / 2) = p - 1 (mod p). Это лаконичнее и полезнее всех ваших таблиц-графиков-примеров
Это просто первая ссылка, которая мне попалась. Поскольку само утверждение простое, оно наверняка есть в учебниках в виде какого-нибудь примера или упражнения. Полагаю, всерьёз вы не думаете, что первым это заметилиmvladlin Автор
16.06.2025 10:17Насчет (p-1)/2 точно не думаю - уж слишком "наверху" находится, смущает что не описано в какой-нибудь вики или открытой статье, чтобы быстро находилось.
Я думаю что и известен пример с (p-2) хотя спрятан дальше.
seregablog
16.06.2025 10:17Утверждение о том, что g^(p-2) = g^(-1) известно, это простое следствие малой теоремы ферма, написано даже в википедии
Ключ p-2 "плохой" настолько же, насколько плох ключ 42 из моего примера вышеmvladlin Автор
16.06.2025 10:17Утверждение о том, что g^(p-2) = g^(-1) известно, это простое следствие малой теоремы ферма, написано даже в википедии
Да, и описана у меня в статье
cpud47
16.06.2025 10:17Вам для понимания стоит сформулировать формально, что такое "уязвимость в криптосистеме DH". Тогда станет ясно, почему это не проблема.
Например, можно сформулировать так: это такой вероятностный алгоритм, что для случайного обмена публичных ключами, алгоритм даёт ответ с неисчезающей вероятностью. Неисчезающая вероятность означает, что если
- вероятность угадать ответ при длине ключа в n бит, то
В такой постановке, Ваши примеры не являются уязвимостями.
mvladlin Автор
16.06.2025 10:17Нет уязвимости в DH, есть (не уязвимость) а особенность DLOG.
А насчет вероятности стремящейся к 0 - Вы правы на 100%
cpud47
16.06.2025 10:17Я не очень понял, с чем Вы соглашаетесь, или что опровергаете :)
описанные уязвимости - математические
Прежде чем серьёзно говорить про "математические" уязвимости нужно строго (математически!) сформулировать, а что такое вообще уязвимость. А после этого математически доказать, что описанное в статье уязвимостями являются.
А статья будет полезна начинающим криптографам - к которым причисляю и себя
Нормальные вводные курсы по криптографии собственно начинаются со строгого определения, что такое вообще уязвимость. Выше я привёл упрощённое определение.
Потому что без определения, это просто махание руками, без какой либо математики. Так можно дойти и до того, что я объявлю функцию f(x), которая решает DLOG для заданной группы (просто предпосчитаю её например) - и у нас будет "математическая" уязвимость. И вот попробуйте мне доказать, что это не так? ;) (серьёзно - попробуйте опровергнуть этот тезис)
Статья у Вас в целом неплохая, но посыл чуть не тот. У Вас как раз очень хорошая иллюстрация, почему понятие "уязвимость" - довольно неоднозначное, и почему для него нужны строгие определения. Вот если Вы этими определниями(с разборами Ваших примеров по определениям) дополните статью - тогда действительно будет хороший материал для начинающих. А пока, она немного вводит в заблуждение неискушённого читателя.
mvladlin Автор
16.06.2025 10:17Извините, просто некогда "воду в ступе толочь"
Imaginarium
16.06.2025 10:17Хех. Вам предложили сделать из статьи что-то стоящее и даже указали как именно, чтобы статья обрела смысл и математическое содержание, потратили время на Вас и на объяснения Вам, а Вы отвечаете вот так))
Без предложенных корректировок как раз Ваша статья и является толчением воды в ступе)
MasterMentor
16.06.2025 10:17Статья - норм! Нужно очень хорошо зубы на алгебраистике наточить, чтобы писать (и читать) такие статьи. :)
PS А был известен этот "баг" в математике DH либо нет, пофиг. :)
mvladlin Автор
16.06.2025 10:17Наверное моя вина - в статье неправильно расставлены акценты.
У меня нет претензий к DH, описанные уязвимости - математические.
Они "пришли" в протокол DH вместе с дискретным логарифмом (DLOG).
Создатели DH всегда подчеркивали что зависят от DLOG.
И вообще протокол DH - прекрасная идея.
Другое дело тривиальные случаи DLOG (не DH), (в терминах DH - когда закрытый ключ может быть вычислен легко), освещены в публичной сфере очень слабо, в комментах исходного кода, в обсуждениях на форумах и прочее.
А статья будет полезна начинающим криптографам - к которым причисляю и себя.
VZ1
16.06.2025 10:17Остается только добавить, что золотое правило — не городить огород самому, а использовать уже существующие библиотеки, где такие бэкдоры уже предусмотрены. Например:
from cryptography.hazmat.primitives.asymmetric import dh parameters = dh.generate_parameters(generator=2, key_size=2048) private_key = parameters.generate_private_key() public_key = private_key.public_key()
Эта библиотека автоматически избегает небезопасных значений ключей и поддерживает современные стандарты.
cpud47
16.06.2025 10:17Золотое правило - не использовать криптографические примитивы. Стоит сразу брать библиотеки высокого уровня с пуленепробиваемыми апи: всякие tls и sodium.
AES, DH, RSA и прочие - слишком тяжело использовать без ошибок.
lgorSL
16.06.2025 10:17Имея ввиду экстраполяцию, можно предположить, что данная особенность распространяется на все множество таблиц степеней GF(p).
Так это же логично. Примерно как для обычных чисел у нас есть два корня из единицы (равные 1 и -1), а так же четыре корня четвёртой степени (-1, 1, i, -i), так и для вычетов простого числа так же, только вместо -1 там будет (p-1) и для четвёртой степени чуть сложнее.
Если внимательно посмотреть на таблицу степеней в gf(17), то в 8 колонке будут корни второй степени (которых ровно два и они 1 и 16), а в колонке 4 - корни четвёртой степени (1, 16, 4, 13)
А например в таблице степеней по модулю 19 можно корни третьей степени найти в колонках 6 и 12, их ровно три: 1, 7, 11
P. S. Ещё можно заметить что сумма всех корней степени n снова равна нулю, как и с комплексными числами.
P. P. S. а ещё можно в кольце вычетов по модулю простого числа найти подходящий корень из единицы и сделать преобразование Фурье на целых числах, примерно как с e(-ikw) на комплексных.
y_u_h
16.06.2025 10:17Будем анализировать DLOG как таблицу степеней
ЭтоНикогда не понимал подобных утверждений, ключевых, с которых начигаются многие нетривиальные вещи. Потому и не близок к сложной математике. Может кто пояснить, на каком основании это использовано?
mvladlin Автор
16.06.2025 10:17Дискретный логарифм (DLOG) по модулю
Пример для
для примитива
Обычно для DLOG строят таблицу логарифмов, главный минус которой - можно построить только по одному
.
Таблица степеней - это перевернутая таблица логарифмов, строка
переносится в шапку таблицы степеней и сортируется, строка
переносится вниз, а слева появляется возможность добавить колонку для
, см. рис.
таблица степеней слева, таблица логарифмов справа По идее в таблицу степеней можно добавить колонку для
но ее обычно опускают.
vened
В мультипликативном DH (FFDH) давно есть типовое требование: использовать для алгоритма циклическую подгруппу (простого) порядка (p-1)/2. Это то же самое. См., например, RFC 7919 (группы FFDH для TLS) или документы NIST 800.
mvladlin Автор
Спасибо, почитаю, не слишком ли глубоко спрятано "циклическую подгруппу (простого) порядка (p-1)/2 " и у меня в статье имеется ввиду классический DH
vened
А в упомянутых документах - как раз тоже классический. FFDH (Finite Field DH) или "мультипликативный" - это и есть классический.