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 — грубая ошибка. Правильный режим так же важен, как и сам шифр.

Проверьте себя
1. Почему режим ECB небезопасен?
AОн слишком медленный
BОдинаковые блоки открытого текста дают одинаковые блоки шифр-текста, и закономерности просвечивают
CОн не использует ключ
DОн работает только с текстом
2. Зачем в режиме CBC нужен вектор инициализации (IV)?
AЧтобы ускорить шифрование
BЧтобы даже одинаковые сообщения шифровались по-разному
CЧтобы заменить ключ
DЧтобы укоротить шифр-текст
Поддержать проект