Генерация случайного IV

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

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

Ключевые свойства IV:

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

Нарушение этих правил приводит к утечке информации о структуре исходных данных даже при наличии шифрования.

Генерация случайного IV в Crypto-js

Библиотека Crypto-js предоставляет встроенный механизм генерации криптографически стойких случайных значений через CryptoJS.lib.WordArray.random.

IV для AES обычно формируется следующим образом:

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

Число 16 обозначает размер в байтах. Для AES это стандартный размер блока (128 бит).

Внутренне Crypto-js использует криптографически безопасный генератор псевдослучайных чисел, который опирается на возможности окружения (браузер или Node.js).

Использование IV в режиме CBC

Режим CBC (Cipher Block Chaining) требует передачи IV при инициализации шифрования:

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

const encrypted = CryptoJS.AES.encrypt('секретные данные', key, {
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});

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

Передача IV вместе с шифротекстом

IV не считается секретной частью, поэтому обычно он передаётся вместе с зашифрованными данными. Частая практика — конкатенация IV и ciphertext.

Пример упаковки:

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

const encrypted = CryptoJS.AES.encrypt('данные', key, { iv });

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

При расшифровке сначала извлекается IV:

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));

const decrypted = CryptoJS.AES.decrypt(
    { ciphertext: ciphertext },
    key,
    { iv: iv }
);

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

Каждое слово WordArray содержит 4 байта, поэтому 16 байт IV соответствуют 4 словам.

Ошибки при генерации IV

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

  • одинаковые сообщения дают одинаковый шифротекст
  • возможен анализ повторяющихся блоков
  • снижается стойкость CBC до уровня, близкого к ECB

Пример неправильного подхода:

const iv = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');

Такой IV делает шифрование детерминированным и уязвимым.

Форматы представления IV

В Crypto-js IV хранится в формате WordArray, но на практике часто требуется преобразование:

Hex:

const ivHex = iv.toString(CryptoJS.enc.Hex);

Base64:

const ivBase64 = iv.toString(CryptoJS.enc.Base64);

Выбор формата зависит от способа передачи данных (JSON, бинарный протокол, база данных).

Размер IV для различных алгоритмов

Хотя чаще всего используется AES, библиотека поддерживает и другие алгоритмы с различными требованиями:

  • AES: 16 байт
  • TripleDES: 8 байт
  • RC4: IV не используется

Неправильный размер IV приводит к ошибкам или некорректной работе алгоритма.

Криптографическая стойкость генерации

CryptoJS.lib.WordArray.random не использует обычный Math.random(). Вместо этого применяется более надёжный источник энтропии:

  • браузер: window.crypto.getRandomValues
  • Node.js: crypto.randomBytes

Если среда не поддерживает криптографический генератор, библиотека использует fallback, который снижает безопасность и не должен применяться в реальных системах.

Пример полного цикла работы с IV

const key = CryptoJS.enc.Utf8.parse('0123456789abcdef');
const iv = CryptoJS.lib.WordArray.random(16);

const message = 'пример текста';

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

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

const decoded = CryptoJS.enc.Base64.parse(payload);

const ivRecovered = CryptoJS.lib.WordArray.create(decoded.words.slice(0, 4));
const ciphertextRecovered = CryptoJS.lib.WordArray.create(decoded.words.slice(4));

const decrypted = CryptoJS.AES.decrypt(
    { ciphertext: ciphertextRecovered },
    key,
    { iv: ivRecovered }
);

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

Особенности работы WordArray при формировании IV

WordArray хранит данные в виде массива 32-битных слов. Это влияет на:

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

Каждое слово содержит 4 байта, поэтому любые операции с IV требуют учёта выравнивания.

Практические рекомендации

Использование IV в Crypto-js требует соблюдения строгих правил:

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

Игнорирование этих правил приводит к тому, что даже сильный алгоритм перестаёт обеспечивать конфиденциальность данных.