Алгоритм RSA основан на математических операциях над большими числами фиксированного размера, определяемого длиной ключа. Это накладывает жёсткое ограничение на объём данных, который может быть зашифрован за одну операцию. В Jsrsasign это проявляется особенно явно, поскольку библиотека предоставляет низкоуровневые интерфейсы к RSA без автоматического разбиения данных.
Максимальный размер шифруемого блока определяется длиной ключа и схемой заполнения (padding).
Для RSA с PKCS#1 v1.5:
keySizeInBytes - 11Для RSA-OAEP:
keySizeInBytes - 2 * hashLen - 2Пример для 2048-битного ключа:
Любое превышение приводит к ошибке шифрования или некорректному результату.
RSA не предназначен для обработки произвольных объёмов данных. Его математическая модель работает с числом m, которое должно быть меньше модуля n:
Если размер сообщения превышает допустимый диапазон, преобразование становится невозможным в корректной форме.
Padding-схемы добавляют структурные данные, необходимые для безопасности:
Эти данные уменьшают доступный объём полезной нагрузки.
В библиотеке Jsrsasign RSA реализован через объект
RSAKey. При вызове методов шифрования:
encrypt(plaintext)decrypt(ciphertext)входные данные преобразуются в байтовую строку и проверяются на допустимый размер.
При превышении лимита возможны сценарии:
nullJsrsasign не выполняет автоматическое разбиение строки на блоки. Это оставляется на уровень приложения.
Строки в JavaScript часто кодируются в UTF-8 или UTF-16, что влияет на реальный размер данных.
Пример:
Таким образом, строка длиной 200 символов может превышать лимит RSA-2048 даже без визуального увеличения.
При подготовке данных важно учитывать фактический байтовый размер после кодирования.
Практическое применение RSA в Jsrsasign почти всегда строится на гибридной модели:
Типовая схема:
encryptedData + encryptedKeyJsrsasign предоставляет инструменты через
KJUR.crypto.Cipher и KEYUTIL.
Пример логики:
// генерация AES ключа
var aesKey = KJUR.crypto.Cipher.generateRandomKey(256);
// шифрование данных AES
var encryptedData = KJUR.crypto.Cipher.encrypt(data, aesKey, "AES");
// загрузка RSA публичного ключа
var rsa = KEYUTIL.getKey(publicKeyPem);
// шифрование AES ключа через RSA
var encryptedKey = rsa.encrypt(aesKey);
В этой схеме RSA обрабатывает только короткую строку ключа AES, что укладывается в допустимый диапазон.
При необходимости использования RSA напрямую для больших данных применяется ручное разбиение.
Алгоритм:
Пример логики:
var maxBlock = 245; // для RSA 2048 PKCS#1 v1.5
var blocks = [];
for (var i = 0; i < data.length; i += maxBlock) {
var chunk = data.substring(i, i + maxBlock);
blocks.push(rsa.encrypt(chunk));
}
Результирующий массив содержит набор независимых RSA-шифрованных блоков.
Разбиение данных через RSA приводит к ряду проблем:
Каждый блок шифруется независимо, что исключает оптимизации уровня протокола.
RSA увеличивает размер данных до фиксированной длины ключа:
Даже если входной блок содержит 1 байт, результат будет занимать полный размер ключа.
Это приводит к экспоненциальному росту данных при chunking.
Важно различать ограничения шифрования и цифровой подписи.
При RSA-подписи:
Таким образом:
Jsrsasign реализует подписи через:
KJUR.crypto.SignatureАрхитектура приложений обычно учитывает следующие принципы:
Проверка размера перед операцией:
function checkSize(data, keySizeBytes) {
return data.length <= (keySizeBytes - 11);
}
На практике часто встречаются следующие проблемы:
Jsrsasign не выполняет автоматическую защиту от этих сценариев, поэтому логика контроля остаётся на уровне приложения.
Jsrsasign поддерживает разные схемы:
Разные реализации серверов могут требовать строго определённый режим.
Несовместимость проявляется в:
OAEP обеспечивает лучшую криптографическую стойкость, но уменьшает допустимый размер данных.
Работа с RSA в Jsrsasign всегда подчиняется одной из двух моделей:
Любые попытки обойти ограничение увеличением ключа приводят только к росту стоимости вычислений и размера данных без изменения фундаментального лимита структуры RSA.