Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Практическая криптография алгоритмы и их программирование

.pdf
Скачиваний:
0
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
Глава 3. Дешифрование классических шифров 51
while (!feof(f)) {
int r = fread(buf, 1, sizeof(buf), f);
for(inti=0;i<r;i++) if (buf[i] < 'À' || buf[i] > 'ß')
buf[i] = 0xE0;
calc_gramm(buf, r); } fclose(f); f = fopen("etalon.h", "wt"); fprintf(f, "BIGRAMM etalon = {\n"); for(inti=0;i<40;i++) {
for(intj=0;j<40;j++)
fprintf(f, "%d, ", current.values[i][j]);
fprintf(f, "\n"); } fprintf(f, "%d };\n", current.total); fclose(f); return 0;
}
encrypt(text, len, key); printf("%s\n", text);
findkey_jakobsen(text, len, unkey);
decrypt(text, len, unkey); printf("%s\n", text);
return 0;
}
Ключ MAKE_ETALON предназначен для создания эталонной матрицы биг­рамм. На вход алгоритма будет подан тестовый файл с русским текстом достаточ­но большого объема, состоящий из заглавных букв и пробелов. Все остальные знаки будут отбрасываться при анализе. Собранные данные в виде будут автома­тически подключены к программе при следующей компиляции (для этого будет необходимо установить ключик MAKE_ETALON в ноль) в виде файла описаний etalon.h.
После того как создан эталон, переходим собственно к анализу. Тестовый пример представлен прямо в программе (переменная text функции main). Функ­ции encrypt и decrypt осуществляют соответственно зашифрование и расшифро­вание простой заменой с помощью ключевых таблиц key и unkey соответственно (см. листинг 3.19). Функция calc_gramm подсчитывает частоты биграмм в задан­ном тексте, а calc_measure выдает разницу между эталоном и рабочей матрицей таких частот.
Листинг 3.19
// использованный алфавит (укороченный в целях упрощения) // "а" маленькое играет роль пробела и заменителя всех остальных знаков unsigned char alpha[33] = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯа";
// ключ-таблица для зашифрования unsigned char key[33] = "БВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯаА";
52 Глава 3. Дешифрование классических шифров
// ключ-таблица для расшифрования unsigned char right_unkey[33] = "ЯаАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮ"; unsigned char unkey[33] = "ЕПРСТЯаАБВГДЖЗИЙКЛМНОУФХЦЧШЩЪЫЬЭЮ";
Случайный начальный ключ приведет к успеху так же, как и начальный ключ, заданный исходя из вторичной информации о шифротексте и настоящем ключе. Разница между этими двумя выборами начального ключа будет заключать­ся только во времени работы алгоритма. В первом случае время, за которое алго­ритм найдет настоящий ключ, будет намного большим, чем во втором. Поэтому, если о ключе почти ничего неизвестно, для его оптимального поиска используют частоты появления символов русского языка, располагая символы в ключе в соот­ветствии с этими частотами (рис. 3.5). Например, после сбора частот по части текста шестой главы данной книги распределение частот было следующим:
Таблица частот:
4321 == Î, 3185 == È, 3172 == Å, 2933 == Ò, 2779 == À, 2248 == Ñ, 2209 == Í, 1858 == Â, 1568 == Ð, 1561 == Ë, 1520 == Ì, 1173 == Ê, 1128 == Ä, 989 == Ï, 890 == ß, 709 == Û, 700 == Ó, 640 == Ü, 620 == ×, 611 == Á, 572 == Ç, 497 == Ã, 416 == Æ, 393 == É, 294 == Õ, 268 == Þ, 227 == Ô, 206 == Ù, 201 == Ö, 153 == Ø, 121 == Ý, 8 == Ú
Êëþ÷:
ОИЕТАСНВРЛМКДПЯЫУ...ЭЪ
Ðèñ. 3.5
Конечно, в случае простой моноалфавитной замены можно было бы восполь­зоваться и простым частотным анализом. Но, во-первых, для коротких сообщений простой частотный анализ неэффективен, а, во-вторых, прибегнув к небольшой модификации алгоритма, мы получаем способ вскрывать полиалфавитные шиф­ры. Вдобавок сам метод частотного анализа может быть составной частью алго­ритма Якобсена. Для этого достаточно заменить целевую функцию, подсчитываю­щую разность между частотами биграмм, на функцию, возвращающую разницу между частотами появления одиночных символов. Менее эффективно, но более быстро и требует значильно меньше памяти в случае очень больших алфавитов.
Тем не менее, несмотря на возможную оптимизацию, алгоритм из листинга
3.1 достаточно медлителен. Ведь каждый раз изменяя ключ, мы должны заново вычислить матрицу (D
) и разность между ней и эталоном (Eij), которая только в
ij
случае биграмм имеет размерность 256 × 256 = 65536 элементов. Вообще говоря, это и должно быть всегда именно так, поскольку, изменяя ключ, мы изменяем способ расшифрования и соответственно получаем совершенно другой дешифро­ванный открытый текст. Однако в случае шифров простой замены мы меняем ключ, лишь переставляя в нем элементы. Фактически это означает, что в табли­це-ключе мы переставляем элементы нижней строки (см. рис. 3.4).
Если приглядеться внимательнее, можно увидеть, что тем самым мы также переставляем строки и столбцы в матрице, которую при этом больше никак не из­меняем. Это означает, что можем не подсчитывать матрицу (D
) каждый раз, за-
ij
менив вызов calc_gramm в цикле функции findkey_jakobsen в программе листинга
Глава 3. Дешифрование классических шифров 53
3.18 на быструю перестановку строк и столбцов с помощью нескольких вызовов memcpy (cм. листинг 3.20).
Листинг 3.20
long buf[1024];
memcpy(buf, &D[i][0], sizeof(long)*256); memcpy(&D[i][0], &D[j][0], sizeof(long)*256); memcpy(&D[j][0], buf, sizeof(long)*256);
Еще одним недостатком подобных алгоритмов (в том числе и только что рас­смотренного, если пробовать применять его для случая шифров гаммирования) является то, что для его успешной работы мы обязаны знать длину использован­ного ключа. На самом деле это не очень существенный конструктивный недоста­ток, поскольку длину ключа для классических шифров можем определить доста­точно достоверно, например, с помощью теста Казиски, описанного далее, а для современных криптосистем такая проблема отпадает сама собой — длины ключей в них фиксированы.
Дешифрование шифров гаммирования
Все вышеописанные алгоритмы можно применять не только для шифров про­стой замены, но и для шифров гаммирования. Одним из самых популярных шиф­ров гаммирования является шифр Виженера. Его зачастую путают с примитивны­ми шифрами простой замены. На самом деле это не так. Шифр Виженера пред­ставляет собой более сложный шифр полиалфавитной замены.
Процедуры зашифрования и расшифрования этим шифром можно предста­вить следующим образом:
= ai+ yi(mod N), äëÿ 0 <= i <= M,
c
i
ãäå M — длина периодической гаммы; N — количество букв в алфавите; c
, ay
i
обозначают соответственно i-ю (в некотором периоде) букву шифротекста, откры­того текста и накладываемой поверх него гаммы. В классическом варианте гамма получается сдвигом строки алфавита на несколько позиций влево.
Первым вопросом, который возникнет у криптоаналитика при дешифровании шифра Виженера, является вопрос о том, каково значение M, то есть какой имен­но длины гамма была использована при шифровании. Второй вопрос — величина сдвига, которым была сформирована гамма.
Для нахождения ответа на первый вопрос существует несколько специально разработанных методов. Самый простой из них называют тестом Казиски. Назван он в честь Фридриха Казиски, который изобрел этот тест в 1863 году.
Суть теста Казиски заключается в поиске одинаковых фрагментов из неско­льких символов в шифротексте. Дело в том, что отстоящие друг от друга на M символов участки открытого текста будут зашифрованы одинаковыми фрагмента­ми гаммы и, следовательно, будут представлять собой одинаковые фрагменты
i
54 Глава 3. Дешифрование классических шифров
шифротекста. Найдя несколько таких фрагментов в шифротексте, мы можем с не­которой уверенностью сказать, что то расстояние, на которое отстоит друг от дру­га большинство из них, и является длиной, использованной для зашифрования гаммы. К сожалению, этот метод работает далеко не всегда — ведь не в каждом открытом тексте так уж часто встречаются одинаковые фрагменты — слова.
К счастью, полстолетия спустя для нахождения длины гаммы был разрабо­тан специальный оценочный параметр — индекс совпадения (index of coinciden­ce). Метод вычисления индекса совпадения был впервые предложен Уильямом Фридменом в начале XX века. Много позже его работы тщательно изучались, и, помимо индекса совпадения, появлялись другие различные параметры, характе­ризующие текст. Первое же, классическое, определение индекса совпадения вы­глядит так:
1
n
1
ff
()
ii
=
0
mm
1
()
.
Ix
()
c
i
=
Значение индекса совпадения есть не что иное, как вероятность того, что две наугад взятые буквы f
из текста x окажутся равными между собой. Для случай-
i
ной строки текста значение индекса совпадения приблизительно равно
1
1
=
N
= 0,0303(03). Для естественных языков индекс совпадения будет значите-
33 льно выше. Для английского языка, к примеру, он равен 0,0662, а для русского — 0,0529.
Используя индекс совпадения, мы можем определить длину гаммы следую­щим образом. Для начала выберем предположительную длину гаммы, равной двум, отберем буквы, стоящие на каждом первом месте в шифротексте, и посчи­таем индекс совпадения для них. Затем то же самое проделаем для букв на вто­рых местах. Аналогично поступим для гаммы длиной три, четыре и т. д. до некото­рого верхнего значения.
Выпишем получившиеся значения индексов совпадения и посчитаем арифме­тическое среднее. Если длина гаммы отличается от двух, мы получаем цепочки символов, состоящие из текстов с участками гаммы, наложенными с разными сдвигами. Они во многом будут похожи на случайный текст. Если же длина гам­мы совпадает с нашими предположениями, то значение индекса совпадения будет значительно выше и приближенно к индексу совпадения естественного языка.
Допустим, волею судеб мы поставлены перед вопросом решения задачи крип­тоанализа следующего шифра гаммирования Виженера:
ФДСЖОЗУЦЛЦСЧСХЧФЛЦННРЙЦРСПБРЛЩЭЖЖТЗХСЖЧФУГКТЮЩЗРГКЙФММЧЛУДЫОЛУУЧОЙЙФЕДЧЛОАТФС
ИНУКДЙЦЦЗНТФСЕЭГПЕЦГЕУЭЛНПСБЫСФЗМЩОЩМХЩИЦЦЕФПШЭГНТБПМРОКДХЖРЙКФТФККИПКУРЯСЧТТ
ЦФДТСИКДЗОФМСФФЦНФХОУСЛЫКЧХЖЕОЦХФЛШДФЦСЬРБШМЧЛУДЫОМОУЦУЙПШРТЦШЯБЧФЖТУХЛХЕУЛГС
БСЕЦЩЗМСЭЦЦБХСЛЛЛКДЧЛПЬНЪУТЧЛНХЧЦГХЭОЧФУИЮЖЕЛХХДЧТТСФЬАГУСЖУЙСРУКЛШНЬЛФУИГСТФ
ЖТПСБЫЕОТФУИИФДЛХХДНРДЬЛРМКУСФСОУТЗЖРСУПЩЙРЛЕТОЪЦСПЬЛМКЧОМУУСЕРОЙЙПЛЗМТОЩЙННК
ДТФУРНЦСЖЕУРТЦШЛЫКТЕЯЬОФПКУРТКИСЖХЛПГФЦСЬРФММЧЛУДЫОЛДРЙСФНШПДЧФЛЛСЛРЙТУЮНПСБЫ
ЦФШФЕУВЙЧЧВЖПЖЪЙЦШЕЙХЖДТЬЛЖТНЖОЗУЦЛЦСХСЖЧФУГКШФГ
Глава 3. Дешифрование классических шифров 55
По его виду мы пока что мало можем сказать о шифре. Частотный анализ в его примитивном виде не приведет к эффектным результатам. Чтобы начать его использовать, нам необходимо знать длину периода, с которым на открытый текст накладывалась гамма. Попробуем посчитать индексы совпадения для различных длин гаммы с помощью программы из листинга 3.21.
Листинг 3.21
void calc_coin(char *buf, int len, int gamma) {
int i, g, true_len; double *index = new double[gamma]; true_len = len / gamma;
// подсчитаем частоты каждого g-го символа в цепочку for (g = 0; g < gamma; g++) {
double freqs[N];
memset(freqs, 0, sizeof(freqs));
for (i = g; i < len; i += gamma) freqs[buf[i] - 'À']++;
// собственно, индекс совпадения index[g] = 0.0; for(i=0;i<N;i++) index[g] += freqs[i]*(freqs[i]-1); index[g] = index[g] / (true_len*(true_len-1));
}
// подсчитаем средний индекс совпадения double index_s = 0.0; for (g = 0; g < gamma; g++)
index_s += index[g]; index_s /= gamma; delete index;
// выводим результаты printf("Длина гаммы: %2d; Индекс совпадения: %1.8f\n", gamma, index_s);
}
Выбирая каждую g-ю букву шифротекста в цикле, подсчитываем частоты мо­нограмм freqs[N]. Затем вычисляем индекс совпадения для каждой цепочки, а в конце подсчитываем их среднее значение. Результат работы программы приведен в листинге 3.22.
Листинг 3.22
Длина гаммы: 1; Индекс совпадения: 0.04150391 Длина гаммы: 2; Индекс совпадения: 0.04670372 Длина гаммы: 3; Индекс совпадения: 0.04009746
Длина гаммы: 4; Индекс совпадения: 0.05858643
Длина гаммы: 5; Индекс совпадения: 0.04010872 Длина гаммы: 6; Индекс совпадения: 0.04477124 Длина гаммы: 7; Индекс совпадения: 0.04135927
Длина гаммы: 8; Индекс совпадения: 0.06253200
Длина гаммы: 9; Индекс совпадения: 0.04235209 Длина гаммы: 10; Индекс совпадения: 0.04454902
56 Глава 3. Дешифрование классических шифров
Длина гаммы: 11; Индекс совпадения: 0.04005270
Длина гаммы: 12; Индекс совпадения: 0.05720093
Длина гаммы: 13; Индекс совпадения: 0.04204298 Длина гаммы: 14; Индекс совпадения: 0.04501134 Длина гаммы: 15; Индекс совпадения: 0.03969103
Длина гаммы: 16; Индекс совпадения: 0.06411290
Длина гаммы: 17; Индекс совпадения: 0.04286680 Длина гаммы: 18; Индекс совпадения: 0.04732510 Длина гаммы: 19; Индекс совпадения: 0.04145749
Длина гаммы: 20; Индекс совпадения: 0.05783333
Обратите особое внимание на значения индексов совпадений там, где длина гаммы четна. Они немного отличаются от остальных. Составив простой график значений из листинга 3.22, увидим (рис. 3.6), что еще более значительно от основной массы величин отличаются величины для гамм длины 4, 8, 12 и 20. Остальные же значения более приближены к значению индекса совпадений для случайных текстов.
Должно ли это навести нас как криптоаналитиков на мысль о том, что длина гаммы может быть равна либо 4, либо 12, либо 20? Вовсе нет. На самом деле мы можем сразу же решить, что длина гаммы равна наименьшему общему кратному из этих чисел, то есть четырем.
Это верно только лишь потому, что гамма, накладываемая сложением по мо­дулю на открытый текст, является периодической. Ее значения повторяются каж­дые M букв, а это означает лишь, что, когда мы подсчитываем частоты каждой 12-й буквы, косвенно учитываем и частоты некоторых «четвертых букв». Индекс совпадения указывает на осмысленность текста — это верно, как верно и то, что этот текст представляет собой прореженную цепочку «каждых четвертых» симво­лов.
Экспериментируя с вычислением длины периода с помощью метода Фридма­на, можно обнаружить, что при длинах гаммы больше пятидесяти (а иногда и три­дцати) алгоритм дает сбой, показывая завышенные частоты на меньших длинах гаммы, чем у соответствующей действительности. Это связано с тем, что для сбо­ра информации о больших гамма-последовательностей требуется во много раз бо-
Ðèñ. 3.6. График значений индекса совпадений
Глава 3. Дешифрование классических шифров 57
льше шифротекста, чем это могло бы быть для длин гаммы в несколько символов. Вывод, когда-то сделанный Клодом Шенноном, о том, что, чем длиннее гамма, тем шифр является более стойким, подтверждается на практике.
Вычислив длину периода с помощью какого-либо из описанных выше мето­дов, можно приступать к решению задачи криптоанализа шифра гаммирования. Для этого существует множество различных подходов, но самый действенный и самый простой получается автоматически переводом материала и программ из предыдущего раздела этой главы. Разобьем шифротекст на периодические участ­ки (см. листинг 3.23).
Листинг 3.23
ÔÄÑÆ ÎÇÓÖ ËÖÑ× ÑÕ×Ô ËÖÍÍ ÐÉÖÐ ÑÏÁÐ ËÙÝÆ ÆÒÇÕ ÑÆ×Ô ÓÃÊÒ ÞÙÇÐ ÃÊÉÔ ÌÌ×Ë ÓÄÛÎ ËÓÓ× ÎÉÉÔ ÅÄ×Ë ÎÀÒÔ ÑÈÍÓ ÊÄÉÖ ÖÇÍÒ ÔÑÅÝ ÃÏÅÖ ÃÅÓÝ ËÍÏÑ ÁÛÑÔ ÇÌÙÎ ÙÌÕÙ ÈÖÖÅ ÔÏØÝ ÃÍÒÁ ÏÌÐÎ ÊÄÕÆ ÐÉÊÔ ÒÔÊÊ ÈÏÊÓ ÐßÑ× ÒÒÖÔ ÄÒÑÈ ÊÄÇÎ ÔÌÑÔ ÔÖÍÔ ÕÎÓÑ ËÛÊ× ÕÆÅÎ ÖÕÔË ØÄÔÖ ÑÜÐÁ ØÌ×Ë ÓÄÛÎ ÌÎÓÖ ÓÉÏØ ÐÒÖØ ßÁ×Ô ÆÒÓÕ ËÕÅÓ ËÃÑÁ ÑÅÖÙ ÇÌÑÝ ÖÖÁÕ ÑËËË ÊÄ×Ë ÏÜÍÚ ÓÒ×Ë ÍÕ×Ö ÃÕÝÎ ×ÔÓÈ ÞÆÅË ÕÕÄ× ÒÒÑÔ ÜÀÃÓ ÑÆÓÉ ÑÐÓÊ ËØÍÜ ËÔÓÈ ÃÑÒÔ ÆÒÏÑ ÁÛÅÎ ÒÔÓÈ ÈÔÄË ÕÕÄÍ ÐÄÜË ÐÌÊÓ ÑÔÑÎ ÓÒÇÆ ÐÑÓÏ ÙÉÐË ÅÒÎÚ ÖÑÏÜ ËÌÊ× ÎÌÓÓ ÑÅÐÎ ÉÉÏË ÇÌÒÎ ÙÉÍÍ ÊÄÒÔ ÓÐÍÖ ÑÆÅÓ ÐÒÖØ ËÛÊÒ ÅßÜÎ ÔÏÊÓ ÐÒÊÈ ÑÆÕË ÏÃÔÖ ÑÜÐÔ ÌÌ×Ë ÓÄÛÎ ËÄÐÉ ÑÔÍØ ÏÄ×Ô ËËÑË ÐÉÒÓ ÞÍÏÑ ÁÛÖÔ ØÔÅÓ ÂÉ×× ÂÆÏÆ ÚÉÖØ ÅÉÕÆ ÄÒÜË ÆÒÍÆ ÎÇÓÖ ËÖÑÕ ÑÆ×Ô ÓÃÊØ
Дело в том, что собранные для подсчета индекса совпадения цепочки симво­лов — каждый первый, каждый второй и т. д. — можно представить как незави­симые между собой шифры простой замены. И в таком случае решать уже M (ведь такова длина гаммы, и соответственно столько различных цепочек символов мы имеем) задач криптоанализа шифров простой замены.
Еще один способ заключается в использовании взаимного индекса совпаде- íèÿ (mutual index of coincidence). Он может использоваться для вычисления отно­сительного сдвига гаммы для соседних символов шифротекста. Взаимный индекс совпадения отвечает за вероятность совпадения двух наугад взятых букв из двух различных текстов x è y и вычисляется следующим образом:
n
1
1
ff
1
i
=
i
0
mm
,
1
где индекс 1 у частот символов f
MI
=
c
и количества символов m обозначает параметры
i
второй строки. Взаимный индекс совпадения для двух текстов x è y обладает до­полнительно весьма интересным свойством:
n
n
1
(, )
MI x y p p p p
ci j hsihsj
≈=
∑∑
−−
h
=
0
1
jjs n
h
=
0
()mod
.
В нашем примере длина гаммы равна четырем. Соберем цепочки символов так же, как мы делали это для вычисления простого индекса совпадения (см. лис­тинг 3.24).
58 Глава 3. Дешифрование классических шифров
Листинг 3.24
1) ФОЛСЛРСЛЖСУЮГМУЛОЕОСКЦФГГЛБЗЩИФГПКРТИРТДКФФХЛХЦШСШУМУРЯЖЛЛСЗЦСКПУНГЧЮХТЬСС ЛЛГЖБТИХРРСУРЩЕЦЛОСЙЗЩКУСРЛЕФРСПСМУЛСПЛРЮБШВВЪЕДЖОЛСУФ
2) ДЗЦХЦЙПЩТЖГЩКМДУЙДАИДЗСПЕНЫММЦПНМДЙФПЯТТДМЦОЫЖХДЬМДОЙТБТХГЕМЦЛДЬТХХФЖХТАЖР ШФСТЫФФХДМФТСЙТСММЕЙМЙДРЖТЫЯПТЖГЬМДДФДЛЙНЫФЙЖЙЙТТЗЦЖГГ
3) СУСЧНЦБЭЗЧКЗЙЧЫУЙЧТНЙНЕЕУПСЩХЦШТРХКККСЦСЗСНУКЕФФРЧЫУПЦЧУЕСЦСБЛЧНЧЧЭУЕДСГУУ НУТПЕУДДЬКСЗУРОПКУРПТНТНЕЦКЬККХФРЧЫРНЧСТПЦЕЧПЦХЬНУСЧК
4) ЖЦЧФНРРЖХФТРФЛОЧФЛФУЦТЭЦЭСФОЩЕЭБОЖФКУЧФИОФФСЧОЛЦБЛОЦШШФХУБЩЭХЛЛЪЛЦОИЛЧФУЙК ЬИФСОИЛНЛУОЖПЛЪЬЧУОЛОНФЦУШТОУИЛЦФЛОЙШФЛУСФУЧЖШЖЛЖЦХФШ
Каждая из этих цепочек могла быть получена, вообще говоря, с помощью шифра простой замены, но в шифре Виженера они определяются циклическим сдвигом алфавита на несколько позиций влево или вправо. Взяв несколько зара­нее заготовленных цепочек русского текста, мы можем подсчитать, чему равен индекс взаимного совпадения для различных сдвигов (см. листинг 3.25).
Листинг 3.25
Сдвиг: 0 ==> Взаимный индекс совпадения: 0.04338331 Сдвиг: 1 ==> Взаимный индекс совпадения: 0.03957709 Сдвиг: 2 ==> Взаимный индекс совпадения: 0.03832372 Сдвиг: 3 ==> Взаимный индекс совпадения: 0.03723952 Сдвиг: 4 ==> Взаимный индекс совпадения: 0.03433679 Сдвиг: 5 ==> Взаимный индекс совпадения: 0.03455978 Сдвиг: 6 ==> Взаимный индекс совпадения: 0.03354095 Сдвиг: 7 ==> Взаимный индекс совпадения: 0.03126490 Сдвиг: 8 ==> Взаимный индекс совпадения: 0.03077278 Сдвиг: 9 ==> Взаимный индекс совпадения: 0.02876586 Сдвиг: 10 ==> Взаимный индекс совпадения: 0.02732026 Сдвиг: 11 ==> Взаимный индекс совпадения: 0.02669358 Сдвиг: 12 ==> Взаимный индекс совпадения: 0.02531334 Сдвиг: 13 ==> Взаимный индекс совпадения: 0.02628989 Сдвиг: 14 ==> Взаимный индекс совпадения: 0.02597463 Сдвиг: 15 ==> Взаимный индекс совпадения: 0.02505575 Сдвиг: 16 ==> Взаимный индекс совпадения: 0.02655902 Сдвиг: 17 ==> Взаимный индекс совпадения: 0.02505575 Сдвиг: 18 ==> Взаимный индекс совпадения: 0.02597463 Сдвиг: 19 ==> Взаимный индекс совпадения: 0.02628989 Сдвиг: 20 ==> Взаимный индекс совпадения: 0.02531334 Сдвиг: 21 ==> Взаимный индекс совпадения: 0.02669358 Сдвиг: 22 ==> Взаимный индекс совпадения: 0.02732026 Сдвиг: 23 ==> Взаимный индекс совпадения: 0.02876586 Сдвиг: 24 ==> Взаимный индекс совпадения: 0.03077278 Сдвиг: 25 ==> Взаимный индекс совпадения: 0.03126490 Сдвиг: 26 ==> Взаимный индекс совпадения: 0.03354095 Сдвиг: 27 ==> Взаимный индекс совпадения: 0.03455978 Сдвиг: 28 ==> Взаимный индекс совпадения: 0.03433679 Сдвиг: 29 ==> Взаимный индекс совпадения: 0.03723952 Сдвиг: 30 ==> Взаимный индекс совпадения: 0.03832372 Сдвиг: 31 ==> Взаимный индекс совпадения: 0.03957709
Глава 3. Дешифрование классических шифров 59
Из чего можем заключить, что, например, для нулевого сдвига в алфавите русского языка взаимный индекс совпадения равен приблизительно 0.04338331 (не следует забывать, что для получения лучших оценок необходимо исследовать гораздо более длинные тексты, чем несколько килобайтов, которые использовали авторы этой книги для подсчета значений из листинга 3.25).
Для всевозможных пар цепочек из листинга 3.24 мы можем подсчитать вза­имный индекс совпадения с помощью программы из листинга 3.26 (она же испо­льзовалась и для вычисления значений взаимного индекса совпадения в листинге
3.25). От программы из листинга 3.24 она практически не отличается, за исклю­чением лишь того, что рассматриваются две строки текста и формула вычисления индекса совпадения изменена.
Листинг 3.26
double calc_mutual_coin(char *buf1, char *buf2, int len) {
int i; double index_s = 0;
// подсчитаем частоты для первой строки double freqs1[N]; memset(freqs1, 0, sizeof(freqs1)); for (i = 0; i < len; i++) freqs1[buf1[i] - 'А']++;
// подсчитаем частоты для второй строки double freqs2[N]; memset(freqs2, 0, sizeof(freqs2)); for (i = 0; i < len; i++) freqs2[buf2[i] - 'А']++;
// подсчитаем взаимный индекс совпадения index_s = 0.0; for(i=0;i<N;i++) index_s += freqs1[i]*freqs2[i]; index_s = index_s / (len*len);
// выводим результаты printf("Взаимный индекс совпадения: %1.8f\n", index_s); return index_s;
}
Просматривая всевозможные варианты, сможем понять, насколько «сдвину­ты» цепочки друг относительно друга. Результат работы программы представлен в листинге 3.27.
Листинг 3.27
0, 1 == Взаимный индекс совпадения: 0.04073408 0, 2 == Взаимный индекс совпадения: 0.04166408 0, 3 == Взаимный индекс совпадения: 0.04470209 1, 2 == Взаимный индекс совпадения: 0.04123008 1, 3 == Взаимный индекс совпадения: 0.04154008 2, 3 == Взаимный индекс совпадения: 0.04439209
60 Глава 3. Дешифрование классических шифров
Сравнивая их со значениями из листинга 3.25, можем указать, насколько сдвинуты все цепочки относительно первой. Для этого нужно подобрать наиболее близкие значения взаимного индекса совпадения и, если их несколько, опробо­вать их все. Сдвигая первую по одному символу N раз (столько же, каково число букв в алфавите), получим N различных возможных сообщений. Выбрать из них визуально осмысленное не составит большого труда. А это значит, что задача криптоанализа шифра гаммирования решена.
Золотая криптография
Криптография всегда была одной из самых загадочных областей человече­ской деятельности. Она притягивала к себе множество великих умов. Ею занима­лись математики и короли, она была и остается страстью многих людей, посвя­тивших свои жизни решению задач криптографии.
Многие известные люди занимались «тайнописью», разрабатывали свои соб­ственные шифры и вскрывали другие. Так появились и правила Керкхоффа и ре­шетка Кардано. Даже Л. Кэрролл в своей «Алисе в стране чудес» умудрился опи­сать несколько криптографических загадок.
Эдгар Алан По творил чудеса в криптографии. Помимо многочисленных упо­минаний о «секретных письменах» в его стихах и рассказах, как, например, в «Зо­лотом жуке», он предложил свою собственную «криптографическую задачу», ко­торая была опубликована в «Александрийском еженедельном вестнике» в начале декабря 1839 года.
В своих статьях в этом журнале он предложил читателям представить ему за­дачи и заявил, что решит их все до единой. В течение следующих шести месяцев Эдгар По публиковал решения шифров, присланных читателями, и объяснял свою точку зрения на саму сущность криптографии.
Сотрудничество По с «Вестником» закончилось в мае 1840 года, но примерно через год он снова поднял этот вопрос в статье «Несколько слов о секретной пись­менности» в журнале «Грехем». В ней и трех дополнениях, последовавших за ста­тьей, он утверждал, что дешифровал около ста шифров, полученных «Вестни­ком», и далее комментировал свои взгляды на предмет криптографии.
Как раз в это время один из читателей По, мистер Тайлер, предложил два шифра для публикации в «колонке шифров», которую вел По. Эдгар По так никог­да и не опубликовал решения задач Тайлера. Это возбудило к ним особый инте­рес — ведь из сотни предоставленных задач не были решены только эти две. По сослался на то, что у него не было времени на решение этого вопроса, но все-таки опубликовал сами задачи с предложением читателям решить их.
Наиболее интересным моментом являлось то, что существовала вероятность, что По сам составил эти задачи. Единственным объяснением доказательства этой теории было, что Тайлер — это просто псевдоним Эдгара По. Эту теорию впервые выдвинули Луис Ренза в статье под названием «Тайная биография По» и позже Шон Росенхейн в книге «Криптографическое воображение». И только решение задач Тайлера могло подтвердить или опровергнуть эту теорию.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]