Взаимодействие jsrsasign и OpenSSL

Взаимодействие между jsrsasign и OpenSSL опирается на единые представления криптографических объектов, где ключевую роль играют форматы PEM и DER.

PEM представляет собой Base64-кодирование бинарных данных DER с добавлением заголовков и разделителей:

-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

DER — бинарный ASN.1-формат, используемый как внутренняя форма представления ключей, сертификатов и подписей.

OpenSSL работает с обоими форматами напрямую, тогда как jsrsasign использует их через преобразование в строки и объекты JavaScript. Основная точка совместимости заключается в корректном распознавании структуры ASN.1.


Структуры ключей: PKCS#1 и PKCS#8

В экосистеме RSA часто встречаются два стандарта представления приватных ключей:

  • PKCS#1 — специализированный формат только для RSA
  • PKCS#8 — универсальный контейнер для различных алгоритмов

OpenSSL по умолчанию часто генерирует PKCS#8:

openssl genpkey -algorithm RSA -out private_key.pem

jsrsasign поддерживает оба варианта через KEYUTIL:

const rsakey = KEYUTIL.getKey(pemKey);

При этом PKCS#1 ключи имеют структуру:

-----BEGIN RSA PRIVATE KEY-----

PKCS#8:

-----BEGIN PRIVATE KEY-----

Несовпадение форматов является одной из частых причин ошибок импорта.


Преобразование ключей между OpenSSL и jsrsasign

OpenSSL используется как источник или валидатор криптографических материалов, jsrsasign — как среда выполнения в браузере или Node.js.

Экспорт RSA приватного ключа в OpenSSL:

openssl rsa -in private_key.pem -out pkcs1.pem

Преобразование PKCS#8 в PKCS#1:

openssl pkcs8 -topk8 -nocrypt -in key.pem -out pkcs8.pem

jsrsasign интерпретирует ключ через универсальный парсер:

const key = KEYUTIL.getKey(pem);
const sig = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
sig.init(key);

Подпись и проверка: SHA256withRSA

Совместимость подписей между OpenSSL и jsrsasign достигается через согласование алгоритма хеширования и схемы подписи.

OpenSSL:

openssl dgst -sha256 -sign private_key.pem -out sig.bin data.txt

Проверка:

openssl dgst -sha256 -verify public_key.pem -signature sig.bin data.txt

jsrsasign:

const sig = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
sig.init(publicKey);
sig.updateString(data);
const isValid = sig.verify(signatureHex);

Ключевым фактором является совпадение:

  • алгоритма хеширования (SHA-256)
  • схемы RSA padding (PKCS#1 v1.5 или PSS)
  • кодировки подписи (HEX vs Base64)

RSA-PSS и различия реализации

OpenSSL поддерживает RSA-PSS как более современную схему:

openssl dgst -sha256 -sign private.pem -sigopt rsa_padding_mode:pss data.txt

jsrsasign требует явного указания параметров:

const sig = new KJUR.crypto.Signature({
  alg: "SHA256withRSAandMGF1",
  prov: "cryptojs/jsrsa"
});

Несоответствие параметров MGF1 или salt length приводит к несовместимости результатов даже при одинаковых ключах.


Работа с ECDSA и кривыми

OpenSSL и jsrsasign поддерживают набор стандартных эллиптических кривых, таких как secp256r1 (P-256).

Генерация ключа OpenSSL:

openssl ecparam -name prime256v1 -genkey -noout -out ec.pem

Подпись:

openssl dgst -sha256 -sign ec.pem data.txt > sig.bin

jsrsasign:

const sig = new KJUR.crypto.Signature({ alg: "SHA256withECDSA" });
sig.init(ecPublicKey);
sig.updateString(data);
sig.verify(sigHex);

Ключевой аспект совместимости — формат подписи. OpenSSL использует DER-кодирование ECDSA-сигнатуры, содержащей два числа (r, s), тогда как jsrsasign может оперировать HEX-представлением.


X.509 сертификаты и цепочки доверия

OpenSSL часто используется для генерации сертификатов:

openssl req -new -x509 -key private.pem -out cert.pem

jsrsasign предоставляет парсинг и проверку структуры:

const x509 = new X509();
x509.readCertPEM(certPEM);

Внутренняя структура сертификата включает:

  • Subject
  • Issuer
  • Public Key
  • Signature Algorithm
  • Extensions

OpenSSL валидирует цепочки через локальное хранилище CA, jsrsasign требует явного указания доверенных сертификатов.


CSR (Certificate Signing Request)

CSR создаётся OpenSSL:

openssl req -new -key private.pem -out request.csr

jsrsasign:

const csr = new KJUR.asn1.csr.CertificationRequest({ ... });

Основное совпадение обеспечивается ASN.1 структурой:

  • Subject
  • Public Key
  • Signature

OpenSSL проверяет CSR:

openssl req -in request.csr -noout -text

jsrsasign извлекает поля через ASN.1 парсинг без внешних зависимостей.


Кодировки Base64 и бинарные ошибки

Частой причиной несовместимости является различие в обработке Base64:

OpenSSL:

  • использует PEM с переносами строк каждые 64 символа

jsrsasign:

  • допускает непрерывную Base64-строку

Ошибки возникают при:

  • наличии BOM
  • лишних пробелах
  • неправильных line endings (CRLF vs LF)

ASN.1 как общий слой интерпретации

Обе системы опираются на ASN.1 DER-структуры.

jsrsasign реализует собственный ASN.1 парсер:

ASN1HEX.parse(pemHex);

OpenSSL использует C-библиотеку OpenSSL ASN.1 engine.

Совместимость достигается только при строгом соблюдении структуры:

  • последовательность SEQUENCE
  • INTEGER для ключевых параметров
  • BIT STRING для публичных ключей

Типичные проблемы несовместимости

На практике возникают повторяющиеся категории ошибок:

  • несовпадение PKCS#1 и PKCS#8
  • различие алгоритмов padding (PKCS#1 v1.5 vs PSS)
  • неверная кодировка подписи (Base64 vs HEX)
  • различие в ECDSA DER encoding
  • нарушение структуры PEM заголовков
  • несоответствие алгоритма хеширования

Взаимное использование OpenSSL как инструмента валидации

OpenSSL часто применяется как эталон корректности криптографических операций, тогда как jsrsasign используется для выполнения аналогичных операций в среде JavaScript.

Проверка подписи, созданной jsrsasign, через OpenSSL:

openssl dgst -sha256 -verify public.pem -signature sig.bin data.txt

И обратная проверка позволяет выявлять расхождения в алгоритмах и кодировках без необходимости дополнительной отладки на уровне JavaScript.


Совместимость алгоритмов хеширования

Поддерживаемые пары:

  • SHA-1 (устаревший, но совместимый)
  • SHA-256 (основной)
  • SHA-384 / SHA-512

OpenSSL:

openssl dgst -sha512 data.txt

jsrsasign:

alg: "SHA512withRSA"

Несоответствие алгоритма хеширования приводит к полной невалидности подписи независимо от корректности ключей.


Форматы хранения ключей и переносимость

OpenSSL часто используется для генерации инфраструктуры ключей, тогда как jsrsasign выполняет их потребление в приложениях.

Поддерживаемые форматы:

  • PEM (основной)
  • DER (бинарный)
  • JWK (через преобразование)
  • PKCS#12 (через промежуточное извлечение)

PKCS#12:

openssl pkcs12 -export -out key.p12 -inkey private.pem -in cert.pem

jsrsasign не работает с PKCS#12 напрямую, требуя предварительного извлечения ключей через OpenSSL.


Совместимость моделей криптографического провайдера

OpenSSL реализует низкоуровневую C-архитектуру криптопровайдера.

jsrsasign использует JavaScript-реализацию (pure JS или WebCrypto fallback).

Различия проявляются в:

  • генерации случайных чисел
  • реализации padding
  • производительности ASN.1 парсинга

Несмотря на архитектурные различия, совместимость достигается на уровне стандартов PKI и криптографических примитивов, а не внутренней реализации.