Перейти к содержанию
Learning Platform
Средний
25 минут
AES Симметричное шифрование SubBytes ShiftRows MixColumns

Симметричное шифрование: AES

Зачем это нужно в блокчейне

Зашифрованные кошельки (keystore файлы Ethereum, wallet.dat Bitcoin) используют AES для защиты приватных ключей паролем. Если кто-то получит ваш keystore файл, без пароля он бесполезен — благодаря AES.

Когда вы создаете кошелек в MetaMask или Geth, ваш приватный ключ шифруется AES-128-CTR (Ethereum) или AES-256-CBC (Bitcoin) перед сохранением на диск. Пароль, который вы вводите, превращается в ключ шифрования через функцию Key Derivation (scrypt или PBKDF2).

Симметричное шифрование — это фундамент защиты данных. Без понимания AES невозможно разобраться, как кошельки хранят ваши ключи.

Интуитивное объяснение

Симметричное шифрование — это замок с одним ключом. Один и тот же ключ запирает (шифрует) и отпирает (расшифровывает) данные.

AES (Advanced Encryption Standard) — это самый распространенный симметричный шифр в мире. Принят как стандарт в 2001 году после конкурса, организованного NIST (Национальный институт стандартов и технологий США).

Как работает AES на высоком уровне:

  1. Берет блок данных фиксированного размера (128 бит = 16 байт)
  2. Применяет серию перемешиваний (раундов) с использованием ключа
  3. Выдает блок зашифрованных данных того же размера

Количество раундов зависит от длины ключа:

AES: структура блочного шифра
Открытый текст
128 бит
+
Ключ
256 бит
Раунд 1
SubBytes
ShiftRows
MixColumns
AddRoundKey
...
Раунд 2
SubBytes
ShiftRows
MixColumns
AddRoundKey
...
Раунд 3
SubBytes
ShiftRows
MixColumns
AddRoundKey
...
Раунд 4
SubBytes
ShiftRows
MixColumns
AddRoundKey
...
Раунд 5
SubBytes
ShiftRows
MixColumns
AddRoundKey
...
Раунд 14
SubBytes
ShiftRows
MixColumns
AddRoundKey
Шифротекст
128 бит
AES-256: ключ 256 бит, блок 128 бит, 14 раундов. Рекомендуется для криптографических приложений.

Каждый раунд — это набор из четырех операций, которые перемешивают данные так тщательно, что восстановить исходные данные без ключа невозможно.

Алгоритмический уровень: четыре операции раунда

AES обрабатывает данные как матрицу 4x4 байтов (так называемое состояние — state). Каждый раунд применяет четыре операции:

Раунд AES: четыре операции
Исходное состояние
63
53
e0
8c
09
60
e1
04
cd
70
b7
51
ba
ca
d0
e7
4x4 матрица байтов (128 бит)
1. SubBytes
fb
ed
e1
64
01
d0
f8
f2
bd
51
a9
d1
f4
74
70
94
Каждый байт заменяется через S-box (нелинейная подстановка)
2. ShiftRows
fb
ed
e1
64
d0
f8
f2
01
a9
d1
bd
51
94
f4
74
70
Строки сдвигаются влево на 0, 1, 2, 3 позиции
3. MixColumns
3e
1c
22
7b
08
96
c4
3c
52
79
5a
b1
e5
b2
56
1a
Столбцы перемешиваются полиномиальным умножением в GF(2^8)
4. AddRoundKey
a0
88
23
2a
fa
54
a3
6c
fe
2c
39
76
17
b1
39
05
XOR с раундовым ключом
SubBytes обеспечивает нелинейность (confusion). ShiftRows + MixColumns обеспечивают диффузию (diffusion). AddRoundKey вносит зависимость от ключа. Последний раунд пропускает MixColumns.

SubBytes — подстановка

Каждый байт заменяется другим байтом через таблицу подстановки (S-box). Это нелинейное преобразование — именно оно делает AES устойчивым к линейному криптоанализу.

S-box — это таблица 16x16, где каждому входному байту (0x00-0xFF) соответствует один выходной байт. Математически S-box построен на обратных элементах в поле GF(2^8) — это связь с конечными полями из предыдущих уроков.

ShiftRows — сдвиг строк

Строки матрицы состояния сдвигаются влево:

  • Строка 0: без сдвига
  • Строка 1: сдвиг на 1 позицию
  • Строка 2: сдвиг на 2 позиции
  • Строка 3: сдвиг на 3 позиции

Это обеспечивает диффузию между столбцами.

MixColumns — перемешивание столбцов

Каждый столбец умножается на фиксированную матрицу в поле GF(2^8). Эта операция обеспечивает максимальную диффузию — изменение одного байта влияет на все четыре байта столбца.

