Interested Article - Шифр Виженера
- 2020-01-08
- 1
Шифр Виженера ( фр. Chiffre de Vigenère ) — метод полиалфавитного шифрования буквенного текста с использованием ключевого слова.
Этот метод является простой формой многоалфавитной замены. Шифр Виженера изобретался многократно. Впервые этот метод описал Джованни Баттиста Беллазо в книге La cifra del. Sig. Giovan Battista Bellasо в 1553 году , однако в XIX веке получил имя Блеза Виженера , французского дипломата. Метод прост для понимания и реализации, но является недоступным для простых методов криптоанализа .
Хотя шифр легко понять и реализовать, на протяжении трех столетий он противостоял всем попыткам его взломать, благодаря чему его называли «неразгаданным шифром» ( фр. le chiffre indéchiffrable ). Многие люди пытались реализовать схемы шифрования, которые по сути являлись шифрами Виженера.
История
В 1466 году Леон Альберти , знаменитый архитектор и философ представил трактат о шифрах в папскую канцелярию. В трактате рассматриваются различные способы шифрования, в том числе маскировка открытого текста в некотором вспомогательном тексте. Работа завершается собственным шифром, который он назвал «шифр, достойный королей». Это был многоалфавитный шифр, реализованный в виде шифровального диска. Суть заключается в том, что в данном шифре используется несколько замен в соответствии с ключом. Позднее Альберти изобрел код с перешифровкой. Данное изобретение значительно опередило свое время, поскольку данный тип шифра стал применяться в странах Европы лишь 400 лет спустя.
В 1518 году в развитии криптографии был сделан новый шаг благодаря появлению в Германии первой печатной книги по криптографии. Аббат Иоганн Тритемий, настоятель монастыря в Вюрцбурге, написал книгу «Полиграфия», в которой дается описание ряда шифров. Один из них использует « » (ныне «таблицу Виженера») и развивает идею многоалфавитной замены. Система шифрования следующая: первая буква исходного текста шифруется по первой строке, вторая по второй и так далее. После использования последней строки следующая буква вновь шифруется по первой строке. В шифре Тритемия отсутствует ключ, секретом является сам способ шифрования.
Следующий шаг в развитии предложенного Тритемием способа шифрования был сделан итальянцем Джовани Белазо. В 1553 году выходит в свет его брошюра «Шифр синьора Белазо». В этом шифре ключом является так называемый пароль — фраза или слово. Пароль записывался периодически над буквами открытого текста. Буква пароля, стоящая над соответствующей буквой открытого текста, указывала номер строки в таблице Тритемия, по которой следует проводить замену (шифрование) это буквы.
В последующем идеи Тритемия и Белазо развил соотечественник Белазо Джованни Батиста Порта . Он предложил отказаться от алфавитного порядка следования букв в первой строке таблицы Тритемия и заменить этот порядок на некоторый произвольный, являющийся ключом шифра. Строки таблицы по-прежнему циклически сдвигались. В своей книге «О тайной переписке», (вышедшей в 1563 году ) Порта предложил биграммный шифр , а также привел описание механического дискового устройства, реализующего биграммную замену.
В середине XVI века в Италии появляется книга Дж. Кардано «О тонкостях» с дополнением «О разных вещах». Там нашли отражение новые идеи криптографии: использование части самого передаваемого открытого текста в качестве ключа шифра (идея «самоключа») и новый способ шифрования, который вошел в историю как « решетка Кардано ».
Посол Франции в Риме Блез де Виженер , познакомившись с трудами Тритемия, Белазо, Кардано, Порта, Альберти, также увлекся криптографией. В 1585 году он написал «Трактат о шифрах», в котором излагаются основы криптографии. В этом труде он замечает: «Все вещи в мире представляют собой шифр. Вся природа является просто шифром и секретным письмом». Эта мысль была позднее повторена Блезом Паскалем — одним из основоположников теории вероятностей, а в XX веке и Норбертом Винером — «отцом кибернетики».
По сути дела Виженер объединил подходы Тритемия, Беллазо, Порта к шифрованию открытых текстов, по существу не внеся в них ничего оригинального. В наше время «шифр Виженера», состоящий в периодическом продолжении ключевого слова по таблице Тритемия, вытеснил имена его предшественников. Дэвид Кан в своей книге «Взломщики кодов» отозвался об этом осуждающе, написав, что история «проигнорировала важный факт и назвала шифр именем Виженера, несмотря на то, что он ничего не сделал для его создания» .
Шифр Виженера имел репутацию исключительно стойкого к «ручному» взлому. Известный писатель и математик Чарльз Лютвидж Доджсон ( Льюис Кэрролл ) назвал шифр Виженера невзламываемым в своей статье «Алфавитный шифр» англ. The Alphabet Cipher , опубликованной в детском журнале в 1868 году. В 1917 году Scientific American также отозвался о шифре Виженера как о не поддающемся взлому. Это представление было опровергнуто после того, как Касиски полностью взломал шифр в XIX веке, хотя известны случаи взлома этого шифра некоторыми опытными криптоаналитиками ещё в XVI веке.
Шифр Виженера достаточно прост для использования в полевых условиях, особенно если применяются шифровальные диски. Например, «конфедераты» использовали медный шифровальный диск для шифра Виженера в ходе Гражданской войны . Послания Конфедерации были далеки от секретных, и их противники регулярно взламывали сообщения. Во время войны командование Конфедерации полагалось на три ключевых словосочетания: «Manchester Bluff», «Complete Victory» и — так как война подходила к концу — «Come Retribution».
Гилберт Вернам попытался улучшить взломанный шифр (он получил название шифр Вернама-Виженера в 1918 году), но, несмотря на его усовершенствования, шифр так и остался уязвимым для криптоанализа . Однако работа Вернама в итоге всё же привела к получению шифра Вернама , который действительно невозможно взломать.
Описание
В шифре Цезаря каждая буква алфавита сдвигается на несколько позиций; например в шифре Цезаря при сдвиге +3, A стало бы D, B стало бы E и так далее. Шифр Виженера состоит из последовательности нескольких шифров Цезаря с различными значениями сдвига. Для зашифровывания может использоваться таблица алфавитов, называемая tabula recta или квадрат (таблица) Виженера. Применительно к латинскому алфавиту таблица Виженера составляется из строк по 26 символов, причём каждая следующая строка сдвигается на несколько позиций. Таким образом, в таблице получается 26 различных шифров Цезаря. На каждом этапе шифрования используются различные алфавиты, выбираемые в зависимости от символа ключевого слова. Например, предположим, что исходный текст имеет такой вид:
ATTACKATDAWN
Человек, посылающий сообщение, записывает ключевое слово (« LEMON ») циклически до тех пор, пока его длина не будет соответствовать длине исходного текста:
LEMONLEMONLE
Первый символ исходного текста («A») зашифрован последовательностью L, которая является первым символом ключа. Первый символ зашифрованного текста («L») находится на пересечении строки L и столбца A в таблице Виженера. Точно так же для второго символа исходного текста используется второй символ ключа; то есть второй символ зашифрованного текста («X») получается на пересечении строки E и столбца T. Остальная часть исходного текста шифруется подобным способом.
Исходный текст: ATTACKATDAWN Ключ: LEMONLEMONLE Зашифрованный текст: LXFOPVEFRNHR
Расшифровывание производится следующим образом: находим в таблице Виженера строку, соответствующую первому символу ключевого слова; в данной строке находим первый символ зашифрованного текста. Столбец, в котором находится данный символ, соответствует первому символу исходного текста. Следующие символы зашифрованного текста расшифровываются подобным образом.
Если — количество букв в алфавите, — номер буквы открытого текста, — номер буквы ключа в алфавите, то шифрование Виженера можно записать следующим образом:
И расшифровывание:
В компьютере такая операция соответствует сложению кодов ASCII символов сообщения и ключа по некоторому модулю. Кажется, что если таблица будет более сложной, чем циклическое смещение строк, то шифр станет надежнее. Это действительно так, если ее менять чаще, например, от слова к слову. Но составление таких таблиц, представляющих собой латинские квадраты, где любая буква встречается в строке или столбце один раз, трудоемко и его стоит делать лишь на ЭВМ. Для ручного же многоалфавитного шифра полагаются лишь на длину и сложность ключа, используя приведенную таблицу, которую можно не держать в тайне, а это упрощает шифрование и расшифровывание.
Применение
В XIX веке большое распространение получил так называемый метод блокнотного шифрования. Им пользовались революционеры- народники , шпионы и т. п. Шифр использует фразы, взятые из языка, как ключ шифрования. Например, фраза: «14 июля — Mary’s birthday». Если использовать принятую для примеров нумерацию букв английского алфавита, то Marysbirthday означает . Для шифровки фразы Iamgoing ↔ производится сложение mod26 текста с ключом, в роли которого выступает записанная фраза. Получается
↔ U A D E G J V X.
Как видно, в данном случае это обыкновенное гаммирование . Виженер предложил использовать ключ такого типа и в тех случаях, когда текст длиннее ключа, накладывая его столько раз, сколько нужно. При этом совсем необязательно, чтобы ключ получался из осмысленной фразы. Более того, это даже нежелательно, так как осмысленность может помочь взломщику шифра. Возьмем, например, текст:
A SMOKE OF MOTHERLAND IS SWEET FOR US AND PLEASANT ↔ и ключ: .
Шифровка получается гаммированием mod26:
- Pt:
- Key:
- Ct:
- Pt:
- Key:
- Ct:
Таким образом, шифр Виженера получается как повторяющаяся комбинация сдвигов. В общем случае этот шифр не сохраняет частотность встречающихся букв и по этой причине не может быть раскрыт методом статистического анализа.
Шифр Виженера был популярен не только среди европейцев: в 1860-х гг. им активно пользовались обе стороны Гражданской войны в США . Вместо таблиц у них были специальные медные диски, но принцип работы остался прежним .
Криптоанализ
Шифр Виженера «размывает» характеристики частотностей появления символов в тексте, но некоторые особенности появления символов в тексте остаются. Главный недостаток шифра Виженера состоит в том, что его ключ повторяется. Поэтому простой криптоанализ шифра может быть построен в два этапа:
- Поиск длины ключа. Можно анализировать распределение частотностей в зашифрованном тексте с различным прореживанием. То есть брать текст, включающий каждую 2-ю букву зашифрованного текста, потом каждую 3-ю и т. д. Как только распределение частотностей букв будет сильно отличаться от равномерного (например, по энтропии), то можно говорить о найденной длине ключа.
- Криптоанализ. Совокупность l шифров Цезаря (где l — найденная длина ключа), которые по отдельности легко взламываются.
Тесты Фридмана и Касиски могут помочь определить длину ключа.
Тест Касиски и определение с его помощью длины ключа
Чарльз Беббидж был первым, кто разработал алгоритм атаки на шифр Виженера в 1854 году. Стимулом к разработке алгоритма послужил обмен письмами с Джоном Х. Б. Твейтсом. Он заявил, что создал новый шифр, и отправил его в «Journal of the Society of the Arts»; когда Беббидж показал, что шифр Твейтса является лишь частным случаем шифра Виженера, Твейтс предложил ему его взломать. Беббидж расшифровал текст, который оказался поэмой «The Vision of Sin» Альфреда Теннисона , зашифрованной ключевым словом Emily — именем жены поэта. Но он не опубликовал свое открытие. Поэтому данный алгоритм назван в честь Фридриха Вильгельма Касиски , офицера прусской армии, который независимо от Беббиджа разработал такой же алгоритм в 1863 году. И только в XX веке, когда ученые исследовали заметки Беббиджа, появилась информация о первом изобретателе этого алгоритма.
Вначале определим понятие индекса совпадения данного текста. Пусть рассматривается текст , соответствующий алфавиту, состоящему из букв. Пусть — длина этого текста. Обозначим через число вхождений буквы с номером в текст . Тогда индекс совпадения текста определяется как
.
Эмпирически проверено, что индекс совпадения длинных осмысленных английских текстов, таких как «Моби Дик» Меллвила , приблизительно равен 0,065. При этом, конечно, в тексте оставляют только 26 букв английского алфавита. В то же время абсолютно случайный достаточно длинный текст на 26 буквах, в котором все буквы встречаются приблизительно одинаковое число раз, равен 0,038. Замечено, что чем «осмысленнее» текст, тем выше его индекс совпадения. Это обстоятельство как раз и помогает вычислять длину ключа в шифре Виженера.
Пусть
— исходный текст, в котором
— его
-я буква, а
— его шифровка по Виженеру. Если применяется обычный сдвиг, то есть длина ключа
, то должно выполняться равенство
, поскольку изменяются только номера букв, но не числа их вхождений. Так как
— осмысленный (по предположению) текст, то значение
, будет приблизительно равно стандартному значению
, для данного языка. Рассматривается пример обычного английского языка, поэтому
. Конечно, вряд ли шифр Виженера будет в общем случае получен ключом длины 1. Поэтому последовательно вычисляются следующие индексы совпадения:
до тех пор, пока не получится
.
Это может свидетельствовать о том, что длина ключа равна , хотя и может оказаться ложным следом.
Действительно, если длина ключа равна , то текст будет получен из сдвигом, следовательно, сохранит , а текст , в свою очередь, является случайной выборкой осмысленного текста, следовательно, должен сохранить его статистические характеристики, в частности индекс совпадения.
Если индекс совпадения некоторого языка неизвестен, то использование теста Касиски также возможно. Нужно не сравнивать полученные значения индексов совпадения со стандартным значением, а смотреть, когда этот индекс резко возрастет. Это может сигнализировать о найденной длине ключа. Конечно, речь идет о расшифровке осмысленных и одновременно достаточно длинных текстов. Впрочем, понятие осмысленности для формальных языков — понятие непростое.
Другим применением теста Касиски является проверка сохранения частотностей встречающихся букв при шифровании. Пусть — зашифрованный текст, причем алгоритм шифрования неизвестен. Если известно, что использовался обычный английский алфавит и значение близко к 0,065, то это дает основание полагать, что использовался шифр, сохраняющий частотности. Возможно, что это шифр простой замены. В ситуации, когда значение далеко от 0,065, можно предположить, что использовался шифр, не сохраняющий частотности, или же текст был бессмысленным, или же использовался другой алфавит и т. п. Одним словом, что-то оказалось не так и необходим более глубокий анализ.
Однако вернемся к шифру Виженера. Пусть определили правильно длину ключа, равную . Теперь нужно найти сам ключ.
Гистограмма, построенная по стандартным частотностям букв в языке, имеет свои отличительные особенности. Они объясняются крайне неравномерным использованием букв в английском языке. Эта неравномерность как раз и позволяет эффективно применять частотный анализ.
Прежде всего, обращают на себя внимание «пики», соответствующие буквам A, E, H, I, N, O, R, S, T, и «пеньки», соответствующие J, Q, X, Z. При этом некоторые «пики» стоят рядом, даже есть целая тройка: R, S, T. Все вместе дает весьма специфический рельеф.
Если используется сдвиг на 4, то картина изменяется циклически. Наблюдается циклический сдвиг рельефа на 4 единицы. Если не знать величину сдвига, то её нетрудно восстановить, руководствуясь здравым смыслом.
Роторные машины
Можно усовершенствовать шифр Виженера, рассматривая в качестве повторяющегося ключа комбинацию произвольных замен: . Это означает, что единицы исходного текста преобразуются в единицы соответственно в и т. д.
При взломе такого шифра, как и в случае шифра Виженера, вначале нужно определить длину ключа . Это можно делать с использованием теста Касиски так же, как в описанном случае. Далее для определения подстановок можно применить частотный анализ.
Частотный анализ
Как только длина ключа становится известной, зашифрованный текст можно записать во множество столбцов, каждый из которых соответствует одному символу ключа. Каждый столбец состоит из исходного текста, который зашифрован шифром Цезаря ; ключ к шифру Цезаря является всего-навсего одним символом ключа для шифра Виженера, который используется в этом столбце. Используя методы, подобные методам взлома шифра Цезаря, можно расшифровать зашифрованный текст. Усовершенствование теста Касиски, известное как метод Кирхгофа, заключается в сравнении частотности появления символов в столбцах с частотностью появления символов в исходном тексте для нахождения ключевого символа для этого столбца. Когда все символы ключа известны, криптоаналитик может легко расшифровать шифрованный текст, получив исходный текст. Метод Кирхгофа не применим, когда таблица Виженера скремблирована, вместо использования обычной алфавитной последовательности, хотя тест Касиски и тесты совпадения всё ещё могут использоваться для определения длины ключа для этого случая.
Упоминания в литературе
В 1881 году Жюль Верн написал роман « Жангада ». В данном романе автор использовал для зашифровки документа шифр Виженера. В качестве зашифрованного текста, автор использует следующий документ:
СГУЧПВЭЛЛЗИРТЕПНДНФГИНБОРГЙУГЛЧД КОТХЖГУУМЗДХРЪСГСЮДТПЪАРВЙГГИЩВЧ ЭЕЦСТУЖВСЕВХАХЯФБЬБЕТФЗСЭФТХЖЗБЗ ЪГФБЩИХХРИПЖТЗВТЖЙТГОЙБНТФФЕОИХТ ТЕГИИОКЗПТФЛЕУГСФИПТЬМОФОКСХМГБТ ЖФЫГУЧОЮНФНШЗГЭЛЛШРУДЕНКОЛГГНСБК ССЕУПНФЦЕЕЕГГСЖНОЕЫИОНРСИТКЦЬЕДБ УБТЕТЛОТБФЦСБЮЙПМПЗТЖПТУФКДГ
По ходу истории герои находят фрагмент расшифрованного слова к этому документу: ОРТЕГА Герои догадались, что это имя может обозначать подпись в конце документа. Таким образом выходит:
О Р Т Е Г А Т У Ф К Д Г
Следовательно, ключ — 432513. Зная ключ, можно легко перевести данный документ:
НАСТОЯЩИЙ ВИНОВНИК КРАЖИ АЛМАЗОВ СГУЧПВЭЛЛ ЗИРТЕПНД НФГИН БОРГЙУГ И УБИЙСТВА СОЛДАТ ОХРАНЫ В НОЧЬ НА Л ЧДКОТХЖГ УУМЗДХ РЪСГСЮ Д ТПЪА РВ ДВАДЦАТЬ ВТОРОЕ ЯНВАРЯ ТЫСЯЧА ЙГГИЩВЧЭ ЕЦСТУЖ ВСЕВХА ХЯФБЬБ ВОСЕМЬСОТ ДВАДЦАТЬ ШЕСТОГО ГОДА ЕТФЗСЭФТХ ЖЗБЗЪГФБ ЩИХХРИП ЖТЗВ НЕ ЖОАМ ДАКОСТА, НЕСПРАВЕДЛИВО ПРИ ТЖ ЙТГО ЙБНТФФЕ ОИХТТЕГИИОКЗП ТФЛ ГОВОРЕННЫЙ К СМЕРТИ, А Я, НЕСЧАСТНЫЙ ЕУГСФИПТЬМ О ФОКСХМ Г Б ТЖФЫГУЧОЮН СЛУЖАЩИЙ УПРАВЛЕНИЯ АЛМАЗНОГО ФНШЗГЭЛЛ ШРУДЕНКОЛГ ГНСБКССЕУ ОКРУГА; ДА, Я ОДИН, В ЧЕМ И ПОДПИСЫ ПНФЦЕЕ ЕГ Г СЖНО И ЫИО Н РСИТКЦЬ ВАЮСЬ СВОИМ НАСТОЯЩИМ ИМЕНЕМ, ЕДБУБ ТЕТЛО ТБФЦСБЮЙП МПЗТЖП ОРТЕГА ТУФКДГ
Варианты
Существует много других легкозапоминающихся квадратов, которые могут применяться в качестве основы для многоалфавитной системы так же, как и квадрат Виженера. Одним из наиболее известных является квадрат Бофора . Его строками являются строки квадрата Виженера, записанные в обратном порядке. Он назван в честь адмирала сэра Френсиса Бофора — создателя шкалы для определения скорости ветра. Если в квадрате Виженера первая строка и столбец указывают на строки и столбцы соответственно, то в квадрате Бофора этим целям служат первая строка и последний столбец.
Вариант шифра Виженера с ( англ. running key ) когда-то был невзламываемым. Эта версия использует в качестве ключа блок текста, равный по длине исходному тексту. Так как ключ равен по длине сообщению, то методы, предложенные Фридманом и Касиски, не работают (так как ключ не повторяется). В 1920 году Фридман первым обнаружил недостатки этого варианта. Проблема с running key шифра Виженера состоит в том, что криптоаналитик имеет статистическую информацию о ключе (учитывая, что блок текста написан на известном языке) и эта информация будет отражаться в шифрованном тексте. Если ключ действительно случайный, его длина равна длине сообщения и он использовался единожды, то шифр Виженера теоретически будет невзламываемым, фактически этот вариант будет уже шифром Вернама-Виженера, для которого доказана абсолютная криптостойкость.
Несмотря на очевидную стойкость шифра Виженера, он широко не использовался в Европе. Большее распространение получил шифр Гронсфельда , созданный графом Гронсфельдом, идентичный шифру Виженера, за исключением того, что он использовал только 10 различных алфавитов (соответствующих цифрам от 0 до 9). Преимущество шифра Гронсфельда состоит в том, что в качестве ключа используется не слово, а цифровая последовательность, которая повторяется до тех пор, пока не станет равной длине шифруемого сообщения. Шифр Гронсфельда широко использовался по всей Германии и Европе, несмотря на его недостатки.
Реализация
JavaScript
//Можно скопировать и вставить весь этот код - в консоль браузера.
var a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //Строка алфавита
var m = "ATTACKATDAWN"; //Сообщение
var k = "LEMON"; //Ключ
function Vizhener( m, k, mode ){//(encrypt/decrypt) for "Gronsfeld" + "Vizhener" + "Beaufort" + "Shifted Atbash"
//m - сообщение или шифротекст (может быть и ключ, если шифр Бофора),
//k - ключ (или сообщение/шифротекст, если шифр Бофора),
//mode - режим:
// Шифрование: "encrypt" (по умолчанию),
// Дешифрование: "decrypt" (mode === 'decrypt'),
// Шифрование-дешифрование по таблице сдвинутого атбаша: (mode==='shifted_atbash')
// Извлечение цифр из ключа шифра Гронсфельда: "gronsfeld" или "gronsfeld_encrypt", "gronsfeld decrypt".
var maxlength = Math.max(m.length, k.length);
var r = ''; //Пустой результат
for(i=0; i<maxlength; i++){ //encrypt/decrypt
//Vizhener - encrypt/decrypt one forumula (encrypt - by default; decrypt - when (mode === 'decrypt') )
var mi = a.indexOf( m[ ( (i>=m.length) ?i%m.length :i ) ] ); //подгон сообщения/шифротекста - к ключу (если меньше)
var ki_s = k[ ( (i>=k.length) ?i%k.length :i ) ];
//подгон ключа к сообщению/шифротексту (если короткий)
var ki = (typeof mode !== 'undefined' && mode.indexOf('gronsfeld') !== -1) ? parseInt( ki_s ): a.indexOf( ki_s );
//вычитание при дешифровании, либо сложение.
ki = ( (typeof mode !== 'undefined' && mode.indexOf('decrypt') !== -1) ?(-ki) :ki );
c = a[ ( ( ( a.length + ( mi + ki ) ) % a.length ) ) ]; //символ по таблице Виженера.
c = (mode === 'shifted_atbash') ? a[a.length-1-a.indexOf(c)] : c; //Атбаш символа или символ.
r += c; //Добавить символ к результату.
}
return r; //вернуть строку результата
}
//Тесты:
//1. Шифр Гронсфельда. (Урезанная версия шифра Виженера).
//Параметры: m - сообщение/шифротекст, k - ключ (только цифр), mode - "encrypt/decrypt"
console.log(
'\n\n1. Шифр Гронсфельда (Урезанная версия шифра Виженера c цифровым ключом):'
, '\n'+ 'm = ', 'GRONSFELD', ' - сообщение'
, '\n'+ 'k = ', '2015', '- ключ'
, '\n'+ 'Шифр Гронсфельда - шифрование: '
, Vizhener( 'GRONSFELD', '2015', 'gronsfeld' ) //выдаст IRPSUFFQF - шифр Гронсфельда
, '\n'+ 'Шифр Гронсфельда - дешифрование: '
, Vizhener( Vizhener('GRONSFELD', '2015', 'gronsfeld'), '2015', 'gronsfeld decrypt' ) //выдаст GRONSFELD - из шифра Гронсфельда
, '\n'+ 'Сравнение с сообщением: ', "( decrypted === m )"
, ( Vizhener( Vizhener( 'GRONSFELD', '2015', 'gronsfeld'), '2015', 'gronsfeld_decrypt' ) === 'GRONSFELD' ) //m? true
);
//2. Также, вместо цифр, в шифре Гронсфельда - возможно и указание букв.
//Тогда, шифром Гронсфельда будет обычный шифр Виженера, но с ограничением символов на ключ.
//Например, при всех возможных цифрах в ключе "0123456789", ключ может быть только из букв "ABCDEFGHIJ"
//Получить его - можно так:
var Gronsfeld_key = '2015';
var Vizhener_key = Gronsfeld_key.split('').map(function(x){return a[parseInt(x)]}).join(''); //CABF
//И наоборот:
var Gronsfeld_key2 = Vizhener_key.split('').map(function(x){return a.indexOf(x)}).join(''); //2015
//Вот они, в консоли:
console.log(
'\n2. Конвертация ключа Гронсфельда - в ключ Виженера:'
, '\nGronsfeld_key', Gronsfeld_key
, '\n'+'в Vizhener_key', Vizhener_key
, '\n'+'и назад:', Gronsfeld_key2
);
//3. Тогда шифрование-дешифрование шифра Гронсфельда - есть работа с шифром Виженера:
console.log(
"\n3. Шифр Гронсфельда - с ключом Виженера, по таблице Виженера:"
, '\n'+ 'm = ', 'GRONSFELD', ' - сообщение'
, '\n'+ 'k = ', Vizhener_key, '- ключ'
, '\n'+ 'Шифр Гронсфельда - шифрование: '
, Vizhener( 'GRONSFELD', Vizhener_key ) //выдаст IRPSUFFQF - шифр Бофора
, '\n'+ 'Шифр Гронсфельда - дешифрование:'
, Vizhener( Vizhener( 'GRONSFELD', Vizhener_key ), Vizhener_key, 'decrypt' ) //выдаст GRONSFELD - из шифра Бофора.
, '\n'+ 'Сравнение с сообщением: ', "( decrypted === m )"
, ( Vizhener( Vizhener( 'GRONSFELD', Vizhener_key ), Vizhener_key, 'decrypt' ) === 'GRONSFELD' ) //'GRONSFELD'? true
);
//4. Шифр Виженера (полная версия):
//Параметры: m - сообщение/шифротекст, k - ключ, mode - "encrypt"/"decrypt"
console.log(
'\n4. Шифр Виженера (полная версия):'
, '\n'+ 'm = ', m, ' - сообщение'
, '\n'+ 'k = ', k, '- ключ'
, '\n'+ 'Шифр Виженера - шифрование: ', Vizhener( m, k ) //выдаст LXFOPVEFRNHR - шифр Виженера
, '\n'+ 'Шифр Виженера - дешифрование: '
, Vizhener( Vizhener(m, k), k, 'decrypt' ) //выдаст ATTACKATDAWN - из шифра Виженера
, '\n'+ 'Сравнение с сообщением: ', "( decrypted === m )"
, ( Vizhener( Vizhener( m, k, 'encrypt'), k, 'decrypt' ) === m ) //m? true
);
//5. Шифр Бофора - через шифр Виженера (там другая таблица и шифротекст - сдвинутый атбаш по строкам).
//Параметры: m - ключ, k - сообщение/шифротекст, mode - 'decrypt' (только дешифрование)
//Особенность шифра Бофора - в том, что дешифрование представляет из себя повторное шифрование шифротекста - тем же ключом.
//То есть - одна и та же операция.
console.log(
"\n5. Шифр Бофора (в талбице - атбаш по строкам):"
, '\n'+ 'm = ', m, ' - сообщение'
, '\n'+ 'k = ', k, '- ключ'
, '\n'+ 'Шифр Бофора - шифрование по таблице Виженера: '
, Vizhener( k, m, 'decrypt' ) //выдаст LLTOLBETLNPR - шифр Бофора
, '\n'+ 'Шифр Бофора - дешифрование по таблице Виженера:'
, Vizhener( k, Vizhener( k, m, 'decrypt' ), 'decrypt' ) //выдаст ATTACKATDAWN - из шифра Бофора.
, '\n'+ 'Сравнение с сообщением: ', "( decrypted === m )"
, ( Vizhener( k, Vizhener( k, m, 'decrypt' ), 'decrypt' ) === m ) //m? true
);
//6. Сдвинутый атбаш - через шифр Виженера (там другая таблица и шифротекст - атбаш, сдвинутый и по строкам по столбцам).
//Параметры: m или k - сообщение/шифротекст и ключ (или наоборот), mode - 'shifted_atbash'(только encrypt + атбаш к результату)
//Мало того, что одна и та же операция (дешифрование - есть шифрование шифротекста), но к тому же она ещё и коммутативна.
//То есть, здесь, n-ные буквы (сообщения/шифротекста) и ключа - могут быть поменяны местами, давая тот же результат.
//Именно этим, сдвинутый атбаш - и приближается к шифру Вернама,
//так как при дешифровании шифром Вернама - операции XOR не важно где именно байты ключа, а где - байты шифротекста.
console.log(
"\n6. Сдвинутый атбаш (в таблице атбаш, сдвинутый и по строкам и по столбцам):"
, '\n'+ 'm = ', m, ' - сообщение'
, '\n'+ 'k = ', k, '- ключ'
, '\n'+ 'Сдвинутый атбаш - шифрование по таблице Виженера: '
, Vizhener( m, k, 'shifted_atbash' ) //выдаст OCULKEVUIMSI - шифр сдвинутого атбаша.
, 'Тест коммутативности замены: '
, Vizhener( k, m, 'shifted_atbash' ) //То же самое, не важно где ключ, а где сообщение.
, '\n'+ 'Сдвинутый атбаш - дешифрование по таблице Виженера: '
, Vizhener( Vizhener( k, m, 'shifted_atbash' ), k, 'shifted_atbash' ) //выдаст ATTACKATDAWN - из шифра сдвинутого атбаша.
, 'Тест коммутативности замены: '
, Vizhener( k, Vizhener( k, m, 'shifted_atbash' ), 'shifted_atbash' ) //То же самое, не важно где ключ, а где шифротекст.
, '\n'+ 'Сравнение с сообщением: '
, "( decrypted === m )"
, ( Vizhener( k, Vizhener( k, m, 'shifted_atbash' ), 'shifted_atbash' ) === m ) //m? true
, '\n'+ 'Коммутативность замены: '
, (
(Vizhener( m, k, 'shifted_atbash') === Vizhener( k, m, 'shifted_atbash'))
&& (
Vizhener( Vizhener( k, m, 'shifted_atbash' ), k, 'shifted_atbash' )
===
Vizhener( k, Vizhener( k, m, 'shifted_atbash' ), 'shifted_atbash' )
)
) //Коммутативность? true
);
Delphi 10
program Vigenere;
uses
System.SysUtils, Winapi.Windows;
const
cmGronsfeld: Byte = 1;
cmShiftedAtbash: Byte = 2;
cmDecrypt: Byte = 4;
YesNo: array[Boolean] of string = ('нет', 'да');
var
log: TStringBuilder;
function VigenereCrypt(m, k: string; mode: Byte = 0): string;
const
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; //Строка алфавита
var
maxLength, i, mi, ki, ix: Integer;
r, ki_s, c: string;
gronsfeld, shiftedAtbash, decrypt: Boolean;
begin
//(encrypt/decrypt) for "Gronsfeld" + "Vigenere" + "Beaufort" + "Shifted Atbash"
//m - сообщение или шифротекст (может быть и ключ, если шифр Бофора),
//k - ключ (или сообщение/шифротекст, если шифр Бофора),
//mode - режим:
// Шифрование: "encrypt" (по умолчанию),
// Дешифрование: "decrypt" (mode === 'decrypt'),
// Шифрование-дешифрование по таблице сдвинутого атбаша: (mode = cmShiftedAtbash)
// Извлечение цифр из ключа шифра Гронсфельда: "gronsfeld" или "gronsfeld_encrypt", "gronsfeld decrypt".
maxLength := m.Length;
if k.Length > maxLength then maxLength := k.Length;
Result := ''; //Пустой результат
gronsfeld := (mode and cmGronsfeld) > 0;
shiftedAtbash := (mode and cmShiftedAtbash) > 0;
decrypt := (mode and cmDecrypt) > 0;
for i := 0 to maxlength-1 do begin //encrypt/decrypt
//Vigenere - encrypt/decrypt one forumula (encrypt - by default; decrypt - when (cmDecrypt is in mode) )
//подгон сообщения/шифротекста - к ключу (если меньше)
if i >= m.length then ix := i mod m.Length else ix := i;
mi := a.IndexOf(m[ix + 1]);
if i >= k.length then ix := i mod k.Length else ix := i;
ki_s := k[ix + 1];
//подгон ключа к сообщению/шифротексту (если короткий)
if gronsfeld then ki := ki_s.ToInteger() else ki := a.IndexOf(ki_s);
//вычитание при дешифровании, либо сложение.
if decrypt then ki := ki * -1;
c := a[((a.Length + mi + ki) mod a.Length) + 1]; //символ по таблице Виженера.
if shiftedAtbash then c := a[a.Length - a.IndexOf(c)]; //Атбаш символа или символ.
Result := Result + c; //Добавить символ к результату.
end;
end;
function GronsfeldToVigenere(GfKey: string): string;
const
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; //Строка алфавита
var
i: Integer;
begin
Result := '';
for i := 1 to Length(GfKey) do
Result := Result + a[StrToInt(GfKey[i]) + 1];
end;
function VigenereToGronsfeld(VgKey: string): string;
const
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; //Строка алфавита
var
i: Integer;
begin
Result := '';
for i := 1 to Length(VgKey) do
Result := Result + IntToStr(a.indexOf(VgKey[i])); //2015
end;
procedure GronsfeldTest();
const
MSG = 'GRONSFELD';
KEY = '2015';
TXT = '1. Шифр Гронсфельда (Урезанная версия шифра Виженера c цифровым ключом):'#13#10+
'Сообщение:'#9'"%s"'#13#10+
'Ключ:'#9#9'"%s"'#13#10+
'Шифрование:'#9'"%s" (должно быть "IRPSUFFQF")'#13#10+
'Дешифрование:'#9'"%s" (должно быть "%s")'#13#10+
'Совпадает:'#9'%s'#13#10;
var
crypted, decrypted: string;
begin
//1. Шифр Гронсфельда. (Урезанная версия шифра Виженера).
//Параметры: m - сообщение/шифротекст, k - ключ (только цифры), mode - "encrypt/decrypt"
crypted := VigenereCrypt(MSG, KEY, cmGronsfeld); //выдаст IRPSUFFQF - шифр Гронсфельда
decrypted := VigenereCrypt(crypted, KEY, cmGronsfeld or cmDecrypt); //выдаст GRONSFELD - из шифра Гронсфельда
log.AppendFormat(TXT, [MSG, KEY, crypted, decrypted, MSG, YesNo[decrypted = MSG]]);
end;
procedure VigenereToGronsfeldTest();
const
GKEY = '2015';
TXT = #13#10'2. Конвертация ключа Гронсфельда в ключ Виженера:'#13#10+
'Gronsfeld key: "%s" >>> Vigenère key: "%s" и назад: "%s"'#13#10;
var
GronsfeldKey2: string;
VigenereKey: string;
begin
//2. Также, вместо цифр, в шифре Гронсфельда - возможно и указание букв.
//Тогда, шифром Гронсфельда будет обычный шифр Виженера, но с ограничением символов на ключ.
//Например, при всех возможных цифрах в ключе "0123456789", ключ может быть только из букв "ABCDEFGHIJ"
//Получить его можно так:
VigenereKey := GronsfeldToVigenere(GKEY); //CABF
//И наоборот:
GronsfeldKey2 := VigenereToGronsfeld(VigenereKey); //2015
log.AppendFormat(TXT, [GKEY, VigenereKey, GronsfeldKey2]);
end;
procedure GronsfeldAsVigenereTest();
const
MSG = 'GRONSFELD';
KEY = 'CABF';
TXT = #13#10'3. Шифр Гронсфельда - с ключом Виженера, по таблице Виженера:'#13#10+
'Сообщение:'#9'"%s"'#13#10+
'Ключ:'#9#9'"%s"'#13#10+
'Шифрование:'#9'"%s" (должно быть "IRPSUFFQF")'#13#10+
'Дешифрование:'#9'"%s" (должно быть "%s")'#13#10+
'Совпадает:'#9'%s'#13#10;
var
crypted, decrypted: string;
begin
//3. Тогда шифрование-дешифрование шифра Гронсфельда - есть работа с шифром Виженера:
crypted := VigenereCrypt(MSG, KEY); //выдаст IRPSUFFQF - шифр Бофора
decrypted := VigenereCrypt(crypted, KEY, cmDecrypt); //выдаст GRONSFELD - из шифра Бофора.
log.AppendFormat(TXT, [MSG, KEY, crypted, decrypted, MSG, YesNo[decrypted = MSG]]);
end;
procedure VigenereFullTest();
const
MSG = 'ATTACKATDAWN'; //Сообщение
KEY = 'LEMON'; //Ключ
TXT = #13#10'4. Шифр Виженера (полная версия):'#13#10+
'Сообщение:'#9'"%s"'#13#10+
'Ключ:'#9#9'"%s"'#13#10+
'Шифрование:'#9'"%s" (должно быть "LXFOPVEFRNHR")'#13#10+
'Дешифрование:'#9'"%s" (должно быть "%s")'#13#10+
'Совпадает:'#9'%s'#13#10;
var
crypted, decrypted: string;
begin
//4. Шифр Виженера (полная версия):
//Параметры: m - сообщение/шифротекст, k - ключ, mode - "encrypt"/"decrypt"
crypted := VigenereCrypt(MSG, KEY); //выдаст LXFOPVEFRNHR - шифр Виженера
decrypted := VigenereCrypt(crypted, KEY, cmDecrypt); //выдаст ATTACKATDAWN - из шифра Виженера
log.AppendFormat(TXT, [MSG, KEY, crypted, decrypted, MSG, YesNo[decrypted = MSG]]);
end;
procedure BeaufortTest();
const
MSG = 'ATTACKATDAWN'; //Сообщение
KEY = 'LEMON'; //Ключ
TXT = #13#10'5. Шифр Бофора (в талбице - атбаш по строкам):'#13#10+
'Сообщение:'#9'"%s"'#13#10+
'Ключ:'#9#9'"%s"'#13#10+
'Шифр Бофора по таблице Виженера:'#13#10+
'Шифрование:'#9'"%s" (должно быть "LLTOLBETLNPR")'#13#10+
'Дешифрование:'#9'"%s" (должно быть "%s")'#13#10+
'Совпадает:'#9'%s'#13#10;
var
crypted, decrypted: string;
begin
//5. Шифр Бофора - через шифр Виженера (там другая таблица и шифротекст - сдвинутый атбаш по строкам).
//Параметры: m - ключ, k - сообщение/шифротекст, mode - 'decrypt' (только дешифрование)
//Особенность шифра Бофора - в том, что дешифрование представляет из себя повторное шифрование шифротекста - тем же ключом.
//То есть - одна и та же операция.
crypted := VigenereCrypt(KEY, MSG, cmDecrypt); //выдаст LLTOLBETLNPR - шифр Бофора
decrypted := VigenereCrypt(KEY, crypted, cmDecrypt); //выдаст ATTACKATDAWN - из шифра Бофора.
log.AppendFormat(TXT, [MSG, KEY, crypted, decrypted, MSG, YesNo[decrypted = MSG]]);
end;
procedure ShiftedAtbashTest();
const
MSG = 'ATTACKATDAWN'; //Сообщение
KEY = 'LEMON'; //Ключ
TXT = #13#10'6. Сдвинутый атбаш (в таблице атбаш, сдвинутый и по строкам и по столбцам):'#13#10 +
'Сообщение:'#9'"%s"'#13#10 +
'Ключ:'#9#9'"%s"'#13#10 +
'Сдвинутый атбаш - шифрование по таблице Виженера:'#9'"%s" (должно быть "OCULKEVUIMSI")'#13#10 +
'Тест коммутативности замены:'#9'"%s" (должно быть "OCULKEVUIMSI")'#13#10 +
'Сдвинутый атбаш - дешифрование по таблице Виженера:'#9'"%s" (должно быть "ATTACKATDAWN")'#13#10 +
'Тест коммутативности замены:'#9'"%s"'#13#10 +
'Сравнение с сообщением:'#9'%s'#13#10 +
'Коммутативность замены:'#9'%s';
var
csaMK, csaKM, csaKMK, csaKKM: string;
begin
//6. Сдвинутый атбаш - через шифр Виженера (там другая таблица и шифротекст - атбаш, сдвинутый и по строкам по столбцам).
//Параметры: m или k - сообщение/шифротекст и ключ (или наоборот), mode - cmShiftedAtbash (только encrypt + атбаш к результату)
//Мало того, что одна и та же операция (дешифрование - есть шифрование шифротекста), но к тому же она ещё и коммутативна.
//То есть, здесь, n-ные буквы (сообщения/шифротекста) и ключа - могут быть поменяны местами, давая тот же результат.
//Именно этим, сдвинутый атбаш - и приближается к шифру Вернама,
//так как при дешифровании шифром Вернама - операции XOR не важно где именно байты ключа, а где - байты шифротекста.
csaMK := VigenereCrypt(MSG, KEY, cmShiftedAtbash); //выдаст OCULKEVUIMSI - шифр сдвинутого атбаша.
csaKM := VigenereCrypt(KEY, MSG, cmShiftedAtbash); //То же самое, не важно где ключ, а где сообщение.
csaKMK := VigenereCrypt(csaKM, KEY, cmShiftedAtbash); //выдаст ATTACKATDAWN - из шифра сдвинутого атбаша.
csaKKM := VigenereCrypt(KEY, csaKM, cmShiftedAtbash); //То же самое, не важно где ключ, а где шифротекст.
log.AppendFormat(TXT, [MSG, KEY, csaMK, csaKM, csaKMK, csaKKM,
YesNo[csaKKM = MSG], YesNo[(csaMK = csaKM) and (csaKMK = csaKKM)]]);
end;
begin
log := TStringBuilder.Create();
try
//Тесты:
GronsfeldTest();
VigenereToGronsfeldTest();
GronsfeldAsVigenereTest();
VigenereFullTest();
BeaufortTest();
ShiftedAtbashTest();
MessageBoxW(GetDesktopWindow(), PWideChar(log.ToString()), 'Vigenère', 0);
finally
log.Free();
end;
end.
Ruby
class Crypto
class CryptoError < StandardError ; self; end
attr_reader :alphabet
# принимает произвольный массив уникальных символов, может быть одного или нескольких языков, по умолчанию латинские строчные буквы
def initialize(alphabet = ('A'..'Z').to_a)
@alphabet = alphabet
check_alphabet
end
# c{j}=(m{j}+k{j}) mod {n}
def encode(key_str, text_srt)
key_arr = str_to_alphabet_index_arr(key_str)
char_number_at_text = 0
str_to_alphabet_index_arr(text_srt).inject("") do |r, letter_index|
encode_letter_index = (letter_index + key_arr[char_number_at_text % key_arr.size]) % alphabet.size
char_number_at_text += 1
r + alphabet[encode_letter_index]
end
end
# m{j}=(c{j} + n - k{j}) mod {n}
def decode(key_str, text_srt)
key_arr = str_to_alphabet_index_arr(key_str)
char_number_at_text = 0
str_to_alphabet_index_arr(text_srt).inject("") do |r, letter_index|
decode_letter_index = (letter_index + alphabet.size - key_arr[char_number_at_text % key_arr.size]) % alphabet.size
char_number_at_text += 1
r + alphabet[decode_letter_index]
end
end
private
def str_to_alphabet_index_arr(str)
str.chars.map do |char|
index = alphabet.index(char)
if index
index
else
raise CryptoError, 'letters should be at alphabet'
end
end
end
def check_alphabet
raise CryptoError, 'alphabet should be array' unless alphabet.is_a?(Array)
raise CryptoError, 'letters should be strings' if alphabet.any? { |letter| !letter.is_a?(String) }
raise CryptoError, 'alphabet should contain at least one letter' if alphabet.size < 1
raise CryptoError, 'letters should be unique' if alphabet.uniq.size != alphabet.size
raise CryptoError, 'letter should not be blank' if alphabet.any?(&:empty?)
raise CryptoError, 'letters should contain just one char' if alphabet.any? { |letter| letter.size != 1 }
end
end
# примеры
crypto = Crypto.new
crypto.encode('LEMON', 'ATTACKATDAWN') # "LXFOPVEFRNHR"
crypto.decode('LEMON', 'LXFOPVEFRNHR') # "ATTACKATDAWN"
crypto.encode('LEMON', 'attack') # Crypto::CryptoError: letters should be at alphabet
rus_crypto = Crypto.new(('А'..'Я').to_a)
rus_crypto.encode('КВАС', 'МАМАМЫЛАРАМУ') # "ЦВМСЦЭЛСЪВМД"
rus_crypto.decode('КВАС', 'ЦВМСЦЭЛСЪВМД') # "МАМАМЫЛАРАМУ"
Примечания
- Martin, Keith M. Everyday Cryptography (англ.) . — Oxford University Press, 2012. — P. 142. — ISBN 978-0-19-162588-6 .
- . rain.ifmo.ru. Дата обращения: 22 декабря 2017. Архивировано из 21 декабря 2017 года.
- Сергей и Марина Бондаренко (2015-07-08). . 3DNews - Daily Digital Digest . из оригинала 23 декабря 2017 . Дата обращения: 22 декабря 2017 .
- ↑ Бабаш А.В., Шанкин Г.П. . — М.: Гелиос АРВ, 2002. — С. 240 с.. — ISBN 5854380439 .
- Smith, Laurence D. Substitution Ciphers // Cryptography the Science of Secret Writing: The Science of Secret Writing (англ.) . — Dover Publications , 1943. — P. 81. — ISBN 0-486-20247-X .
- ↑ Носов В. А. (рус.) // Московский университет и развитие криптографии а России. Материалы конференции в МГУ.. — (17 октября 2002). 26 января 2012 года.
- ↑ David, Kahn. The Codebreakers: The Story of Secret Writing. — Simon & Schuster, 1999. — ISBN 0-684-83130-9 .
- Knudsen, Lars R. Block Ciphers—a survey. — London: Springer, 1997. — ISBN 3-540-65474-7 .
- Stanislaw Jarecki. // University of California. — 2004. 17 мая 2017 года.
- Richard A. Mollin. . — Chapman and Hall/CRC, 2005. — 704 Pages с. — ISBN 9781584884705 .
- — М. : , 1996. — 336 с. — ISBN 978-5-87484-054-9
- , с. 60.
- Singh S. The Code Book: The Science of Secrecy from Ancient Egypt to Quantum Cryptography. — New York City: Doubleday, 1999. — 416 p. с. — ISBN 978-1-85702-879-9 .
- // CS 415: Computer and Network Security. — 2006. 23 июля 2011 года.
- Arto Salomaa. Public-Key Cryptography. — ISBN 3540528318 .
Литература
- Романьков В.А Введение в криптографию: курс лекций, 2009. — 238 с. — ISBN 5777909825 .
- Бабаш А. В., Шанкин Г. П. История криптографии. Часть I. — М.: Гелиос АРВ, 2002. — 240 с. — ISBN 5854380439 .
- — М. : , 1996. — 336 с. — ISBN 978-5-87484-054-9
- Arto Salomaa. Public-Key Cryptography. — ISBN 3540528318 .
- Н. Смарт. Криптография.. — Москва: Техносфера, 2005. — 528 с. — ISBN 5-94836-043-1 .
- Синклер Маккей. Шифры цивилизации Коды, секретные послания и тайные знаки в истории человечества = Sinclair Mckay. 50 codes that changed the world: And Your Chance to Solve Them!. — М. : Альпина Паблишер, 2023. — С. 416. — ISBN 978-5-9614-8368-0 . .
- Singh S. The Code Book , Histoire des codes secrets (англ.) : The Science of Secrecy from Ancient Egypt to Quantum Cryptography, De l'Égypte des pharaons à l'ordinateur quantique — New York City: Doubleday , , 1999. — 416 p.
- Richard A. Mollin. Codes: The Guide to Secrecy From Ancient to Modern Times. — Chapman and Hall/CRC, 2005. — 704 Pages с. — ISBN 9781584884705 .
- Martin, Keith M. Everyday Cryptography. — Oxford University Press, 2012. — 142 с. — ISBN 978-0-19-162588-6
- Knudsen, Lars R. Block Ciphers—a survey. — London: Springer, 1997. — ISBN 3-540-65474-7 .
- Henk C.A. van Tilborg. Encyclopedia of Cryptography and Security. — Springer, 2005. — 115 с. — ISBN 038723473X .
- Arto Salomaa. Public-Key Cryptography. — ISBN 3540528318 .
Ссылки
- Носов В. А. (рус.) // Московский университет и развитие криптографии а России. Материалы конференции в МГУ.. — (17 октября 2002).
- Stanislaw Jarecki // University of California. — 2004.
- // CS 415: Computer and Network Security. — 2006.
- 2020-01-08
- 1