В криптографических алгоритмах на базе симметричного шифрования основная безопасность держится на трёх элементах: ключе (key), векторе инициализации (IV) и соли (salt). Библиотека CryptoJS в JavaScript предоставляет как автоматические механизмы генерации этих параметров, так и возможность полного ручного контроля над ними.
Ручная передача ключа, IV и соли используется в случаях, когда требуется строгая совместимость с другими языками, протоколами или существующей криптосистемой. В таких сценариях недопустимо полагаться на внутренние генераторы CryptoJS, поскольку даже незначительное отличие в байтовом представлении приводит к невозможности расшифровки данных.
CryptoJS не работает с «сырыми» строками напрямую. Любой
криптографический материал приводится к внутреннему формату
WordArray.
Ключ и IV должны быть представлены именно в этом формате:
const key = CryptoJS.enc.Utf8.parse("1234567890123456");
const iv = CryptoJS.enc.Utf8.parse("abcdefghijklmnop");
Важно учитывать:
При явной передаче ключа и IV отключается использование встроенного механизма генерации параметров.
const message = "Секретное сообщение";
const key = CryptoJS.enc.Utf8.parse("1234567890123456");
const iv = CryptoJS.enc.Utf8.parse("abcdefghijklmnop");
const encrypted = CryptoJS.AES.encrypt(message, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
const ciphertext = encrypted.toString();
Особенность такого подхода заключается в полной детерминированности результата при одинаковых входных данных.
IV используется не во всех режимах, но в CBC и CFB он критически важен. Его задача — обеспечить уникальность первого блока шифротекста.
y = f(x) = AES_{CBC}(x, key, IV)
CBC (Cipher Block Chaining) связывает каждый блок шифрования с предыдущим. Из-за этого повторение IV с тем же ключом приводит к утечке структуры данных.
Для восстановления исходного сообщения необходимо использовать идентичные key и IV:
const decrypted = CryptoJS.AES.decrypt(ciphertext, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
const originalText = decrypted.toString(CryptoJS.enc.Utf8);
Любое несоответствие хотя бы одного байта делает результат нечитаемым.
Соль используется не напрямую в AES, а при генерации ключа из пароля. Это критический элемент при использовании PBKDF2.
const salt = CryptoJS.enc.Hex.parse("a1b2c3d4e5f6g7h8");
const key = CryptoJS.PBKDF2("password123", salt, {
keySize: 256 / 32,
iterations: 1000
});
Соль выполняет следующие функции:
Часто применяется комбинированная схема:
Пример полного цикла:
const password = "secret_password";
const salt = CryptoJS.lib.WordArray.random(128/8);
const key = CryptoJS.PBKDF2(password, salt, {
keySize: 256 / 32,
iterations: 2000
});
const iv = CryptoJS.lib.WordArray.random(128/8);
const encrypted = CryptoJS.AES.encrypt("данные", key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
Здесь важно сохранять salt и IV вместе с шифротекстом, иначе расшифровка будет невозможна.
На практике зашифрованные данные часто хранятся в структуре:
{
"ciphertext": "...",
"iv": "...",
"salt": "..."
}
Все значения обычно кодируются в Base64 или Hex:
const payload = {
ciphertext: encrypted.toString(),
iv: iv.toString(CryptoJS.enc.Base64),
salt: salt.toString(CryptoJS.enc.Base64)
};
Несоответствие кодировок
Использование строк вместо WordArray
Повторное использование IV
Неправильная длина ключа
При интеграции с backend на Java, Python или Go часто требуется:
Например, в OpenSSL-совместимых схемах CryptoJS должен повторять логику EVP_BytesToKey или PBKDF2 с одинаковыми параметрами.
Ручное управление key, IV и salt фактически выводит разработчика на уровень низкоуровневого криптографического проектирования. Это означает:
Такая модель используется там, где важна предсказуемость и совместимость, а не удобство.