Последний раунд пропускает MixColumns. Это не ошибка — без MixColumns в последнем раунде шифрование и расшифровка имеют одинаковую структуру (важно для реализации).

AddRoundKey — наложение ключа

Состояние XOR-ится с раундовым ключом. Раундовые ключи генерируются из основного ключа через процедуру Key Expansion.

Размеры ключей AES

Размеры ключей AES
AES-128
Размер ключа128 бит
Размер блока128 бит
Раундов10
Стойкость2^128 операций
Быстрое шифрование, где скорость критична
AES-192
Размер ключа192 бит
Размер блока128 бит
Раундов12
Стойкость2^192 операций
Редко используется на практике
Рекомендуется
AES-256
Размер ключа256 бит
Размер блока128 бит
Раундов14
Стойкость2^256 операций
Криптовалютные кошельки, секретные данные
Ethereum keystore файлы используют AES-128-CTR. Bitcoin wallet.dat использует AES-256-CBC.
  • AES-128: 10 раундов, достаточен для большинства задач
  • AES-192: 12 раундов, редко используется
  • AES-256: 14 раундов, рекомендуется для криптовалютных приложений

Bitcoin использует AES-256-CBC для шифрования wallet.dat. Ethereum keystore файлы используют AES-128-CTR — этого достаточно, потому что ключ шифрования выводится через scrypt с высоким параметром сложности.

Почему AES безопасен

AES безопасен благодаря двум принципам Клода Шеннона:

  1. Confusion (запутывание): SubBytes делает связь между ключом и шифротекстом максимально сложной. Даже зная часть ключа, нельзя предсказать, как изменится шифротекст.

  2. Diffusion (диффузия): ShiftRows и MixColumns обеспечивают, что изменение одного бита открытого текста меняет в среднем половину битов шифротекста (эффект лавины).

За 25+ лет не найдено практических атак на AES. Лучшие теоретические атаки (biclique) снижают сложность полного перебора с 2^256 до 2^254.4 для AES-256 — это все еще астрономически много.

Код на Python

Мы не реализуем AES вручную — это сложно и опасно (ошибки в реализации создают уязвимости). Вместо этого используем pycryptodome:

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

# AES-256 базовое шифрование блока (ECB — только для обучения!)
key = get_random_bytes(32)  # 256-бит ключ
cipher = AES.new(key, AES.MODE_ECB)

# Открытый текст должен быть ровно 16 байт для ECB
plaintext = b"Exactly16Bytes!!"
ciphertext = cipher.encrypt(plaintext)
print(f"Шифротекст: {ciphertext.hex()}")

# Расшифровка
decipher = AES.new(key, AES.MODE_ECB)
decrypted = decipher.decrypt(ciphertext)
print(f"Расшифровано: {decrypted}")
assert decrypted == plaintext

# ВАЖНО: ECB небезопасен для реальных данных!
# Используйте CBC, CTR или GCM — см. следующий урок

Почему мы не пишем AES с нуля? Реализация AES на чистом Python была бы в 1000 раз медленнее C-реализации pycryptodome и содержала бы ошибки. AES — это алгоритм, который нужно понимать (через диаграммы), но использовать через проверенные библиотеки.

Математический уровень

Для тех, кто хочет глубже:

SubBytes использует мультипликативную инверсию в поле GF(2^8), определенном неприводимым полиномом x^8 + x^4 + x^3 + x + 1. Каждый байт интерпретируется как элемент этого поля, инвертируется (0 отображается в 0), затем проходит через аффинное преобразование.

Это прямая связь с конечными полями (GF(p)) из предыдущих уроков — но здесь поле расширяется до GF(2^8) с полиномиальной арифметикой.

MixColumns — это умножение вектора-столбца на фиксированную матрицу в GF(2^8):

[2 3 1 1]   [s0]
[1 2 3 1] * [s1]
[1 1 2 3]   [s2]
[3 1 1 2]   [s3]

Умножение и сложение выполняются в GF(2^8), где сложение — это XOR, а умножение — полиномиальное по модулю неприводимого полинома.

Практика

Откройте Jupyter notebook 04-symmetric-encryption.ipynb для практических упражнений:

  • Шифрование и расшифровка с AES в режиме ECB
  • Демонстрация проблемы одинаковых блоков в ECB
  • Переход к безопасным режимам (CBC, CTR, GCM) — следующий урок

Что дальше

AES шифрует один блок (16 байт). Но реальные данные длиннее 16 байт. Как шифровать произвольные объемы данных? Нужны режимы работы блочных шифров — ECB, CBC, CTR, GCM. Об этом в следующем уроке.

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс