RSA-подпись в формате PKCS#1 v1.5 представляет собой детерминированную схему формирования цифровой подписи, основанную на хэшировании сообщения и последующем шифровании хэша закрытым ключом RSA с применением стандартизированного заполнения (padding).
Суть схемы заключается в следующем:
Вычисляется хэш сообщения (например, SHA-256).
Формируется структура DigestInfo, содержащая
идентификатор алгоритма хэширования и сам хэш.
К полученным данным применяется padding по стандарту PKCS#1 v1.5.
Результат возводится в степень закрытого ключа RSA:
signature = (EM)^d mod n, где EM — encoded
message.При проверке выполняется обратная операция с использованием открытого ключа.
Библиотека Jsrsasign реализует RSA-подписи через объект
KJUR.crypto.Signature. Поддерживаются алгоритмы вида:
SHA1withRSASHA256withRSASHA384withRSASHA512withRSAАлгоритм PKCS#1 v1.5 используется по умолчанию при выборе RSA Signature API, если не задействованы схемы PSS.
Jsrsasign работает с ключами в формате PEM и внутренним объектом RSAKey.
const pemPrivateKey = `
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
`;
const privateKey = KEYUTIL.getKey(pemPrivateKey);
Публичный ключ:
const pemPublicKey = `
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
`;
const publicKey = KEYUTIL.getKey(pemPublicKey);
Подпись формируется через объект
KJUR.crypto.Signature.
const sig = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
sig.init(privateKey);
sig.updateString("Сообщение для подписи");
const signatureHex = sig.sign();
Ключевые этапы:
init(privateKey) — инициализация закрытого ключаupdateString() — добавление данныхsign() — генерация подписи в hex-форматеПри работе с бинарными данными используется
updateHex:
sig.init(privateKey);
sig.updateHex("a1b2c3d4");
const signature = sig.sign();
Для проверки используется тот же класс Signature, но с
открытым ключом.
const verifier = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
verifier.init(publicKey);
verifier.updateString("Сообщение для подписи");
const isValid = verifier.verify(signatureHex);
Результат:
true — подпись корректнаfalse — данные или подпись измененыJsrsasign абстрагирует сложную структуру PKCS#1 v1.5, но внутри происходит:
Формирование DER-структуры DigestInfo
Кодирование ASN.1
Применение padding:
0x00 || 0x01 || PS || 0x00 || DigestInfoВозведение в степень RSA
Эта схема не требует ручного формирования padding, но важно учитывать фиксированность структуры.
Выбор алгоритма влияет на безопасность и формат
DigestInfo.
Пример SHA-1 (устаревший):
new KJUR.crypto.Signature({ alg: "SHA1withRSA" });
SHA-256 (рекомендуется):
new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
SHA-512 (для повышенной стойкости):
new KJUR.crypto.Signature({ alg: "SHA512withRSA" });
Подпись и проверка должны использовать один и тот же алгоритм:
SHA256withRSA ≠ SHA1withRSA
Ошибка возникает при смешивании:
Решение — использовать единый формат (updateString или
updateHex).
Частая проблема:
Jsrsasign возвращает подпись в HEX. Для Base64 требуется преобразование:
const hex = sig.sign();
const b64 = hextob64(hex);
Обратное преобразование:
const hex = b64tohex(b64);
При взаимодействии с Java, .NET или OpenSSL важно учитывать:
Вместо Signature можно использовать RSAKey,
но это требует ручного хэширования:
const rsa = KEYUTIL.getKey(pemPrivateKey);
const sigValue = rsa.signString("msg", "sha256");
Проверка:
const isValid = rsa.verifyString("msg", signatureHex);
Схема широко поддерживается:
Это делает её стандартом для интеграций, несмотря на появление более современных схем (например, PSS).
Типичный процесс в Jsrsasign выглядит следующим образом:
SHA256withRSASignatureЭта последовательность фиксирована и повторяется для любых RSA PKCS#1 v1.5 операций.