JavaRush /Курсы /Harvard CS50 /Криптография. Шифр Цезаря и шифр Виженера

Криптография. Шифр Цезаря и шифр Виженера

Harvard CS50
2 уровень , 7 лекция
Открыта

Криптография, наука о шифровке и дешифровке информации… На самом деле наука о шифровке посланий существовала задолго до компьютерных времён. Разнообразную тайнопись использовали ещё армии Римской Империи для передачи секретных сообщений. Сейчас наука набрала обороты, и ею пользуются все. Скажем, ваши пароли в Facebook и других социальных сетях хранятся в зашифрованном виде. 

Теоретические сведения

Для начала мы изучим один из простейших шифров — шифр Цезаря, названный в честь римского императора. В этом шифре каждая буква текста заменяется на другую, которая находится на фиксированное число букв дальше в алфавите. Это фиксированное число букв называется ключом. Так, ключ 1 переводит букву латиницы C в букву D, а Z — по циклу в A. Если ключ равен 3, то буква C перейдет в F, а Z — в C. 

Примеры: используем шифр Цезаря с ключом 5 на слове cat.

c -> h
a -> f
t -> y 
Caesar (cat, 5) = hfy

Ключ = 7, слово = computer

c->j
o->v
m->t
p->w
u->b
t->a
e->l
r->y
Caesar(computer,7) = jvtwbaly
Криптография. Шифр Цезаря и шифр Виженера - 1

Шифр Цезаря прост, но, увы, ненадёжен (это взаимосвязанные вещи!): для английского алфавита — всего 25 вариантов шифровки, перебрать все возможные варианты легко даже без компьютера. Тем не менее, шифр Цезаря часто используют в качестве шага в других шифрах, таких, как шифр Виженера (о нём — в следующем пункте).

«Математизируем» шифр Цезаря. Обозначим незашифрованный текст буквой p, а pi — буква в тексте p, которая находится на позиции с номером i. Назовем секретный ключ буквой k, с — зашифрованный текст, а ci — буква в шифрованном тексте, которая находится на позиции i. Тогда вычислить каждую букву шифра можно по формуле: 

ci = (pi + k) % 26

Привыкайте к такой формализации, она позволяет программировать алгоритм и выражает смысл шифра точно и сжато.

Если ключ k = 13 а изначальный текст p — «Be sure to drink your Ovaltine!», вот какой шифр мы получим:

Or fher gb qevax lbhe Binygvar!

Обратите внимание, O (первая буква в шифрованном тексте) смещена на 13 позиций от буквы B (первая буква в оригинальном тексте). То же самое с буквой r (вторая буква в шифровке) смещена на 13 букв от e (вторая буква в оригинале). Третья буква в шифровке, f, смещена на 13 букв от s (третья в оригинале), тут мы ходим по кругу от z до a.

Шифр Цезаря с ключом 13 имеет специальное название ROT13. Он симметричный: применив его дважды, мы вернемся к изначальному тексту. Конечно, есть еще и ROT26, этот вообще супер-секьюрный, но только если вы нечётко выражаете свои мысли =). 

Шифр Виженера

Шифр Виженера несколько безопаснее шифра Цезаря: в качестве ключа в нем используется слово и его сложно взломать вручную с помощью одного только частотного анализа или перебора. Каждая буква ключа генерирует число, и в результате мы получаем несколько ключей для сдвига букв.

Пример:

p = Meet me in the park at eleven am 
В качестве ключевого слова возьмем 
k = bacon
Длина сообщения p = 25 
В то время как длина k = 5 
Поэтому его нужно повторять 5 раз.
Криптография. Шифр Цезаря и шифр Виженера - 2

Если число букв в сообщении не делится на ключ нацело, мы в последнем применении ключа используем только его часть:

Криптография. Шифр Цезаря и шифр Виженера - 3

