Опишите шаги генерации ключей и шифрования в RSA, укажите распространённые ошибки реализации (малые показатели e, отсутствие паддинга PKCS/OAEP, слабые генераторы простых чисел) и опишите, как эти ошибки приводят к компрометации безопасности
Шаги генерации ключей и шифрования (суть, в формулах): - Случайно выбрать два больших простых числа p, q \,p,\;q\,p,q. - Вычислить модуль n=pq \,n = p q\,n=pq. - Вычислить функцию Эйлера (или показатель Ламберта): например φ(n)=(p−1)(q−1) \,\varphi(n) = (p-1)(q-1)\,φ(n)=(p−1)(q−1) (или λ(n)=lcm(p−1,q−1)\lambda(n)=\operatorname{lcm}(p-1,q-1)λ(n)=lcm(p−1,q−1)). - Выбрать публичную экспоненту e \,e\,e, такую что 1<e<φ(n) \,1 < e < \varphi(n)\,1<e<φ(n) и gcd(e,φ(n))=1\gcd(e,\varphi(n))=1gcd(e,φ(n))=1. - Вычислить секретную экспоненту d≡e−1(modφ(n)) \,d \equiv e^{-1} \pmod{\varphi(n)}\,d≡e−1(modφ(n)). - Публичный ключ: (n,e)(n,e)(n,e). Приватный ключ: (n,d)(n,d)(n,d) (обычно с дополнительными параметрами p,q,dp,dq,q−1 \,p,q,d_p,d_q,q^{-1}\,p,q,dp,dq,q−1 для ускорения CRT-расчёта). Шифрование/дешифрование: - Перед шифрованием применить паддинг к сообщению mmm (см. ниже). После паддинга получить число m∈[0,n−1]\,m\in[0,n-1]m∈[0,n−1]. - Шифротекст: c≡me(modn) \,c \equiv m^e \pmod{n}\,c≡me(modn). - Дешифрование: m≡cd(modn) \,m \equiv c^d \pmod{n}\,m≡cd(modn) (или с CRT для ускорения). Распространённые ошибки реализации и как они компрометируют безопасность 1) Малые значения публичного показателя eee (например e=3 \,e=3\,e=3 или вообще маленькие) - Уязвимости: - Если одно и то же сообщение mmm отправлено без паддинга нескольким получателям с разными модульными nin_ini и одинаковым малым eee, то по теореме Хастада можно собрать системы ci≡me(modni)c_i \equiv m^e \pmod{n_i}ci≡me(modni). С помощью CRT получить M≡me(modN)M \equiv m^e \pmod{N}M≡me(modN) с N=∏niN=\prod n_iN=∏ni. Если me<Nm^e < Nme<N, то можно взять целый eee-ый корень и восстановить mmm. - Если сообщение маленькое так что me<nm^e < nme<n, то c=mec = m^ec=me без редукции по модулю, и можно восстановить mmm вычислением m=cem=\sqrt[e]{c}m=ec. - Как предотвращать: использовать стандартное значение e=65537 \,e=65537\,e=65537 ( 216+1 \,2^{16}+1\,216+1) или другое достаточно большое простое, всегда применять стойкий паддинг (OAEP/PKCS#1 v2) перед шифрованием. 2) Отсутствие паддинга (или использование устаревшего/ошибочного паддинга) - Уязвимости: - Отсутствие паддинга делает RSA детерминированным и умножаемым: E(m1)E(m2)=E(m1m2) \,E(m_1)E(m_2)=E(m_1 m_2)\,E(m1)E(m2)=E(m1m2). Это даёт возможности для множества атак (перехват и подстановка, манипуляция сообщениями). - Неприменение современного паддинга делает возможными прямые восстановления при малых eee (см. выше) и выбранно-текстовые атаки. - Неправильно реализованные старые схемы паддинга (PKCS#1 v1.5) подвержены атакам типа Блейхенбахера — наличие побочного орaкульного ответа (например, успешная/неуспешная проверка формата) позволяет по итерациям восстановить секретный текст. - Как предотвращать: применять проверенные схемы паддинга и протоколы — RSA-OAEP (PKCS#1 v2+) для шифрования; для подписи — PSS. Не давать оракулы формат-проверки, использовать проверенные криптобиблиотеки. 3) Слабые генераторы простых чисел / плохая энтропия - Уязвимости: - Повторное использование тех же простых в разных ключах: если два модуля n1=n2=pq1n_1=n_2=pq_1n1=n2=pq1 и n2=pq2n_2=pq_2n2=pq2 имеют общий простой множитель ppp, то gcd(n1,n2)=p\gcd(n_1,n_2)=pgcd(n1,n2)=p и ключи фактически ломаются мгновенно. - Плохая энтропия (предсказуемые или малоразмерные случайные числа) позволяет атакующему перебрать или восстановить p,qp,qp,q по известному генератору/примитиву или по словарю — результат: факторизация nnn. - Слишком маленькие простые или простые, близкие друг к другу (если ∣p−q∣|p-q|∣p−q∣ маленькое) — эффективна факторизация Ферма: берут a=⌈n⌉a=\lceil\sqrt{n}\rceila=⌈n⌉, ищут b2=a2−nb^2=a^2-nb2=a2−n. - Специальные свойства p−1p-1p−1 или q−1q-1q−1 (очень гладкие числа) делают возможным Pollard p-1 атаку. - Как это компрометирует: знание либо восстановление одного простого делителя даёт немедленный доступ к приватному ключу (факторизация nnn позволяет восстановить φ(n)\varphi(n)φ(n) и ddd). Плохой RNG в прошлом приводил к миллионам уязвимых ключей (пример: Debian OpenSSL). - Как предотвращать: использовать криптографически стойкие генераторы случайных чисел, проверять уникальность/primality (Miller–Rabin с достаточным числом итераций), гарантировать минимальную разницу по длине и статистическую независимость p,qp,qp,q, проверять, что ни одно случайное ppp не употребляется повторно. Короткие дополнительные замечания (часто встречуются) - Малый приватный показатель ddd (не в списке, но часто встречается) — уязвим к атаке Винера, если d<n0.25d < n^{0.25}d<n0.25. - Всегда хранить приватный ключ защищённо, применять механизмы защиты от боковых каналов при вычислениях (CRT без защиты даёт утечки по времени/электромагнитным/ошибочным подсказкам). Резюме (практические предписания) - Генерируйте p,qp,qp,q с крипто-RNG и полноценно проверяйте простоту. - Используйте e=65537 \,e=65537\,e=65537 или эквивалент и убедитесь, что gcd(e,φ(n))=1\gcd(e,\varphi(n))=1gcd(e,φ(n))=1. - Обязательно применять OAEP (для шифрования) и PSS (для подписей); не используйте "сырой" RSA. - Проверяйте ключи на коллизии (gcd с другими модулями), достаточную длину и отсутствие слабых свойств (слишком близкие p и q, гладкость p-1/q-1).
- Случайно выбрать два больших простых числа p, q \,p,\;q\,p,q.
- Вычислить модуль n=pq \,n = p q\,n=pq.
- Вычислить функцию Эйлера (или показатель Ламберта): например φ(n)=(p−1)(q−1) \,\varphi(n) = (p-1)(q-1)\,φ(n)=(p−1)(q−1) (или λ(n)=lcm(p−1,q−1)\lambda(n)=\operatorname{lcm}(p-1,q-1)λ(n)=lcm(p−1,q−1)).
- Выбрать публичную экспоненту e \,e\,e, такую что 1<e<φ(n) \,1 < e < \varphi(n)\,1<e<φ(n) и gcd(e,φ(n))=1\gcd(e,\varphi(n))=1gcd(e,φ(n))=1.
- Вычислить секретную экспоненту d≡e−1(modφ(n)) \,d \equiv e^{-1} \pmod{\varphi(n)}\,d≡e−1(modφ(n)).
- Публичный ключ: (n,e)(n,e)(n,e). Приватный ключ: (n,d)(n,d)(n,d) (обычно с дополнительными параметрами p,q,dp,dq,q−1 \,p,q,d_p,d_q,q^{-1}\,p,q,dp ,dq ,q−1 для ускорения CRT-расчёта).
Шифрование/дешифрование:
- Перед шифрованием применить паддинг к сообщению mmm (см. ниже). После паддинга получить число m∈[0,n−1]\,m\in[0,n-1]m∈[0,n−1].
- Шифротекст: c≡me(modn) \,c \equiv m^e \pmod{n}\,c≡me(modn).
- Дешифрование: m≡cd(modn) \,m \equiv c^d \pmod{n}\,m≡cd(modn) (или с CRT для ускорения).
Распространённые ошибки реализации и как они компрометируют безопасность
1) Малые значения публичного показателя eee (например e=3 \,e=3\,e=3 или вообще маленькие)
- Уязвимости:
- Если одно и то же сообщение mmm отправлено без паддинга нескольким получателям с разными модульными nin_ini и одинаковым малым eee, то по теореме Хастада можно собрать системы ci≡me(modni)c_i \equiv m^e \pmod{n_i}ci ≡me(modni ). С помощью CRT получить M≡me(modN)M \equiv m^e \pmod{N}M≡me(modN) с N=∏niN=\prod n_iN=∏ni . Если me<Nm^e < Nme<N, то можно взять целый eee-ый корень и восстановить mmm.
- Если сообщение маленькое так что me<nm^e < nme<n, то c=mec = m^ec=me без редукции по модулю, и можно восстановить mmm вычислением m=cem=\sqrt[e]{c}m=ec .
- Как предотвращать: использовать стандартное значение e=65537 \,e=65537\,e=65537 ( 216+1 \,2^{16}+1\,216+1) или другое достаточно большое простое, всегда применять стойкий паддинг (OAEP/PKCS#1 v2) перед шифрованием.
2) Отсутствие паддинга (или использование устаревшего/ошибочного паддинга)
- Уязвимости:
- Отсутствие паддинга делает RSA детерминированным и умножаемым: E(m1)E(m2)=E(m1m2) \,E(m_1)E(m_2)=E(m_1 m_2)\,E(m1 )E(m2 )=E(m1 m2 ). Это даёт возможности для множества атак (перехват и подстановка, манипуляция сообщениями).
- Неприменение современного паддинга делает возможными прямые восстановления при малых eee (см. выше) и выбранно-текстовые атаки.
- Неправильно реализованные старые схемы паддинга (PKCS#1 v1.5) подвержены атакам типа Блейхенбахера — наличие побочного орaкульного ответа (например, успешная/неуспешная проверка формата) позволяет по итерациям восстановить секретный текст.
- Как предотвращать: применять проверенные схемы паддинга и протоколы — RSA-OAEP (PKCS#1 v2+) для шифрования; для подписи — PSS. Не давать оракулы формат-проверки, использовать проверенные криптобиблиотеки.
3) Слабые генераторы простых чисел / плохая энтропия
- Уязвимости:
- Повторное использование тех же простых в разных ключах: если два модуля n1=n2=pq1n_1=n_2=pq_1n1 =n2 =pq1 и n2=pq2n_2=pq_2n2 =pq2 имеют общий простой множитель ppp, то gcd(n1,n2)=p\gcd(n_1,n_2)=pgcd(n1 ,n2 )=p и ключи фактически ломаются мгновенно.
- Плохая энтропия (предсказуемые или малоразмерные случайные числа) позволяет атакующему перебрать или восстановить p,qp,qp,q по известному генератору/примитиву или по словарю — результат: факторизация nnn.
- Слишком маленькие простые или простые, близкие друг к другу (если ∣p−q∣|p-q|∣p−q∣ маленькое) — эффективна факторизация Ферма: берут a=⌈n⌉a=\lceil\sqrt{n}\rceila=⌈n ⌉, ищут b2=a2−nb^2=a^2-nb2=a2−n.
- Специальные свойства p−1p-1p−1 или q−1q-1q−1 (очень гладкие числа) делают возможным Pollard p-1 атаку.
- Как это компрометирует: знание либо восстановление одного простого делителя даёт немедленный доступ к приватному ключу (факторизация nnn позволяет восстановить φ(n)\varphi(n)φ(n) и ddd). Плохой RNG в прошлом приводил к миллионам уязвимых ключей (пример: Debian OpenSSL).
- Как предотвращать: использовать криптографически стойкие генераторы случайных чисел, проверять уникальность/primality (Miller–Rabin с достаточным числом итераций), гарантировать минимальную разницу по длине и статистическую независимость p,qp,qp,q, проверять, что ни одно случайное ppp не употребляется повторно.
Короткие дополнительные замечания (часто встречуются)
- Малый приватный показатель ddd (не в списке, но часто встречается) — уязвим к атаке Винера, если d<n0.25d < n^{0.25}d<n0.25.
- Всегда хранить приватный ключ защищённо, применять механизмы защиты от боковых каналов при вычислениях (CRT без защиты даёт утечки по времени/электромагнитным/ошибочным подсказкам).
Резюме (практические предписания)
- Генерируйте p,qp,qp,q с крипто-RNG и полноценно проверяйте простоту.
- Используйте e=65537 \,e=65537\,e=65537 или эквивалент и убедитесь, что gcd(e,φ(n))=1\gcd(e,\varphi(n))=1gcd(e,φ(n))=1.
- Обязательно применять OAEP (для шифрования) и PSS (для подписей); не используйте "сырой" RSA.
- Проверяйте ключи на коллизии (gcd с другими модулями), достаточную длину и отсутствие слабых свойств (слишком близкие p и q, гладкость p-1/q-1).