Криптография
Шифрование, кодирование и хеширование: что делает каждое
Разделяем кодирование, шифрование и хеширование на лабораторных с Base64, SHA-256 и OpenSSL. Почему Base64 ничего не защищает, а хеши необратимы.
Шифр Цезаря сдвигает каждую букву на фиксированное число позиций. Зашифруйте HELLO в KHOOR вручную, расшифруйте обратно и посмотрите, почему он ненадёжен.
Шифр Цезаря — шифр подстановки. Он заменяет каждую букву другой, отстоящей от неё на фиксированное число позиций в алфавите. Сдвиньте каждую букву на три позиции вперёд, и HELLO превратится в KHOOR. Название происходит от имени Юлия Цезаря, который, по преданию, использовал такой сдвиг в своих посланиях. Шифр достаточно прост, чтобы работать с ним вручную, и из-за этой простоты он почти не даёт защиты.
Запишите алфавит в одну строку. Во второй строке запишите тот же алфавит со сдвигом на три, с переходом на начало после Z:
Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Shift: DEFGHIJKLMNOPQRSTUVWXYZABCЧтобы зашифровать текст, найдите каждую букву открытого текста в верхней строке и выпишите букву прямо под ней. H становится K, E становится H, L становится O, а O становится R. В итоге HELLO превращается в KHOOR. Ключ — величина сдвига, здесь 3.
Пробелов, цифр и знаков препинания нет в алфавите от A до Z. Учебная версия может оставлять их без изменений, и код на Python ниже так и делает.
Расшифровка — та же таблица, прочитанная в обратном направлении. Сдвиньте каждую букву на три позиции назад, что равносильно сдвигу на 23 позиции вперёд:
KHOOR → HELLOПри заданном ключе каждой букве открытого текста соответствует ровно одна буква шифртекста, и обратное соответствие так же однозначно. Поэтому шифр можно обратить, если известен ключ.
В английском алфавите 26 букв, поэтому сдвиги повторяются каждые 26 позиций. Сдвиг на 29 даёт тот же результат, что и сдвиг на 3:
29 mod 26 = 3Сдвиг на −3 даёт тот же результат, что и сдвиг на 23. В коде берите сдвиг по модулю 26, тогда подойдёт любое целое число.
Эта функция сдвигает только буквы от A до Z и от a до z, всё остальное оставляет без изменений и переходит на начало алфавита по модулю 26. Для преобразования между буквами и числами она использует ord и chr:
def caesar(text, shift):
out = []
for ch in text:
if ch.isascii() and ch.isalpha():
base = ord('A') if ch.isupper() else ord('a')
out.append(chr((ord(ch) - base + shift) % 26 + base))
else:
out.append(ch)
return ''.join(out)
print(caesar("HELLO", 3))
print(caesar("KHOOR", -3))
print(caesar("KHOOR", 23))
print(caesar("HELLO", 29))
print(caesar("ATTACK AT DAWN", 3))
print(caesar(caesar("Hello, World!", 13), 13))
print(caesar("Hello, World!", 13))
print(caesar("hello, world", 3))
print(caesar("KHOOR", 26 - 3) == caesar("KHOOR", -3))
print(sum(1 for s in range(1, 26) if caesar("KHOOR", s) == "HELLO"))
print(caesar("HELLO", 3) == caesar("HELLO", 29))Вывод этого скрипта:
KHOOR
HELLO
HELLO
KHOOR
DWWDFN DW GDZQ
Hello, World!
Uryyb, Jbeyq!
khoor, zruog
True
1
TrueВывод подтверждает предыдущие разделы. Сдвиги −3 и 23 совпадают, 3 и 29 тоже. Из сдвигов от 1 до 25 только один превращает KHOOR обратно в HELLO. Двукратное применение сдвига 13 возвращает исходный текст: это случай ROT13, описанный ниже.
В алфавите из 26 букв есть всего 25 сдвигов, которые меняют текст. Атакующий может перебрать их все и посмотреть, какой результат читается. В английском тексте читаемый результат легко заметить, поэтому атака почти не требует усилий.
Частоты букв тоже сохраняются при сдвиге. В английском E встречается часто, а Z редко, поэтому шифртекст, где одна буква появляется намного чаще остальных, даёт сильную подсказку. Даже без перебора всех сдвигов подсчёт букв указывает на ключ.
Шифр полезен, чтобы освоить терминологию криптографии: открытый текст, шифртекст, ключ, подстановка и перебор. Защищать пароли, данные клиентов, API-ключи или личные файлы им нельзя. Настоящее шифрование использует стандартизованные алгоритмы, правильно сгенерированные ключи и аккуратное управление ключами. Формальные определения этой области даёт запись о криптографии в глоссарии NIST.
ROT13 — шифр Цезаря со сдвигом 13. Он сам себе обратный: двукратное применение возвращает исходный текст, потому что 13 + 13 = 26, а полный круг по алфавиту ничего не меняет. Результат ROT13 для Hello, World! — Uryyb, Jbeyq!, как показано выше.
ROT13 применяют, чтобы спрятать спойлеры или развязки шуток от случайного взгляда. Настоящей защиты он не даёт: любой, кто знает метод, прочитает текст за секунды.
Зашифруйте ATTACK AT DAWN вручную со сдвигом 3, сохранив пробелы. Сравните свой ответ с этим:
DWWDFN DW GDZQЗатем измените сдвиг в функции на Python и запустите её на том же тексте. Попробуйте сдвиг 0, сдвиг 26 и сдвиг 13 и предскажите каждый результат до запуска. Текст для проверки берите синтетический или свой собственный, а упражнение выполняйте на своей машине.
Когда будете готовы, в следующей статье, шифр Цезаря на Python, эта функция дополняется обработкой ввода и тестами.
Что ещё почитать: запись о криптографии в глоссарии NIST и документацию Python по ord и chr.
Криптография
Разделяем кодирование, шифрование и хеширование на лабораторных с Base64, SHA-256 и OpenSSL. Почему Base64 ничего не защищает, а хеши необратимы.
Криптография
Почему быстрые хеши не годятся для паролей, что делают соль и коэффициент нагрузки и как хешировать и проверять пароли с Argon2id в Python через argon2-cffi.
Криптография
Публичные и приватные ключи с нуля: что доказывает подпись, почему приватный ключ остаётся в секрете, и лабораторная на Ed25519, где изменённый файл не проходит проверку.