Повторное использование IV

Повторное использование вектора инициализации (IV) в симметричном шифровании разрушает ключевое свойство современных режимов — семантическую стойкость. Даже при корректно выбранном алгоритме (например, AES) ошибка в управлении IV приводит к утечке информации о структуре исходных данных и потенциальной возможности восстановления текста.

В блочных шифрах один и тот же открытый текст при одинаковом ключе должен давать разные шифротексты. Эту задачу решает IV (Initialization Vector).

C = E_K(P IV)

В зависимости от режима работы алгоритма IV может:

  • добавляться к первому блоку перед шифрованием,
  • участвовать в цепочке блоков,
  • влиять на поток генерации ключевого потока.

Ключевая характеристика IV — уникальность при одном ключе, а не секретность.

Поведение CryptoJS при использовании AES

В CryptoJS часто применяется AES в режиме CBC по умолчанию при явной передаче IV.

Пример корректного использования:

import CryptoJS from "crypto-js";

const key = CryptoJS.enc.Utf8.parse("1234567890123456");
const iv = CryptoJS.lib.WordArray.random(16);

const encrypted = CryptoJS.AES.encrypt("secret data", key, {
  iv: iv,
  mode: CryptoJS.mode.CBC,
  padding: CryptoJS.pad.Pkcs7
});

const result = iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64);

IV генерируется случайно для каждого сообщения и передаётся вместе с шифротекстом.

Повторное использование IV и его последствия

Использование одного и того же IV с одинаковым ключом приводит к следующим эффектам:

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

Особенно критично это в режимах:

  • CBC (Cipher Block Chaining)
  • CFB (Cipher Feedback)
  • OFB (Output Feedback)

В этих режимах IV фактически задаёт начальное состояние цепочки.

Ошибочный паттерн: фиксированный IV

На практике часто встречается следующий антишаблон:

const key = CryptoJS.enc.Utf8.parse("1234567890123456");
const iv = CryptoJS.enc.Utf8.parse("0000000000000000");

function encrypt(message) {
  return CryptoJS.AES.encrypt(message, key, {
    iv: iv
  }).toString();
}

Проблема заключается в том, что каждый вызов функции использует одинаковое начальное состояние.

Если два сообщения начинаются одинаково, их шифротексты также будут иметь одинаковые префиксы, что создаёт утечку информации.

Корректная модель генерации IV

IV должен быть:

  • случайным
  • непредсказуемым
  • уникальным для каждого шифрования при одном ключе

Рекомендуемый подход:

function encrypt(message, key) {
  const iv = CryptoJS.lib.WordArray.random(16);

  const encrypted = CryptoJS.AES.encrypt(message, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });

  return {
    iv: iv.toString(CryptoJS.enc.Base64),
    data: encrypted.toString()
  };
}

Здесь каждый вызов создаёт новое начальное состояние цепочки шифрования.

Декодирование при корректной передаче IV

При расшифровке IV должен быть восстановлен:

function decrypt(payload, key) {
  const iv = CryptoJS.enc.Base64.parse(payload.iv);
  const encrypted = payload.data;

  const decrypted = CryptoJS.AES.decrypt(encrypted, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });

  return decrypted.toString(CryptoJS.enc.Utf8);
}

Отсутствие IV или его подмена делает расшифровку невозможной или приводит к некорректному результату.

Свойства уязвимости при повторном IV

Повтор IV не раскрывает ключ напрямую, но создаёт структурные утечки:

  • одинаковые сообщения → одинаковые шифротексты
  • различия между сообщениями становятся анализируемыми
  • возможны атаки на шаблоны данных (например, JSON, токены, заголовки)

Для CBC это особенно критично, так как первый блок зависит только от IV и первого блока данных.

Особенности потоковых режимов

В режимах OFB и CFB повтор IV приводит к генерации одинакового ключевого потока:

C_i = P_i KS_i

Если KS (key stream) повторяется, то:

C_i C’_i = P_i P’_i

что позволяет восстановить взаимосвязи между открытыми текстами без знания ключа.

Практические ошибки при работе с CryptoJS

Наиболее частые ошибки:

  • использование фиксированного IV ради «простоты»
  • хранение IV отдельно без привязки к шифротексту
  • повторное использование IV при пакетном шифровании данных
  • генерация IV один раз при инициализации модуля

Особенно опасна ситуация, когда IV генерируется глобально:

const iv = CryptoJS.lib.WordArray.random(16);

function encrypt(msg) {
  return CryptoJS.AES.encrypt(msg, key, { iv }).toString();
}

В таком случае вся сессия шифрования становится уязвимой.

Связь IV с криптостойкостью системы

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

IV не является дополнительным уровнем защиты, но его неправильное использование полностью нарушает свойства:

  • случайности шифротекста
  • устойчивости к анализу повторов
  • семантической безопасности

Корректная работа с IV — обязательное условие безопасного применения AES в прикладных JavaScript-сценариях.