Ручная передача ключа, IV и соли

В криптографических алгоритмах на базе симметричного шифрования основная безопасность держится на трёх элементах: ключе (key), векторе инициализации (IV) и соли (salt). Библиотека CryptoJS в JavaScript предоставляет как автоматические механизмы генерации этих параметров, так и возможность полного ручного контроля над ними.

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


Представление ключа и IV в CryptoJS

CryptoJS не работает с «сырыми» строками напрямую. Любой криптографический материал приводится к внутреннему формату WordArray.

Ключ и IV должны быть представлены именно в этом формате:

const key = CryptoJS.enc.Utf8.parse("1234567890123456");
const iv = CryptoJS.enc.Utf8.parse("abcdefghijklmnop");

Важно учитывать:

  • длина ключа должна соответствовать алгоритму (AES-128, AES-192, AES-256)
  • IV для AES всегда 16 байт
  • строка не должна содержать неожиданных символов кодировки

Использование AES с ручным ключом и IV

При явной передаче ключа и 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

IV используется не во всех режимах, но в CBC и CFB он критически важен. Его задача — обеспечить уникальность первого блока шифротекста.

CBC режим

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

Соль выполняет следующие функции:

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

Связка password + salt + IV

Часто применяется комбинированная схема:

  1. пароль → PBKDF2 → ключ
  2. соль → защита PBKDF2
  3. IV → защита режима CBC/CFB

Пример полного цикла:

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

Частые ошибки при ручной передаче параметров

  1. Несоответствие кодировок

    • Utf8 vs Hex vs Base64 приводит к разным байтовым массивам
  2. Использование строк вместо WordArray

    • CryptoJS интерпретирует строку иначе, чем бинарные данные
  3. Повторное использование IV

    • критическая уязвимость при CBC
  4. Неправильная длина ключа

    • AES строго зависит от 16/24/32 байт

Совместимость с внешними системами

При интеграции с backend на Java, Python или Go часто требуется:

  • фиксированный IV
  • заранее согласованный salt
  • единый алгоритм PBKDF2
  • идентичный padding (обычно PKCS7)

Например, в OpenSSL-совместимых схемах CryptoJS должен повторять логику EVP_BytesToKey или PBKDF2 с одинаковыми параметрами.


Контроль над криптографическим контекстом

Ручное управление key, IV и salt фактически выводит разработчика на уровень низкоуровневого криптографического проектирования. Это означает:

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

Такая модель используется там, где важна предсказуемость и совместимость, а не удобство.