Чтобы найти значение для смещения, используем позиции каждой буквы нашего ключа bacon в алфавите (от a до z). Считаем с нуля, как истинные программисты. И каждую букву в оригинальном тексте смещаем на заданное число, как в шифре Цезаря, возвращаясь при надобности после Z в начало алфавита. Таким образом, M сместится на 1, первая e вообще не сместится, а вторая сместится на 2 позиции. Ниже вы видите изначальное сообщение, расписанный ключ и результат его применения.

Криптография. Шифр Цезаря и шифр Виженера - 4

Шифр Виженера, конечно, понадежнее, но если вы знаете длину ключа, его сломать довольно просто. Как её выявить? Если оригинальный текст достаточно длинный, чтобы некоторые слова встречались в нем несколько раз, то вы увидите некоторые повторения:

Криптография. Шифр Цезаря и шифр Виженера - 5

Также можно использовать полный перебор, но вариантов немало: 26^n – 1 где n — длина неизвестного ключа. Но обычно это немало. Правда, для компьютера это не проблема.

А теперь — математика шифра:

Пусть р – некоторый текст, k — ключевое слово, kj — j-я буква ключа, pi — буква под номером i в оригинальном тексте, ci — буква под номером i в шифровке. Тогда:

ci = (pi + kj) % 26
Комментарии (24)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Radio_Bashka Уровень 1
7 апреля 2022
Не понятно вообще формула ci = (pi + kj) % 26 Если а=1, b =2 и тд , и kj небольшие числа, то вообще чушь получается
Radio_Bashka Уровень 1
7 апреля 2022
в общем разобралс\я % 26 это mod( остаток от деления)
Samurai Уровень 10
2 марта 2021
Если ты еще не почел эту статью, то не стоит) лучше посмотрите видео или почитайте об этой статье в другом месте....
дима тарасов Уровень 4
25 апреля 2021
https://www.youtube.com/watch?v=DMp55himLK4 вот например
Daniil Уровень 0
27 августа 2020
ребят подскажите что не так пишу ? #include <stdio.h> #define MAXLINE 1000 //максчимальный размер вводимой строки int get_line(char line [], int MAXLINE); void copy (char to[], char from[]); // печать самой длинной строки int main(void) { int len; // длина текущей строки int max; // длина максимальной из просмотренных строк char line [MAXLINE]; // текущая строка char longest [MAXLINE]; // САМая длинная строка max = 0; while (len = get_line (line,MAXLINE) > 0 ) if (len > max) { max = len; copy (longest, line ); } if (max > 0)// если длина максимально изь просмотренных строк > 0 printf("%s", longest); return 0; } //get_line : читатет строку в s, возвращает длину int get_line(char s [], int lim) { int c,i; for(i = 0; i < lim - 1 && (c = getchar ()) != EOF && c != '\n'; ++i) s[i] = c ; if ( c== '\n') { s[i] = c; ++i; } s[i] = '\0'; return i; } //copy: копирует из from в to : to достаточно большой void copy (char to[],char from[]) { int i; i = 0; while ((to[i] from[i]) != '\0') ++i; }
Maxim Sunshine Уровень 0
8 июля 2020
Однако сложно...
Павел Арестов Уровень 5
26 января 2020
несколько несколько
Дмитрий Уровень 37
9 января 2020
Реализовал шифр Виженера на java. Вот ссылочка gitHub
6 мая 2020
У Вас ссылка на страницу с 404 ошибкой
Дмитрий Уровень 37
22 мая 2020
почистил git
Ava Уровень 18
6 ноября 2018
Значит я еще в детстве занимался шифрованием. А я думал, что новый язык придумал. =) Я переворачивал слова по мягкости-твердости, т.е. Б->П, З->C, А->Я, О->Ё, Ь->Ъ и так далее. (c) Стэзъ пил Яфя.
Виктория Уровень 0
12 апреля 2019
мы тоже :)
Azazil47 Уровень 22
25 сентября 2018
А зачем там проценты? ci = (pi + k) % 26 или тут ci = (pi + kj) % 26 Никак не пойму....
Vadim GAMZA Уровень 0
13 декабря 2018
Процент - это остаток от деления на число. Используется для того, чтобы зациклить алфавит, т.е. после z шла a. Например: Есть Х, его нужно сдвинуть на 100 символов. По факту букв 25, тоесть мы пройдем несколько кругов если будем идти чисто по алфавиту. А если пойдем по ASCII то вообще забредем не туда куда нужно. Поэтому используем модуль: 100 % 26 = 22. В итоге мы сдвинемся на 22 символа, и получим нужный результат.
Dmitriy Davidov Уровень 1
23 ноября 2017
ci = (pi + kj) % 26 это Формула для АЛФАВИТА. В алфавите A=0, B=1, C=2 ...
Eugene Ostapenko Уровень 0
5 октября 2017
На самом деле формула и пояснение к ней подается с неточностью, о которую можно сломать мозг, что я успешно и делал в течение 2-х часов. Что я имею ввиду, у вас написано: >>pi — буква в тексте p, которая находится на позиции с номером i Вот тут и есть ловушка, pi это номер (В АЛФАВИТЕ) БУКВЫ которая находится на позиции с номером i. Т.е. в алфавите A это 1, а в ASCII это 65. Поэтому если применить формулу как есть в цикле, то корректно она работать не будет. Например, при k=1, берем Z (ascii = 90), далее (90+1) MOD 26 = 13, что соответствует возврату каретки, а должны получить, следующую за Z букву, т.е. А с ascii кодом 65. Поэтому нужно при кажой операции вычислять номер символа в алфавите. Т.е. для заглавных английских формула такая: putchar((p[i] - 65 + k) % 26 + 65); Для строчных английских такая: putchar((p[i] - 97 + k) % 26 + 97); Не думаю что это всем очевидно, предложил бы добавить уточнение к формуле шифра Цезаря. Еще не смотрел Виженера, но думаю там такая же ист
Eugene Ostapenko Уровень 0
5 октября 2017
И еще вопрос, при попытке провести тесты с помощью check50 нужно вводить имя пользователя гита и пароль. Есть какой то общий аккаунт или надо где то регистрироваться? ~/workspace/ $ check50 cs50/2017/fall/caesar Connecting...... Authenticating..... GitHub username: cs50 GitHub password: **** Invalid username and/or password. Submission cancelled.
hidden #1126476 Уровень 36
18 октября 2017
Евгений, нужно просто завести себе аккаунт на Гитхабе и пользоваться им.
Дарья Шилова Уровень 9
30 декабря 2018
Нужно зарегистрироваться на github Это вроде форума программистов
дима тарасов Уровень 4
19 октября 2019
Молодец, предлагаю отредактировать немного статью. Очень грамотно объяснил :)
Ivan Уровень 41
24 августа 2021
Тут наверно не ASCII имеется ввиду, тут скорее всего речь про массив с символами алфавита: char[] array = {'A', 'B', 'C', ..., 'Z'}; и тогда все встает на свои места.
hidden #2969529 Уровень 1
17 марта 2022
Иван, вам бы в политику) *это шутка про хорошие и логичные объяснения, подстраиваемые под данность) А на самом деле да, если представить алфавит в виде массива, да так оно и работает)
hidden #2969529 Уровень 1
17 марта 2022
Я всё равно не понимаю... Если мы говорим про алфавит: ci = (pi + k) % 26 pi = А k = 2 ci = 3 % 26?! Остаток от целочисленного деления равен нулю! Если бы это было под оператором IF с нужным условием... Но нет же...
Shahin Уровень 2
8 октября 2022
"А" это 0, а не 1. Представь что алфавит это массив букв. А в массиве отчёт начинается с 0. Следовательно, (0+2)%26 = 2. А 2 это индекс буквы "С" в массиве английского алфавита. Получилось смещение на 2 шага вперёд.