Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Практическая криптография алгоритмы и их программирование
.pdf
Глава 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
, aiè y
i
обозначают соответственно i-ю (в некотором периоде) букву шифротекста, открытого текста и накладываемой поверх него гаммы. В классическом варианте гамма
получается сдвигом строки алфавита на несколько позиций влево.
Первым вопросом, который возникнет у криптоаналитика при дешифровании
шифра Виженера, является вопрос о том, каково значение M, то есть какой именно длины гамма была использована при шифровании. Второй вопрос — величина
сдвига, которым была сформирована гамма.
Для нахождения ответа на первый вопрос существует несколько специально
разработанных методов. Самый простой из них называют тестом Казиски. Назван
он в честь Фридриха Казиски, который изобрел этот тест в 1863 году.
Суть теста Казиски заключается в поиске одинаковых фрагментов из нескольких символов в шифротексте. Дело в том, что отстоящие друг от друга на M
символов участки открытого текста будут зашифрованы одинаковыми фрагментами гаммы и, следовательно, будут представлять собой одинаковые фрагменты
i

54 Глава 3. Дешифрование классических шифров
шифротекста. Найдя несколько таких фрагментов в шифротексте, мы можем с некоторой уверенностью сказать, что то расстояние, на которое отстоит друг от друга большинство из них, и является длиной, использованной для зашифрования
гаммы. К сожалению, этот метод работает далеко не всегда — ведь не в каждом
открытом тексте так уж часто встречаются одинаковые фрагменты — слова.
К счастью, полстолетия спустя для нахождения длины гаммы был разработан специальный оценочный параметр — индекс совпадения (index of coincidence). Метод вычисления индекса совпадения был впервые предложен Уильямом
Фридменом в начале 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 года, но примерно
через год он снова поднял этот вопрос в статье «Несколько слов о секретной письменности» в журнале «Грехем». В ней и трех дополнениях, последовавших за статьей, он утверждал, что дешифровал около ста шифров, полученных «Вестником», и далее комментировал свои взгляды на предмет криптографии.
Как раз в это время один из читателей По, мистер Тайлер, предложил два
шифра для публикации в «колонке шифров», которую вел По. Эдгар По так никогда и не опубликовал решения задач Тайлера. Это возбудило к ним особый интерес — ведь из сотни предоставленных задач не были решены только эти две. По
сослался на то, что у него не было времени на решение этого вопроса, но все-таки
опубликовал сами задачи с предложением читателям решить их.
Наиболее интересным моментом являлось то, что существовала вероятность,
что По сам составил эти задачи. Единственным объяснением доказательства этой
теории было, что Тайлер — это просто псевдоним Эдгара По. Эту теорию впервые
выдвинули Луис Ренза в статье под названием «Тайная биография По» и позже
Шон Росенхейн в книге «Криптографическое воображение». И только решение
задач Тайлера могло подтвердить или опровергнуть эту теорию.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
