AES и режимы шифрования
AES — это стандарт, которым зашифрован почти весь современный интернет. Разберём его идею и важную тонкость — режимы работы.
Что такое AES
AES (Advanced Encryption Standard) — блочный шифр, принятый как мировой стандарт в 2001 году. Он шифрует данные блоками по 16 байт, используя ключ длиной 128, 192 или 256 бит. Внутри AES много раундов перемешивания: байты переставляются, заменяются по таблице и смешиваются между собой. После 10–14 таких раундов от исходных данных не остаётся никаких заметных закономерностей.
Нам не нужно реализовывать AES вручную — это сложно и опасно делать самому. Важно понимать одну ключевую идею: как именно блоки соединяются друг с другом. За это отвечают режимы.
Режим ECB и его проблема
Самый простой режим — ECB (Electronic Codebook): каждый блок шифруется независимо одним и тем же ключом. Звучит логично, но есть ловушка: одинаковые блоки открытого текста дают одинаковые блоки шифр-текста. Это значит, что повторы в данных «просвечивают» сквозь шифр.
def ecb_encrypt(blocks, key):
# упрощённо: каждый блок шифруется одинаково и независимо
return [tuple(b ^ key for b in block) for block in blocks]
# Картинка с большими одноцветными областями = повторяющиеся блоки
image = [(1, 1, 1, 1), (1, 1, 1, 1), (9, 2, 7, 3), (1, 1, 1, 1)]
encrypted = ecb_encrypt(image, key=42)
for block in encrypted:
print(block)Вывод:
(43, 43, 43, 43) (43, 43, 43, 43) (35, 40, 45, 41) (43, 43, 43, 43)
Видишь проблему? Одинаковые блоки фона (1,1,1,1) превратились в одинаковые (43,43,43,43). Если так зашифровать картинку, контуры объектов будут видны прямо на «зашифрованном» изображении! Это знаменитый пример «ECB-пингвина».
Как чинят: режим CBC
Лучшие режимы (например, CBC) связывают блоки в цепочку: каждый блок перед шифрованием смешивается с предыдущим зашифрованным блоком. Тогда даже одинаковые куски данных дают разный шифр-текст. Покажем идею сцепления:
def cbc_demo(blocks, key, iv):
result, prev = [], iv
for block in blocks:
mixed = [b ^ p for b, p in zip(block, prev)] # смешиваем с предыдущим
enc = [m ^ key for m in mixed] # шифруем
result.append(tuple(enc))
prev = enc # цепочка
return result
image = [(1, 1, 1, 1), (1, 1, 1, 1), (1, 1, 1, 1)]
for block in cbc_demo(image, key=42, iv=[5, 9, 2, 7]):
print(block)Вывод:
(46, 38, 47, 35) (36, 36, 36, 36) (10, 10, 10, 10)
Теперь три одинаковых блока дали три разных результата — закономерность исчезла. iv (вектор инициализации) — это случайное стартовое значение, благодаря которому даже одинаковые сообщения шифруются по-разному.
Вывод
Сам алгоритм AES надёжен, но использовать его в режиме ECB — грубая ошибка. Правильный режим так же важен, как и сам шифр.