В библиотеке CryptoJS криптографическая стойкость симметричного шифрования во многом определяется качеством ключевого материала. Для генерации случайных значений используется встроенный генератор:
const key = CryptoJS.lib.WordArray.random(32);
Здесь 32 означает количество байт. Для AES-256 требуется
ключ длиной 256 бит, то есть 32 байта. Для AES-128 — 16 байт, для
AES-192 — 24 байта.
Полученный объект имеет тип WordArray, который является
внутренним представлением бинарных данных в CryptoJS. Он не является
строкой и не предназначен для прямого отображения без кодирования.
Для преобразования в удобный формат используется кодировка:
const keyHex = key.toString(CryptoJS.enc.Hex);
const keyBase64 = key.toString(CryptoJS.enc.Base64);
Выбор формата зависит от способа хранения или передачи. Hex увеличивает размер данных в два раза, Base64 более компактный.
Вектор инициализации (IV) используется в режимах блочного шифрования, таких как CBC или CFB. Его основная задача — обеспечить уникальность шифрования одинаковых данных при одинаковом ключе.
IV в CryptoJS создаётся аналогично ключу:
const iv = CryptoJS.lib.WordArray.random(16);
Для AES размер IV всегда равен размеру блока — 16 байт (128 бит), независимо от длины ключа.
IV не требует секретности, но требует уникальности. Повторное использование IV с одним и тем же ключом приводит к криптографическим уязвимостям, включая утечку информации о структуре данных.
Типовой процесс шифрования с автоматической генерацией ключа и IV:
const message = "Секретное сообщение";
const key = CryptoJS.lib.WordArray.random(32);
const iv = CryptoJS.lib.WordArray.random(16);
const encrypted = CryptoJS.AES.encrypt(message, key, {
iv: iv
});
Результат encrypted содержит зашифрованные данные в
формате CipherParams. Для получения строки используется
кодирование:
const ciphertextBase64 = encrypted.toString();
По умолчанию используется Base64.
Поскольку IV не является секретным, его часто сохраняют вместе с шифротекстом. Один из распространённых подходов — конкатенация:
const encryptedBase64 = encrypted.toString();
const ivBase64 = iv.toString(CryptoJS.enc.Base64);
const payload = ivBase64 + ":" + encryptedBase64;
При расшифровке выполняется обратное разделение:
const parts = payload.split(":");
const iv = CryptoJS.enc.Base64.parse(parts[0]);
const ciphertext = parts[1];
const decrypted = CryptoJS.AES.decrypt(ciphertext, key, {
iv: iv
});
const originalText = decrypted.toString(CryptoJS.enc.Utf8);
Автоматически сгенерированный ключ должен сохраняться отдельно от зашифрованных данных. Потеря ключа делает восстановление невозможным.
Часто используется один из подходов:
Пример вывода ключа в строку:
const storedKey = key.toString(CryptoJS.enc.Base64);
При восстановлении:
const key = CryptoJS.enc.Base64.parse(storedKey);
Вместо прямой генерации ключа часто применяется производная функция:
const password = "user-password";
const salt = CryptoJS.lib.WordArray.random(16);
const key = CryptoJS.PBKDF2(password, salt, {
keySize: 256 / 32,
iterations: 1000
});
Здесь ключ формируется детерминированно, но устойчиво к перебору благодаря соли и итерациям.
IV при этом всё равно остаётся случайным:
const iv = CryptoJS.lib.WordArray.random(16);
Использование одного IV для нескольких сообщений при одном ключе:
const iv = CryptoJS.lib.WordArray.random(16);
const enc1 = CryptoJS.AES.encrypt("A", key, { iv });
const enc2 = CryptoJS.AES.encrypt("B", key, { iv });
Такой подход снижает стойкость шифрования и позволяет анализировать структуру данных.
const key = CryptoJS.lib.WordArray.random(8);
Ключ длиной 64 бита недостаточен для современных алгоритмов и легко поддаётся атаке перебором.
IV не требует защиты, его скрытие не добавляет безопасности и усложняет архитектуру.
CryptoJS использует WordArray, который требует явного
преобразования:
const key = CryptoJS.lib.WordArray.random(32);
const hex = key.toString(CryptoJS.enc.Hex);
const base64 = key.toString(CryptoJS.enc.Base64);
const restoredKey = CryptoJS.enc.Base64.parse(base64);
Ошибки в кодировании часто приводят к невозможности расшифровки данных, даже при корректном ключе.
const message = "Конфиденциальные данные";
// генерация
const key = CryptoJS.lib.WordArray.random(32);
const iv = CryptoJS.lib.WordArray.random(16);
// шифрование
const encrypted = CryptoJS.AES.encrypt(message, key, {
iv: iv
});
// упаковка
const payload = {
iv: iv.toString(CryptoJS.enc.Base64),
data: encrypted.toString(),
key: key.toString(CryptoJS.enc.Base64)
};
Расшифровка:
const key = CryptoJS.enc.Base64.parse(payload.key);
const iv = CryptoJS.enc.Base64.parse(payload.iv);
const decrypted = CryptoJS.AES.decrypt(payload.data, key, {
iv: iv
});
const text = decrypted.toString(CryptoJS.enc.Utf8);