Роль вектора инициализации

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

IV представляет собой случайный или псевдослучайный набор байт фиксированной длины, который применяется на этапе первого блока шифрования. Он не является секретным, но должен быть уникальным для каждой операции шифрования с одним и тем же ключом.

Назначение IV в режимах шифрования

Вектор инициализации особенно важен в режимах блочного шифрования, где данные разбиваются на блоки фиксированного размера.

CBC (Cipher Block Chaining)

В режиме CBC каждый блок открытого текста перед шифрованием XOR-ится с предыдущим зашифрованным блоком. Для первого блока используется IV.

C_1 = E_K(P_1 IV)

Последующие блоки зависят от предыдущих:

C_i = E_K(P_i C_{i-1})

Таким образом, даже одинаковые входные данные при разных IV дают разные результаты шифрования.

CTR (Counter Mode)

В режиме CTR IV используется как начальное значение счётчика, который изменяется для каждого блока. Здесь IV фактически формирует поток ключа.

S_i = E_K(IV + i)

C_i = P_i S_i

Требования к вектору инициализации

К IV предъявляются строгие требования:

  • Уникальность: IV не должен повторяться при одном и том же ключе
  • Непредсказуемость: желательно использовать криптографически стойкую случайность
  • Фиксированная длина: зависит от алгоритма (например, для AES обычно 16 байт)
  • Публичность допустима: IV не обязан быть секретным, он может передаваться вместе с шифротекстом

Повтор IV с одним и тем же ключом приводит к утечке информации о структуре данных и может позволить атаки на шифротекст.

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

В библиотеке CryptoJS вектор инициализации задаётся через параметр iv при вызове методов шифрования.

Генерация IV

Обычно IV создаётся случайным образом:

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

16 байт соответствует размеру блока AES.

Шифрование с IV

const key = CryptoJS.enc.Utf8.parse("my-secret-key-123");
const message = "Confidential data";

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

Расшифрование с IV

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

const originalText = decrypted.toString(CryptoJS.enc.Utf8);

IV должен быть известен при расшифровании, поэтому обычно он сохраняется вместе с зашифрованными данными.

Способы хранения IV

На практике IV часто добавляется в начало или конец зашифрованного сообщения:

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

При расшифровке данные разделяются обратно:

const raw = CryptoJS.enc.Base64.parse(result);
const iv = CryptoJS.lib.WordArray.create(raw.words.slice(0, 4));
const ciphertext = CryptoJS.lib.WordArray.create(raw.words.slice(4));

Ошибки при работе с IV

Неправильное использование IV приводит к критическим уязвимостям:

  • повторное использование IV с тем же ключом
  • использование фиксированного IV (например, из нулей)
  • отсутствие IV в режимах, где он обязателен
  • неправильное разделение IV и ciphertext

Особенно опасно повторение IV в CBC: при одинаковом ключе и IV одинаковые первые блоки открытого текста дают одинаковые блоки шифротекста, что позволяет анализировать структуру данных.

IV и режим ECB

Режим ECB (Electronic Codebook) не использует IV вообще. Это делает его небезопасным для большинства задач, поскольку одинаковые блоки данных шифруются одинаково, независимо от контекста.

CryptoJS позволяет явно выбрать режим:

mode: CryptoJS.mode.ECB

Но в криптографической практике его использование считается нежелательным именно из-за отсутствия IV.

Различие IV и соли

IV часто путают с солью (salt), но их назначение различается:

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

В CryptoJS соль используется так:

CryptoJS.PBKDF2(password, salt, {
    keySize: 256 / 32,
    iterations: 1000
});

IV при этом применяется уже на уровне шифрования результата.

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

Корректная схема работы обычно включает:

  1. Генерацию случайного IV
  2. Шифрование данных с использованием IV и ключа
  3. Объединение IV и ciphertext
  4. Передачу или хранение результата
  5. Извлечение IV перед расшифровкой
  6. Расшифровку с тем же ключом и IV