Криптографические алгоритмы с асимметричными ключами, такие как RSA, обладают фундаментальным ограничением — их производительность и допустимый размер шифруемых данных. В практических системах это делает невозможным использование RSA для шифрования больших объёмов информации напрямую. AES, напротив, предназначен для быстрого симметричного шифрования больших данных, но требует безопасного обмена ключом.
Гибридное шифрование объединяет преимущества обеих схем: RSA используется для защиты симметричного ключа, а AES — для шифрования данных.
Jsrsasign представляет собой чисто JavaScript-библиотеку, реализующую криптографические алгоритмы, включая:
Основные пространства имён:
KEYUTIL — работа с ключамиKJUR.crypto.Cipher — симметричное шифрованиеKJUR.crypto.CipherUtil — утилиты для криптографииKJUR.asn1 — работа с ASN.1 структурамиГибридная модель строится вокруг разделения ответственности:
Генерация случайного AES-ключа
Шифрование данных AES-ключом
Шифрование AES-ключа с помощью RSA публичного ключа
Передача:
На стороне получателя:
Для начала требуется создать RSA ключевую пару.
const rsaKeypair = KEYUTIL.generateKeypair("RSA", 2048);
const publicKey = rsaKeypair.pubKeyObj;
const privateKey = rsaKeypair.prvKeyObj;
Альтернативный вариант — импорт PEM-ключей:
const privateKey = KEYUTIL.getKey(pemPrivateKey);
const publicKey = KEYUTIL.getKey(pemPublicKey);
RSA-2048 остаётся базовым уровнем безопасности для большинства прикладных задач, хотя в современных системах часто используется RSA-3072 или выше.
AES-ключ должен быть случайным и криптографически стойким. В
Jsrsasign используется генерация через
KJUR.crypto.CipherUtil.
const aesKeyHex = KJUR.crypto.Cipher.generateRandomKey(256);
Здесь 256 бит — стандарт для AES-256.
IV (инициализационный вектор) также генерируется отдельно:
const ivHex = KJUR.crypto.Cipher.generateRandomIV();
Для симметричного шифрования используется AES-CBC или AES-GCM (в зависимости от реализации и требований).
Пример AES-CBC:
const encryptedData = KJUR.crypto.Cipher.encrypt(
plaintext,
aesKeyHex,
"aes",
"cbc",
ivHex
);
Результат обычно кодируется в Base64 или Hex.
RSA применяется только к ключу, а не к основным данным.
const encryptedAesKey = publicKey.encrypt(aesKeyHex);
В Jsrsasign используется PKCS#1 v1.5 или OAEP padding:
const encryptedAesKey = KJUR.crypto.Cipher.encrypt(
aesKeyHex,
publicKey,
"RSAOAEP"
);
OAEP предпочтительнее из-за устойчивости к атакам.
Гибридная схема требует упаковки всех элементов в единый объект:
const payload = {
key: encryptedAesKey,
iv: ivHex,
data: encryptedData
};
Для передачи обычно применяется сериализация:
const jsonPayload = JSON.stringify(payload);
Далее возможна дополнительная кодировка в Base64:
const encoded = KJUR.crypto.CipherUtil.stringtob64(jsonPayload);
На стороне получателя первым шагом является восстановление симметричного ключа:
const decryptedAesKey = privateKey.decrypt(encryptedAesKey);
Если используется OAEP:
const decryptedAesKey = KJUR.crypto.Cipher.decrypt(
encryptedAesKey,
privateKey,
"RSAOAEP"
);
После получения ключа выполняется расшифрование данных:
const decryptedData = KJUR.crypto.Cipher.decrypt(
data,
decryptedAesKey,
"aes",
"cbc",
ivHex
);
Результат преобразуется обратно в строку:
const originalText = KJUR.crypto.CipherUtil.b64toutf8(decryptedData);
Пример GCM:
const encrypted = KJUR.crypto.Cipher.encrypt(
plaintext,
aesKeyHex,
"aes",
"gcm",
ivHex
);
Jsrsasign поддерживает стандартные форматы:
Импорт ключа из PEM:
const key = KEYUTIL.getKey(pemString);
Экспорт:
const pem = KEYUTIL.getPEM(privateKey, "PKCS8PRV");
Использование фиксированного IV полностью ломает безопасность AES-CBC.
RSA не предназначен для этого. Ограничение связано с размером модуля и padding.
Один ключ на множество сообщений увеличивает риск криптоанализа.
PKCS#1 v1.5 считается устаревшим в защищённых системах.
Практическая реализация обычно включает:
Структура пакета:
{
k: encryptedKey,
i: iv,
d: ciphertext,
a: authTag
}
const aesKey = KJUR.crypto.Cipher.generateRandomKey(256);
const iv = KJUR.crypto.Cipher.generateRandomIV();
const encryptedData = KJUR.crypto.Cipher.encrypt(
message,
aesKey,
"aes",
"gcm",
iv
);
const encryptedKey = publicKey.encrypt(aesKey);
const packet = {
key: encryptedKey,
iv: iv,
data: encryptedData
};
const aesKey = privateKey.decrypt(packet.key);
const decrypted = KJUR.crypto.Cipher.decrypt(
packet.data,
aesKey,
"aes",
"gcm",
packet.iv
);
Гибридная модель обеспечивает:
Jsrsasign работает полностью в JavaScript, что делает его применимым в:
При этом важно учитывать: