AES-128, AES-192, AES-256: ключи и стойкость

AES (Advanced Encryption Standard) представляет собой симметричный алгоритм блочного шифрования, основанный на сети подстановок и перестановок. В библиотеке CryptoJS он реализуется в соответствии со стандартом FIPS-197 и используется как основной механизм защиты данных на стороне JavaScript.

AES работает с блоками данных размером 128 бит и поддерживает три варианта длины ключа: 128, 192 и 256 бит. Различие между ними заключается не только в длине ключа, но и в количестве раундов преобразований:

  • AES-128 — 10 раундов
  • AES-192 — 12 раундов
  • AES-256 — 14 раундов

Каждый раунд включает последовательность операций: SubBytes, ShiftRows, MixColumns и AddRoundKey. Увеличение числа раундов напрямую влияет на устойчивость к криптоанализу, но также увеличивает вычислительную стоимость.


Длина ключа и её значение

Ключ в AES определяет исходное состояние шифрования и сложность его подбора. В CryptoJS ключи передаются в виде строки или WordArray, однако важно понимать внутреннюю природу их безопасности.

AES-128

Ключ длиной 128 бит обеспечивает 2¹²⁸ возможных комбинаций. Это значение считается устойчивым к brute-force атакам при текущем уровне вычислительных возможностей.

Характерные особенности:

  • Быстрая обработка
  • Меньшая нагрузка на CPU
  • Достаточная безопасность для большинства прикладных задач

AES-192

Ключ 192 бит увеличивает пространство поиска до 2¹⁹².

Особенности:

  • Умеренно увеличенная стойкость
  • Более медленная генерация ключевого расписания
  • Реже используется в веб-приложениях

AES-256

Ключ 256 бит обеспечивает 2²⁵⁶ комбинаций, что считается максимально устойчивым в рамках AES.

Особенности:

  • Наибольшая криптостойкость
  • Более высокая вычислительная нагрузка
  • Используется в высокозащищённых системах, включая государственные и банковские решения

Внутреннее расширение ключа (Key Schedule)

AES не использует ключ напрямую для каждого раунда. Вместо этого он расширяется в набор раундовых ключей.

В CryptoJS этот процесс скрыт, но логически включает:

  • преобразование исходного ключа
  • генерацию промежуточных ключей
  • применение S-box и Rcon констант

Для AES-256 процесс расширения сложнее, так как исходный ключ длиннее и требует большего числа итераций генерации.


Реализация AES в CryptoJS

Библиотека CryptoJS предоставляет высокоуровневый интерфейс:

const CryptoJS = require("crypto-js");

const ciphertext = CryptoJS.AES.encrypt(
  "секретные данные",
  "ключ"
).toString();

const bytes = CryptoJS.AES.decrypt(ciphertext, "ключ");
const originalText = bytes.toString(CryptoJS.enc.Utf8);

Однако такой подход использует строковый ключ, который автоматически проходит через PBKDF1/PBKDF2-подобное преобразование внутри библиотеки (в зависимости от версии и режима).


Ключи как WordArray

Для более строгого контроля используется WordArray:

const key = CryptoJS.enc.Utf8.parse("0123456789abcdef"); // 16 байт = AES-128

const encrypted = CryptoJS.AES.encrypt("данные", key, {
  mode: CryptoJS.mode.CBC,
  padding: CryptoJS.pad.Pkcs7
});

Размер ключа напрямую определяет используемый стандарт AES:

  • 16 байт → AES-128
  • 24 байта → AES-192
  • 32 байта → AES-256

CryptoJS автоматически определяет вариант алгоритма по длине ключа.


Влияние режима работы (Mode of Operation)

AES сам по себе работает только с 128-битными блоками, но режим определяет, как эти блоки связываются между собой.

Наиболее используемые режимы в CryptoJS:

  • CBC (Cipher Block Chaining)
  • CFB (Cipher Feedback)
  • OFB (Output Feedback)
  • ECB (Electronic Codebook) — не рекомендуется

Пример CBC:

const encrypted = CryptoJS.AES.encrypt("данные", key, {
  mode: CryptoJS.mode.CBC,
  iv: CryptoJS.enc.Utf8.parse("1234567890123456")
});

IV (инициализационный вектор) не влияет на стойкость ключа, но критически важен для уникальности шифротекста.


Генерация ключей и производные (PBKDF2)

Использование прямых строковых ключей снижает стойкость. В практических системах применяется KDF (Key Derivation Function).

CryptoJS поддерживает PBKDF2:

const key = CryptoJS.PBKDF2("пароль", "соль", {
  keySize: 256 / 32,
  iterations: 1000
});
  • соль предотвращает радужные таблицы
  • итерации усложняют подбор пароля
  • keySize определяет AES-128/192/256

Криптостойкость и реальные угрозы

Несмотря на различие в теоретической стойкости, в реальных условиях безопасность AES чаще определяется не длиной ключа, а:

  • качеством генерации ключа
  • использованием IV
  • режимом шифрования
  • защитой ключа в приложении

AES-128 не считается слабым. Основные криптоаналитические атаки на AES не являются практическими при корректной реализации.

AES-256 не гарантирует «двойную безопасность» в прикладном смысле, но увеличивает запас устойчивости против теоретических атак, включая квантовые модели (Grover’s algorithm снижает эффективную стойкость до 2¹²⁸ для AES-256).


Ошибки при работе с ключами в CryptoJS

Частые проблемы:

  • использование строк вместо бинарных ключей без KDF
  • фиксированный IV
  • повторное использование IV при CBC
  • хранение ключей в коде фронтенда
  • несоответствие длины ключа режиму использования

Пример опасной практики:

CryptoJS.AES.encrypt("data", "password");

Без PBKDF2 такой подход делает систему уязвимой к словарным атакам.


Сравнение AES-128, AES-192 и AES-256 в прикладной перспективе

  • AES-128: оптимальный баланс скорости и безопасности
  • AES-192: промежуточный вариант без широкого распространения
  • AES-256: максимальный уровень стойкости при увеличенной нагрузке

В веб-контексте различия в производительности часто минимальны, но в массовых операциях (стриминг, большие массивы данных) AES-128 заметно быстрее.


Внутренние ограничения JavaScript-реализации

CryptoJS не использует аппаратное ускорение AES-NI, как это делают нативные реализации в современных браузерах и Node.js crypto module. Это приводит к:

  • более медленной обработке AES-256
  • отсутствию оптимизаций уровня ОС
  • повышенной нагрузке при больших объёмах данных

Ключевые свойства безопасности AES в CryptoJS

  • симметричность алгоритма (один ключ для шифрования и расшифрования)
  • фиксированный размер блока (128 бит)
  • зависимость стойкости от ключа и режима
  • отсутствие встроенного управления ключами
  • необходимость внешнего KDF для безопасной генерации