Клиентские библиотеки шифрования, такие как Crypto-js, часто используются в связке с серверной логикой, реализованной на других языках: Node.js, Python, Java, PHP. Несмотря на использование одинаковых алгоритмов (AES, SHA-256 и др.), различия в форматах данных, способах кодирования и параметрах шифрования могут приводить к несовместимости.
Ключевые источники проблем:
Первый этап тестирования — подтверждение того, что клиент и сервер используют один и тот же алгоритм с одинаковыми параметрами.
Пример AES (CBC + PKCS7):
Crypto-js по умолчанию:
На сервере необходимо явно указать те же параметры.
Node.js (crypto):
crypto.createCipheriv('aes-256-cbc', key, iv);
Python (PyCryptodome):
AES.new(key, AES.MODE_CBC, iv)
Любое расхождение делает результат несовместимым.
Crypto-js активно использует собственные структуры
(WordArray). При передаче данных на сервер требуется
преобразование.
Основные форматы:
Пример преобразования:
const encrypted = CryptoJS.AES.encrypt("text", key, { iv: iv });
const base64 = encrypted.toString(); // Base64
На сервере необходимо:
Crypto-js допускает два способа задания ключа:
WordArray)Особенность: если передаётся строка, Crypto-js автоматически применяет алгоритм OpenSSL EVP_BytesToKey для генерации ключа и IV.
Это критически важно.
Рекомендация для совместимости:
Пример корректного подхода:
const key = CryptoJS.enc.Hex.parse("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff");
const iv = CryptoJS.enc.Hex.parse("00112233445566778899aabbccddeeff");
CryptoJS.AES.encrypt("text", key, { iv: iv });
Crypto-js по умолчанию использует PKCS7. На сервере необходимо выбрать тот же метод.
Ошибки при несовпадении:
Результат шифрования представляет собой объект:
{
ciphertext: WordArray,
salt: WordArray (опционально),
iv: WordArray (если задан)
}
Метод .toString() возвращает строку в формате
OpenSSL:
U2FsdGVkX1...
Это:
Salted__Сервер должен уметь:
Или — отключить этот механизм и передавать всё явно.
Важно не только совпадение текста, но и байтов.
Сравнение:
Для надёжной проверки создаются фиксированные тест-кейсы:
Пример:
"Hello World"001122...aabbcc...Base64 строкаЭти значения фиксируются и используются во всех средах.
1. Разная кодировка строки
Crypto-js:
CryptoJS.enc.Utf8.parse("text")
Если сервер использует ASCII или Latin1 — данные не совпадут.
2. Использование пароля вместо ключа
CryptoJS.AES.encrypt("text", "password")
На сервере это не будет работать без повторения derivation алгоритма.
3. Потеря IV
Если IV не передан:
4. Неправильный режим
AES-ECB и AES-CBC дают разные результаты даже с одинаковыми ключами.
5. Ошибки Base64
Некоторые серверные библиотеки:
Это ломает совместимость.
Crypto-js (клиент):
const encrypted = CryptoJS.AES.encrypt("text", key, { iv: iv }).ciphertext.toString(CryptoJS.enc.Base64);
Node.js (сервер):
const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuffer, ivBuffer);
let decrypted = decipher.update(base64Data, 'base64', 'utf8');
decrypted += decipher.final('utf8');
Crypto-js → Python:
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = unpad(cipher.decrypt(base64.b64decode(data)), AES.block_size)
Метод пошаговой проверки:
проверить длину ключа (128 / 192 / 256 бит)
убедиться в совпадении IV
сравнить режим шифрования
проверить паддинг
вывести промежуточные значения:
Для полной совместимости:
Формат JSON:
{
"iv": "hex",
"data": "base64"
}
Создаются unit-тесты:
Инструменты:
Минимальный набор:
Если данные совпадают во всех трёх средах — реализация считается совместимой.
Разные версии Crypto-js могут:
Фиксация версии обязательна:
npm install crypto-js@4.1.1
Такая схема обеспечивает устойчивую и предсказуемую совместимость между Crypto-js и серверной частью независимо от языка реализации.