Длина симметричного ключа, бит
|
Длина несимметричного ключа, бит
|
56
|
384
|
64
|
512
|
80
|
768
|
112
|
1792
|
128
|
2304
|
) Процесс шифрования-расшифрования с
использованием пары ключей проходит на два-три порядка медленнее, чем
шифрование-расшифрование того же текста симметричным алгоритмом.
) В чистом виде асимметричные
криптосистемы требуют существенно больших вычислительных ресурсов, потому на
практике используются в сочетании с другими алгоритмами.
) Для ЭЦП сообщение предварительно
подвергается хешированию, а с помощью асимметричного ключа подписывается лишь
относительно небольшой результат хеш-функции.
) Для шифрования они используются в
форме гибридных криптосистем, где большие объёмы данных шифруются симметричным
шифром на сеансовом ключе, а с помощью асимметричного шифра передаётся только
сам сеансовый ключ.
Также метод, который я здесь
рассматриваю, требует термина дискретное логарифмирование где:
Дискретное
логарифмирование (DLOG) - задача обращения функции в
некоторой конечной мультипликативной группе .
Наиболее часто задачу
дискретного логарифмирования рассматривают в мультипликативной группе
кольца вычетов или конечного поля, а также в группе точек эллиптической
кривой над конечным полем. Эффективные алгоритмы для решения задачи дискретного
логарифмирования в общем случае неизвестны.
Для заданных g
и a решение x уравнения gx=a
называется дискретным логарифмом элемента a по
основанию g. В случае, когда G является мультипликативной
группой кольца вычетов по модулю m, решение называют также индексом
числа a по основанию g. Индекс числа a по
основанию g гарантированно существует, если g является
первообразным корнем по модулю m.
1. Способы использования
и алгоритмы
Свойства и методы
формирования криптопараметров и оценка стойкости.
Также для данной темы
нам нужно оперировать сильными простыми числами рассмотрим что это такое:
Иногда также добавляют
дополнительные условия, например a1=1, a2=2 и т.п.
Такие числа часто
используются в разных принципах криптографии.
Я предлагаю для данной
работы использовать алгоритм, в котором мы, выбрав изначальное q, мы будем
домножать его на другое случайное число и прибавлять единицу и проверять на
простоту получившееся число.
Также мы должны ввести
проверку GNFS:
Exp(((64/9)1/3+o(1))
(log n)1/3 (log log n)2/3)=Ln[1/3, (64/9)1/3]
Полученное число будет
одним из критериев криптостойкости.
В случае реализации
подписи Шнорра важным параметром стойкости будет число t о котором будет
упомянуто позже.метод Полларда - алгоритм разложения натурального числа на
простые множители. Предложен Джоном Поллардом в 1974 году. Алгоритм
предназначен для нахождения простых делителей p, у которых p-1 хорошо
раскладывается на множители, то есть имеет небольшой максимальный простой
делитель. Если обозначить этот максимальный простой делитель ,
то алгоритм требует(B log B log2N) действий. Метод очень быстро
находит простые факторы малой и средней величины (до 20-25 десятичных цифр).
1.1 Криптографические
хэш-функции
Поскольку подписываемые
документы - переменного (и как правило достаточно большого) объёма, в схемах ЭП
зачастую подпись ставится не на сам документ, а на его хеш. Для вычисления хэша
используются криптографические хеш-функции, что гарантирует выявление изменений
документа при проверке подписи. Хеш-функции не являются частью алгоритма ЭП,
поэтому в схеме может быть использована любая надёжная хеш-функция.
Использование
хеш-функций даёт следующие преимущества:
1. Вычислительная сложность.
Обычно хеш цифрового документа делается во много раз меньшего объёма, чем объём
исходного документа, и алгоритмы вычисления хеша являются более быстрыми, чем
алгоритмы ЭП. Поэтому формировать хэш документа и подписывать его получается
намного быстрее, чем подписывать сам документ.
2. Совместимость. Большинство
алгоритмов оперирует со строками бит данных, но некоторые используют другие
представления. Хеш-функцию можно использовать для преобразования произвольного
входного текста в подходящий формат.
. Целостность. Без
использования хеш-функции большой электронный документ в некоторых схемах нужно
разделять на достаточно малые блоки для применения ЭП. При верификации
невозможно определить, все ли блоки получены и в правильном ли они порядке.
Стоит заметить, что использование
хеш-функции не обязательно при электронной подписи, а сама функция не является
частью алгоритма ЭП, поэтому хеш-функция может использоваться любая или не
использоваться вообще.
1.2 Методы и алгоритмы
формирования рабочих ключей
Генератор псевдослучайных чисел
(ГПСЧ, Pseudorandom number generator, PRNG) - алгоритм, генерирующий последовательность
чисел, элементы которой почти независимы друг от друга и подчиняются заданному
распределению (обычно равномерному).
И часто используются в криптографии.
При этом от качества используемых ГПСЧ напрямую зависит качество получаемых
результатов. Это обстоятельство подчёркивает известный афоризм Роберта Р.
Кавью: «генерация случайных чисел слишком важна, чтобы оставлять её на волю
случая».
Обычно используется создание
некоторого набора из большого количества случайных чисел и опубликование его в
некотором «словаре». Тем не менее, и такие наборы обеспечивают очень
ограниченный источник чисел по сравнению с тем количеством, которое требуется
приложениям сетевой безопасности. Хотя данные наборы действительно обеспечивают
статистическую случайность, они не достаточно случайны, так как противник может
получить копию словаря.
Генератор псевдослучайных чисел
включён в состав многих современных процессоров (напр., семейства х86)
Криптографические приложения
используют для генерации случайных чисел особенные алгоритмы. Эти алгоритмы
заранее определены и, следовательно, генерируют последовательность чисел,
которая теоретически не может быть статистически случайной. В то же время, если
выбрать хороший алгоритм, полученная численная последовательность будет проходить
большинство тестов на случайность. Такие числа называют псевдослучайными
числами.
Возведение в степень по модулю
возведение в степень по модулю
целого числа, т.е.
М=Cd (mod N).
Прежде всего отметим,
что не имеет смысла сначала находить R =, а потом определять его
остаток от деления на N. Действительно, поступая таким образом при вычислении
5
(mod 511) = 28153056843 (mod 511) = 359,
мы получаем большой
промежуточный результат - 28153056843. В реальной ситуации, когда возводятся в
степень числа с 1024 двоичными знаками, промежуточный результат будет иметь 21024•
1024 знаков. Только для записи таких чисел потребуется около 1031
гигабайт на винчестере.
Чтобы промежуточные
результаты не были столь огромны, необходимо вспомнить, что мы работаем по
модулю N. Но даже при этом стоит быть внимательным. Наивный подход к решению
нашей задачи привел бы к следующим вычислениям:
х = 123,2 =
х·х (mod 511) = 310,3= х·x2(mod 511) = 316,4 =
х·x3(mod 511) = 32,5 = х·x4(mod 511) = 359.
На это уходит 4
умножения в кольце вычетов, что кажется приемлемым для нашего игрушечного
примера. Но в общем случае, при возведении в 1024-разрядную степень потребуется
около 21024 таких умножений. Если каждое произведение при этом
осуществляется за 1 миллионную долю секунды, нам потребуется 10294
лет на осуществление операции расшифрования в алгоритме RSA.
Однако даже на нашем
небольшом примерчике легко увидеть, как можно было бы сократить количество
умножений:
х = 123,2=
х·х (mod 511) =310,4=x2*x2 (mod 511) =32,5=
x·x4(mod 511) =359.
Здесь нам потребовалось
только три произведения, а не 4, как раньше. Обратите внимание на то, что
двоичное представление числа 5 имеет вид: '101b', т.е.
это трехзначное число,
его вес Хемминга равен h
= 2. (где вес Хемминга кол-во 1 в бинарном представлении числа)
Поэтому мы произвели 1 =
h - 1 умножение общего вида и 2 = t - 1 возведения в квадрат. Такой подсчет
остается справедливым и в общем случае: возведение в степень по модулю целого
числа может быть осуществлено с помощью h - 1 умножений и t - 1 возведения в
квадрат,
где t - количество
знаков в двоичном представлении показателя, a h - его вес Хемминга. Усредненный
вес Хемминга целого числа равен половине количества его двоичных знаков, т.е.
t/2. Поэтому среднее число умножений и возведений в квадрат при вычислении
экспоненты в кольце вычетов равно t + t/2 - 1. Это означает, что при возведении
в 1024-битовую степень потребуется не более 2048 умножений, а среднее число
операций и того меньше - 1535.
Метод, с помощью
которого достигается такая экономия операций носит специальное название: метод
двоичного потенцирования. Работает он, поочередно считывая знаки двоичного
представления показателя, начиная с младшего разряда.
1.3 Формирование и
проверка ЭЦП
Выбор параметров
системы:
Выбирается простое p и
простое q, такое, что q|p-1 (p≈21024, q>=2130)
Выбирается элемент β,
такой, что βq=1 (mod p)
Параметры (p, q,
β) свободно публикуются
Выбирается параметр t,
t>40 q<2t (t-уровень секретности)
Выбор параметров доказывающей
стороны
Пусть каждая
доказывающая сторона A выбирает секрет a (закрытый ключ), такой, что
1<=a<=q-1 и вычисляет v=β-q(mod
p), где v-открытый ключ.
Передаваемые сообщения:B:
x=βr(mod p)B:
e (где 1<=e<=2t<q)B: y=(a*e+r) (mod q)
Основные
действиявыбирает случайное r (1<r<q-1), вычисляет x=βr(mod
p) и отсылает x стороне B (доказательство)
Сторона B отсылает
случайное e из диапазона от 1 до q-1 (вызов)возвращает B y=(a*e+r) (mod
q)проверяет, действительно ли z=x, где z= βr*ve(mod
p) и, если это так, то идентификация считается успешной.
Пример:
Выбирается простое
р=48731 и простое q=443 ()
Вычисляется β
из условия βq=1 (mod p), в данном случае β=11444
Тогда системными
параметрами будут (48731,443,11444), a t=8
Сторона А выбирает
закрытый ключ a=357 и вычисляет открытый ключ v=β-a(mod
p)=7355
Сторона А случайным
образом выбирает доказательство r=274 и отсылает x=βr(mod
p)= 37123 стороне B
В отсылает A вызов
e=129отсылает B y=(a*e+r) (mod q)=255вычисляет z= βr*ve(mod
p) =37123 и идентифицирует A, так как z=x
Моделирование для
цифровой подписи:
Пусть сторона A хочет
отправить сообщение М стороне B; причем B должен убедиться в том, что сообщение
пришло именно от A. Тогда:выбирает случайное r (), вычисляет x=βr(mod
p)
Пусть имеется
однонаправленная хеш-функция H(M). Сторона А объединяет M с x и хеширует
результат e=(M, x)
Далее A вычисляет
y=(a*e+r) (mod q). Значения e и y являются цифровой подписью и отсылаются
B.вычисляет z= βr*ve(mod p). Затем z и полученное сообщение M'
пропускаются через хеш-функцию: e’=H (M’, x). Если e=e’, то подпись считается
верной.
В данной курсовой работе
была представлена реализация эцп по методу Шнорра.
2. Описание программы
2.1 Общие сведения
шнорр криптографический
подпись хеш
В данной курсовой работе
реализована упрощенная модель электронной цифровой подписи файла с
использованием метода Шнорра. В качестве хеш-значения в учебных целях
используем несложную контрольную сумму СRC-32.
Программа, которая
называется «Shnorr» реализована как консольное приложение на языке С++ и
откомпилирована в среде MicrosoftVisualStudio 2010.
Она была реализована на
операционной системе MS Windows 7 Home Edition. Программа функционирует на
любой операционной системе типа Windows.
2.2 Функциональное
назначение программы
Назначение программы состоит в
вычислении ЭЦП для определенного файла. Подробное описание назначения ЭЦП
приведено в подразделе 1.2. Также для вычисления ЭЦП нам нужна хеш функция
описанная в разделе 1.3.
2.3 Описание логической
структуры
Для реализации нам понадобятся такие
функции как: функция возведения в степень по модулю(Power), функция
Рабина-Миллера для проверки числа на простоту(NoPrime), функция вычисления
инверсного элемента(InversElem), функция нахождения НОД(NOD), функция сравнения
которая нужна для оригинальной функции факторизации р-Поларда(Sravn), сама
функция факторизации(Factor), функция для убеждения в том что число является
сильным простым числом(GetQ), функция для генерации открытых
параметров(GenOpenParam), функция генерации параметров подписываемой
стороны(GetKeyA), Функция подписывания(Sign), Функция проверки
підписи(ChekSign), общая функция(main).
Программа была написана на компютере
с такими параметрами: процессор Intel Core i3, мощностью 2.2 GHz и 2.2 GHz, 4
Гб ОЗУ. Програма может быт отложена на любом современном компютере.
2.5 Запуск. Входные и
выходные данные
Программа запускается с диска с
помощью файла Shnorr.exe.
В меню, которое выводится на экран,
четыре пункта. При вводе 1 выводится генерация случайных простых ключевых
параметров. При вводе 2 генерирует параметры стороны А. При вводе 3 программа
подписывает файл, название которого надо ввести. При вводе 4 программа
выполняет проверку подписи файла, для которого эта подпись генерировалась при
вводе 3. Для этого нужно опять ввести название того же файла и на экране
отобразится результат проверки: Sign is WRONG!! подпись не прошла проверку и
Sign is OK! если подпись верная.
Перечень ссылок
1. Шнайер Б. Прикладная криптография. Протоколы, алгоритмы,
исходные тексты на языке Си - М.: Триумф, 2002. - С. 296-300. - 816 с.
2. Горбенко І.Д., Гріненко Т.О. Захист інформації в
інформаційно-телекомунікаційних системах: Навчальний посібник. Частина 1:
Криптографічний захист інформації) - Харків. ХНУРЕ, 2004. - 376 с.
3. ДСТУ 3008-95 «ЗВІТИ У СФЕРІ НАУКИ І ТЕХНІКИ. Структура та
правила оформлення».
4. ГОСТ 19.701 - 90. ЕСПД. Схемы алгоритмов, программ, данных
и систем. Условные обозначения и правила выполнения.
Приложение А
// ЭЦП Шнорра
#include <iostream>
#include <conio.h>
#include <time.h>
#include «CRC32.h»
#pragma comment (lib, «CRC32.lib»)
#define MFILE «general.key» // файлы
для параметров, ключей и подписи будут стандартными
#define AFILE «personal.key»
#define SFILE «sign.key»
using namespace std;Power
(unsigned int X, unsigned int Pow, unsigned int &Y, unsigned int Mod) // ф-ция побитового возведения в степень по
модулю.
{i;__int64 time;(Pow==0) // если
степнь 0, то результат == 1
{=1;;
}if (Pow==1) // если степнь 1, то
результат без изменений
{=X % Mod;;
}=X % Mod;(i=31;!
(Pow&(1<<i)) && i>=0; i-); // в таком цикле находим самый
старгий еденичный бит- ; // и берём следующий, т.к. по алгоритму с него надо
начтинать(; i>=0; i-)
{=Y;*=time; // на каждой итерации
возводим результат в квадрат=time % Mod;(Pow&(1<<i)) // а если ещё и
текущий бит ==, то и умножаем на Х (всё это тупо по алгоритму)
{=Y;*=X;=time % Mod;
}
}
}NoPrime (unsigned int Ch) // ф-ция
Рабина-Миллера проверки числа на проостоту
{int rez, a, pow_2 (0), coef
(Ch-1);((Ch==2) || (Ch==3) || (Ch==5) || (Ch==7) || (Ch==11))0;Flag;// с
помощью этого цикле мы представляем число Ch-1 = 2^pow_2 * coef
{/=2;_2+=1;
} while (! (coef&1));(int i=0;
i<100; i++) // для достаточной точности выбрак параметр к=100, тогда
вероятность ошибки = (1/4)^100
{ // тупо по алгоритму:
{= ((rand()<<16) |
rand())%(Ch-1); // выбираем случайное а
} while (! a);(a, coef, rez, Ch); //
возводим в степень, полученную ранее((rez == 1) || (rez == Ch-1)) // и если
результат сравним с 1 или -1, то число вероятно простое, идём на след
итерацию;=1;(int j=0; j<(pow_2-1); j++) // иначе должно найтись хотя бы одно
такое i Є (1, pow+2-1), что a^(2^i) == 1 по модулю Р.
{(rez, 2, rez,
Ch);(rez==1)1;(rez==(Ch-1))
{=0;;
}
}(Flag) // если такое i ни разу не
встретилось, то число составное1;
}0;
}InversElem (unsigned int Fn,
unsigned int E, unsigned int &D) // ф-ция вычисляет обратный эл-т (D) для
(E) методом цепных дробей
{int r, s, a=Fn, b=E,
ai[3]={0,1};M(-1); // кол-во итераций
{=a/b;=a % b;[2]=r*ai[1]+ai[0]; //
находим текущее а[0]=ai[1]; // записываем предыдущее а в
пре-предыдущее[1]=ai[2];=b; // записываем числитель=s; // записываем
знаменаткль
++M; // наращиваем итерации
} while (s); // до тех пор, пока
есть остаток(a!=1) // если последний знаменатель НЕ 1 (т.е. НОД (Fn, D)!=1)1;(M
% 2==0)=ai[0];=Fn-ai[0];0;
}
unsigned int NOD
(unsigned int m, unsigned int n, int temp=1) // http://ru.wikipedia.org/wiki/Бинарный_алгоритм_вычисления_НОД
{(! m && m)n*temp;if (m
&&! n)m*temp;if (m == n)m*temp;if((m==1) && n)1*temp;if (m
&& (n==1))1*temp;if (! (m&1)&&! (n&1))
{*=2;/=2; n/=2;(m, n, temp);
}if (! (m&1) &&
(n&1))
{/=2;(m, n, temp);
}if((m&1) &&! (n&1))
{/=2;(m, n, temp);
}if((m&1) && (n&1))
{(n>m)
{=m;
}
{=n;
}(m, n, temp);
}
}
unsigned int Sravn
(unsigned int x, unsigned int c, unsigned int Mod) //y=x^2+c (mod Mod)
{ // это сравнение нужно для
оригинального метода факторизации р-Поллардаint y;__int64 temp;= x*x;%=
Mod;+=c;%=Mod;=temp;y;
}
bool Factor (unsigned
int Mod, unsigned int &P, unsigned int &Q) // если ошибка, возвращает 1, иначе 0
{ // ф-ция разложения на множители,
но тольк она 2 множителя__int64 d, temp, x[2], y[2], c;
{=((rand()<<16) |
rand())%(Mod-1); // выбирая случайное с
} while (! c);
{[0]=((rand()<<16) |
rand())%(Mod-1); // и случайное х для начала алгоритма
{[1]=Sravn (x[0], c, Mod); // на каждой итерации х_i=f
(x_(i-1))[0]=x[1]; // f(x) - это и есть ф-ция Sravn()[1]=Sravn (y[0], c, Mod);
// а y_i=f (f(y_(i-1)))[1]=Sravn (y[1], c, Mod);[0]=y[1];(x[1]>y[1])=x[1] -
y[1];=y[1] - x[1];=NOD (Mod, temp); // п оалгоритму надо назодить НОД разности
х и у текущих(d==Mod) // это если Mod - простое1;
} while (d==1);=d;=Mod/P;0;
}
void GetQ (unsigned int
P, unsigned int &q)
{int p1, p2; // зная Р, находим для него q, такое что q|Р-1Err;
{= Factor (P, p1, p2); // на каждой итерации факторизируем число=
(p1>p2)? p1:p2; // и выбираем наибольшее из результатов
} while (! Err); // до тех пор пока не получим простое= P; // его
и принимаем за q
}
void GenOpenParam
(unsigned int &P, unsigned int &q, unsigned int &b)
{int temp;
{
{= (rand()<<16) | rand(); // снчала находим просто простое
число
} while (NoPrime(P));*= 2, P += 1; // потом по условию сильного
протсого
} while (NoPrime(P));(P, q);(b = P-1; b>=1; b-) // а бету
находим методом перебора
{(b, q, temp, P);(temp == 1);
}
}
void GetKeysA (unsigned
int P, unsigned int q, unsigned int b, unsigned int &a, unsigned int
&v)
{ // генерация ключей для А-абонентаint temp;
{= (rand()<<16) | rand();
} while (! a);(b, a, temp, P);(P, temp, v);
}
void Sign (unsigned int
P, unsigned int q, unsigned int b, unsigned int a, FILE* File, unsigned int
&e, unsigned int &y)
{ // ф-ция подписыванияint r, x;__int64 temp;char *S;FileLen;
{= (rand()<<16) | rand();
} while (! r);(b, r, x, P);(File, 0, SEEK_END); // ставим указатель
в конец файла= ftell(File); // находим его позицию в байтах (таким образом и
длину самого файла)(File, 0, SEEK_SET); // и возвращаемся обратно в начало= new
unsigned char [FileLen + 4]; // 4 доп байта для слеивания строки с x(S+4,
sizeof (unsigned char), FileLen, File);[0] = (x >> 3*8) & 0xff; //
вот ттаким образом склеиваем строку со значением x[1] = (x >> 2*8) &
0xff;[2] = (x >> 1*8) & 0xff;[3] = (x >> 0*8) & 0xff;=
CRC32Count (S, (FileLen+4)); // и находим хэш функцию от неё= a*e;%= q;+= r;%=
q;= temp;[] S;
}
bool CheckSign (unsigned
int P, unsigned int b, unsigned int v, unsigned int e, unsigned int y, FILE*
File)
{ // почти то же, что и при подписывании__int64 temp;int Rez1,
Rez2, z, FileLen, e1;char *S;(b, y, Rez1, P);(v, e, Rez2, P);= Rez1*Rez2;%= P;=
temp;(File, 0, SEEK_END);= ftell(File);(File, 0, SEEK_SET);= new unsigned char
[FileLen + 4];[0] = (z >> 3*8) & 0xff;[1] = (z >> 2*8) &
0xff;[2] = (z >> 1*8) & 0xff;[3] = (z >> 0*8) & 0xff;(S+4,
sizeof (unsigned char), FileLen, File);= CRC32Count (S, FileLen + 4);(e ==
e1)false;true;
}main()
{int Pr, P, q, b, a, v, e, y;*MFile, *AFile, *TFile,
*SFile;temp[512];
{<< «Enter\n1 to gen general parametrs\n2 to gen keys for
A\n3 to sign a file\n4 to check sign\n0 to exit\n»;>>Pr;.get();(Pr == 1)
{(P, q, b);= fopen (MFILE, «wb»);(&P, sizeof (unsigned int),
1, MFile);(&q, sizeof (unsigned int), 1, MFile);(&b, sizeof (unsigned
int), 1, MFile);(MFile);<< «General parametrs were gened!\n»;.get();
}(Pr == 2)
{= fopen (MFILE, «rb»);(&P, sizeof (unsigned int), 1, MFile);(&q,
sizeof (unsigned int), 1, MFile);(&b, sizeof (unsigned int), 1,
MFile);(MFile);(P, q, b, a, v);= fopen (AFILE, «wb»);(&a, sizeof (unsigned
int), 1, AFile);(&v, sizeof (unsigned int), 1, AFile);(AFile);<<
«Personal parametrs were gened!\n»;.get();
}(Pr == 3)
{<< «Enter the name of the file to sign:\n»;.getline (temp,
512);= fopen (temp, «rb»);= fopen (MFILE, «rb»);= fopen (AFILE, «rb»);(&P,
sizeof (unsigned int), 1, MFile);(&q, sizeof (unsigned int), 1,
MFile);(&b, sizeof (unsigned int), 1, MFile);(&a, sizeof (unsigned
int), 1, AFile);(P, q, b, a, TFile, e, y);(TFile); fclose(AFile);
fclose(MFile);= fopen (SFILE, «wb»);(&e, sizeof (unsigned int), 1,
SFile);(&y, sizeof (unsigned int), 1, SFile);(SFile);<< «The file was
signed!\n»;.get();
}(Pr == 4)
{<< «Enter the name of the signed file: \n»;.getline (temp,
512);= fopen (temp, «rb»);= fopen (MFILE, «rb»);= fopen (AFILE, «rb»);= fopen
(SFILE, «rb»);(&P, sizeof (unsigned int), 1, MFile);(&q, sizeof
(unsigned int), 1, MFile);(&b, sizeof (unsigned int), 1, MFile);(AFile, 4,
SEEK_SET);(&v, sizeof (unsigned int), 1, AFile);(&e, sizeof (unsigned
int), 1, SFile);(&y, sizeof (unsigned int), 1, SFile);(CheckSign (P, b, v,
e, y, TFile))<< «The sign is WRONG!\n»;<< «The sign is correct!\n»;.get();(TFile);
fclose(MFile); fclose(AFile); fclose(SFile);
}
} while (Pr);
}