IV (Initialization Vector) в симметричных алгоритмах шифрования используется для того, чтобы одинаковые входные данные при повторном шифровании не давали одинаковый результат. В режимах работы блочных шифров, таких как CBC, без IV структура шифротекста становилась бы предсказуемой, что разрушает смысл криптографической защиты.
В алгоритмах, где данные обрабатываются блоками фиксированного размера, каждый блок шифруется на основе предыдущего. В первом блоке такой зависимости нет, поэтому вводится начальное значение — IV.
Ключевые свойства IV:
Нарушение этих правил приводит к утечке информации о структуре исходных данных даже при наличии шифрования.
Библиотека Crypto-js предоставляет встроенный механизм генерации
криптографически стойких случайных значений через
CryptoJS.lib.WordArray.random.
IV для AES обычно формируется следующим образом:
const iv = CryptoJS.lib.WordArray.random(16);
Число 16 обозначает размер в байтах. Для AES это
стандартный размер блока (128 бит).
Внутренне Crypto-js использует криптографически безопасный генератор псевдослучайных чисел, который опирается на возможности окружения (браузер или Node.js).
Режим 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 и 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 с одинаковым ключом. Это приводит к тому, что:
Пример неправильного подхода:
const iv = CryptoJS.enc.Hex.parse('00000000000000000000000000000000');
Такой IV делает шифрование детерминированным и уязвимым.
В Crypto-js IV хранится в формате WordArray, но на
практике часто требуется преобразование:
Hex:
const ivHex = iv.toString(CryptoJS.enc.Hex);
Base64:
const ivBase64 = iv.toString(CryptoJS.enc.Base64);
Выбор формата зависит от способа передачи данных (JSON, бинарный протокол, база данных).
Хотя чаще всего используется AES, библиотека поддерживает и другие алгоритмы с различными требованиями:
Неправильный размер IV приводит к ошибкам или некорректной работе алгоритма.
CryptoJS.lib.WordArray.random не использует обычный
Math.random(). Вместо этого применяется более надёжный
источник энтропии:
window.crypto.getRandomValuescrypto.randomBytesЕсли среда не поддерживает криптографический генератор, библиотека использует fallback, который снижает безопасность и не должен применяться в реальных системах.
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 хранит данные в виде массива 32-битных слов.
Это влияет на:
Каждое слово содержит 4 байта, поэтому любые операции с IV требуют учёта выравнивания.
Использование IV в Crypto-js требует соблюдения строгих правил:
Игнорирование этих правил приводит к тому, что даже сильный алгоритм перестаёт обеспечивать конфиденциальность данных.