
- •П.А. Приставка а.А. Ракитский Криптографические методы защиты информации
- •Введение
- •Алгоритм быстрого возведения числа в степень по модулю
- •Элементы теории чисел
- •Система Диффи-Хеллмана
- •Шаг младенца, шаг великана
- •Шифр Шамира
- •Шифр Эль-Гамаля
- •Шифр rsa
- •Шифр Вернама
- •Электронная подпись Криптографическая хэш-функция
- •Подпись rsa
- •Подпись Эль-Гамаля
- •Подпись гост р34.10-94
- •Потоковые шифры
- •Блочные шифры
- •Ментальный покер
- •Алгоритм слепой подписи
- •Заключение
- •Список литературы
- •Криптографические методы защиты информации
Система Диффи-Хеллмана
Рассмотрим коммуникационную систему с большим числом пользователей. Перед нами стоит задача разработать метод, обеспечивающий защищённый канал связи между любой парой пользователей. Для решения этой задачи необходимо обеспечить обоих пользователей неким общим секретным ключом, который при этом не могут ни узнать, ни получить никакие другие пользователи. Именно на это и нацелена система Диффи-Хеллмана, она позволяет доказано-надёжным методом получить сгенерировать общий ключ, не используя для этого никаких вспомогательных средств.
В системе есть общие параметры, закрытые ключи пользователей (эта информация недоступна никому кроме самого пользователя) и открытые ключи пользователей (эта информация должна быть общедоступной). Рассмотрим все эти параметры подробнее. Для удобства будем считать, что из множества пользователей были выбраны два, Алиса и Боб, которые хотят получить общий ключ.
Общие параметры системы:
,
где
простые числа. Число
так же называется числом Софи Жермен,
число
называют безопасным простым числом.
Использование безопасных простых чисел
в данной системе особенно важно, так
как существуют подходы для вычисления
дискретного логарифма, время работы
которых зависит от величины наибольшего
делителя функции Эйлера
.
Если
безопасное простое, мультипликативная
группа чисел по модулю
имеет подгруппу высокого порядка.
первообразный
корень по модулю
.
Это такое целое число, что:
и
.
Другими словами, первообразный корень
— это образующий элемент мультипликативной
группы кольца вычетов по модулю
.
Закрытые
ключи: это произвольные целые числа
Открытые
ключи:
Алгоритм работы системы:
Разработчик системы генерирует общие данные
согласно всем описанным выше требованиям.
Абоненты Алиса(А) и Боб(Б) формируют свои закрытые ключи
и вычисляют на их основе открытые ключи
.
Алиса вычисляет общий секретный ключ по формуле:
Боб вычисляет общий секретный ключ по формуле:
Ключи
,
полученные по этому алгоритму будут
равны, доказательство можно найти в
[1].
При разработке такой системы необходимо в первую очередь научиться генерировать общие параметры. Обычно речь идёт о достаточно больших числах, поэтому для генерации безопасного простого числа необходимо уметь быстро проверять число на простоту. Для этого отлично подходят статистические тесты, которые позволяют утверждать, что число является простым с некоторой заданной вероятностью. Кроме того, необходимо генерировать первообразный корень, однако с учётом свойств числа , эта задача на порядок проще.
Для
генерации первообразного корня
воспользуемся тем утверждением, что
если
безопасное простое число, то первообразным
корнем поля по модулю
будет любое число
,
для которого выполняются условия
.
Более того, утверждается, что таких
чисел достаточно много, и даже если
просто перебирать все числа начиная с
2, то достаточно быстро встретится
подходящее.
Методы проверки на простоту
Согласно
малой теореме Ферма можно утверждать,
что если для какого-то числа
выполняется условие
,
то число
является составным. Исходя из данного
утверждения, можно легко разработать
тест Ферма для проверки на простоту,
который на языке С++ выглядит следующим
образом:
bool testFerma(long long p, int k)
{
if(p==2) return true;
if(p&1) return false;
for(int i=0; i<k; ++i)
{
long long a=rand()%(P-1)+1;
if(gcd(a,p)!=1 || powMod(a,p-1,p)!=1)
return false;
}
return true;
}
Здесь
gcd(a,b)
– функция нахождения наибольшего общего
делителя, а powMod(a,b,p)
– функция быстрого возведения в степень
по модулю. Взяв случайное число
,
мы проверяем утверждение: если
или
,
тогда
– гарантированно составное число и
проверку можно прекратить. Иначе с
вероятностью 50% число может быть как
простым, так и составным. Таким образом,
выполнив k
независимых проверок, мы получим
вероятность того, что число составное
.
Тем не менее, важно отметить, что
существуют псевдопростые числа, которые
успешно проходят тест Ферма, они
называются числами Кармайкла. Отчасти
их можно отсечь за счёт проверки
наибольшего общего делителя, но такая
проверка не имеет хорошего теоретического
обоснования вероятности отсечения,
поэтому необходимо рассмотреть и другие
тесты.
На практике чаще всего применяется тест Миллера-Рабина, он реализован во многих языках программирования и включен в стандартные библиотеки. Теоретическое описание теста можно найти, например, по ссылке: https://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%81%D1%82_%D0%9C%D0%B8%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_%E2%80%94_%D0%A0%D0%B0%D0%B1%D0%B8%D0%BD%D0%B0 . Представим здесь реализацию теста Миллера-Рабина на языке программирования C#:
public bool MillerRabinTest(BigInteger n, int k)
{
if (n == 2 || n == 3)
return true;
if (n < 2 || n % 2 == 0)
return false;
// представим n-1 в виде (2^s)·t, где t нечётно, это можно сделать последовательным делением n - 1 на 2
BigInteger t = n - 1;
int s = 0;
while (t % 2 == 0)
{
t /= 2;
s += 1;
}
for (int i = 0; i < k; i++)
{
// выберем случайное целое число a в отрезке [2, n-3]
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] _a = new byte[n.ToByteArray().LongLength];
BigInteger a;
do
{
rng.GetBytes(_a);
a = new BigInteger(_a);
}
while (a < 2 || a >= n - 2);
// x ← a^t mod n, вычислим с помощью возведения в степень по модулю
BigInteger x = BigInteger.ModPow(a, t, n);
// если x == 1 или x == n-1, то перейти на следующую итерацию цикла
if (x == 1 || x == n - 1)
continue;
// повторить s - 1 раз
for (int r = 1; r < s; r++)
{
x = BigInteger.ModPow(x, 2, n);
// если x == 1, то вернуть "составное"
if (x == 1)
return false;
// если x == n -1, то перейти на следующую итерацию внешнего цикла
if (x == n - 1)
break;
}
if (x != n - 1)
return false;
}
// вернуть "вероятно простое"
return true;
}
После
выполнения k
раундов теста, мы можем утверждать, что
число составное с вероятностью не более
.