Варианты реализации JWE в связке с другими библиотеками

Общая модель взаимодействия библиотек при работе с JWE

В практических JavaScript-проектах редко встречается ситуация, когда весь стек криптографии замыкается на одной библиотеке. Даже при использовании jsrsasign для формирования и разбора JWE (JSON Web Encryption) нередко возникает необходимость взаимодействия с более современными или специализированными реализациями, такими как jose, Web Crypto API или серверные криптобиблиотеки Node.js.

Основная сложность совместимости JWE заключается не в самом алгоритме, а в согласованности параметров:

  • формат сериализации (Compact JWE vs General JSON Serialization)
  • алгоритм шифрования (alg)
  • алгоритм контентного шифрования (enc)
  • формат ключей (PEM, JWK, CryptoKey)
  • правила base64url кодирования
  • структура protected header

Даже небольшое расхождение в одном из этих элементов приводит к невозможности расшифровки токена между библиотеками.


jsrsasign как базовый инструмент JWE

Библиотека jsrsasign предоставляет достаточно классический API для работы с JWE через объект KJUR.jwe.JWE. Она ориентирована на поддержку спецификации JOSE, но при этом сохраняет старый стиль JavaScript-API.

Пример формирования JWE:

const header = {
  alg: "RSA-OAEP",
  enc: "A256GCM"
};

const payload = JSON.stringify({
  sub: "user123",
  role: "admin"
});

const publicKey = `-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----`;

const jwe = KJUR.jwe.JWE.encrypt(payload, publicKey, header);

Данный подход формирует Compact Serialization JWE:

header.encryptedKey.iv.ciphertext.tag

Особенность jsrsasign заключается в том, что он часто используется как «точка совместимости» между устаревшими реализациями JWT и более современными криптобиблиотеками.


Интеграция jsrsasign и библиотеки jose

Библиотека jose считается одной из наиболее актуальных реализаций JOSE-стека в JavaScript. При взаимодействии с jsrsasign чаще всего возникает задача миграции или параллельной работы двух систем.

Типичный сценарий: генерация JWE в jsrsasign и расшифровка в jose.

Пример расшифровки через jose:

import { compactDecrypt } from "jose";

const privateKey = await importPKCS8(pemPrivateKey, "RSA-OAEP");

const { plaintext } = await compactDecrypt(jweToken, privateKey);

console.log(new TextDecoder().decode(plaintext));

Критически важные условия совместимости:

  • jsrsasign должен использовать RSA-OAEP или RSA-OAEP-256, а не RSAES-PKCS1-v1_5
  • enc должен совпадать (A256GCM, A128CBC-HS256)
  • ключи должны быть корректно конвертированы в JWK/PKCS8

Обратная совместимость (jose → jsrsasign) часто работает хуже из-за различий в сериализации protected header.


Взаимодействие с Web Crypto API

Web Crypto API используется в браузерных окружениях и современных runtime-средах. Основная проблема интеграции с jsrsasign заключается в различии представления ключей.

Web Crypto использует CryptoKey, тогда как jsrsasign ожидает PEM или внутренние структуры.

Преобразование ключа для совместимости:

const publicKey = await window.crypto.subtle.importKey(
  "spki",
  spkiBuffer,
  {
    name: "RSA-OAEP",
    hash: "SHA-256"
  },
  false,
  ["encrypt"]
);

Далее возникает архитектурный выбор:

  • использовать Web Crypto для шифрования
  • использовать jsrsasign только для формирования JWT/JWE header
  • либо полностью изолировать jsrsasign на стороне сервера

В смешанном режиме чаще встречается следующая схема:

  • Web Crypto: генерация и шифрование payload
  • jsrsasign: упаковка структуры JWE и подписи метаданных

Node.js crypto и гибридные схемы

Node.js предоставляет низкоуровневый crypto модуль, который часто используется для ускорения операций шифрования.

В гибридных системах jsrsasign выполняет роль форматтера JWE, а Node crypto — криптографического ядра.

Пример RSA-OAEP шифрования через Node:

import crypto from "crypto";

const encryptedKey = crypto.publicEncrypt(
  {
    key: publicKeyPem,
    oaepHash: "sha256"
  },
  Buffer.from(cek)
);

Далее результат может быть интегрирован в структуру JWE, сформированную jsrsasign вручную.

Подобный подход используется в системах, где требуется:

  • контроль над криптографией на уровне инфраструктуры
  • аудит алгоритмов
  • соответствие требованиям FIPS

Совместимость форматов сериализации

Одна из ключевых проблем взаимодействия библиотек — различие в форматах JWE.

Compact Serialization

Используется в jsrsasign по умолчанию:

BASE64URL(header).
BASE64URL(encryptedKey).
BASE64URL(iv).
BASE64URL(ciphertext).
BASE64URL(tag)
General JSON Serialization

Чаще встречается в jose:

{
  "protected": "...",
  "encrypted_key": "...",
  "iv": "...",
  "ciphertext": "...",
  "tag": "..."
}

jsrsasign ограниченно поддерживает JSON-формат, поэтому при интеграции с другими библиотеками часто требуется ручная трансформация структуры.


Проблемы согласования алгоритмов

На практике большинство ошибок совместимости возникает не на уровне кода, а на уровне параметров:

RSA алгоритмы
  • RSA1_5 — устаревший, но всё ещё встречается
  • RSA-OAEP — базовый современный вариант
  • RSA-OAEP-256 — рекомендуемый вариант

jsrsasign может по умолчанию использовать менее строгие настройки, тогда как jose требует явного указания SHA-256.

Content Encryption (enc)
  • A128GCM
  • A256GCM
  • A128CBC-HS256

Ошибка выбора enc приводит к невозможности расшифровки даже при корректных ключах.


Гибридная архитектура: разделение ответственности

В сложных системах часто применяется архитектурный паттерн разделения криптографических обязанностей:

  • jsrsasign: формирование JWT/JWE структуры, работа с legacy токенами
  • jose: современное шифрование и дешифрование
  • Web Crypto: аппаратно ускоренные операции в браузере
  • Node crypto: серверная криптооперационная база

Пример распределённого сценария:

  1. jsrsasign формирует JWE header
  2. Node crypto генерирует CEK (Content Encryption Key)
  3. Web Crypto или Node crypto выполняет шифрование payload
  4. jsrsasign собирает финальный Compact JWE

Проблемы base64url и нормализации данных

Даже при совпадении алгоритмов возможны ошибки из-за различий в кодировании:

  • jsrsasign использует собственную реализацию base64url
  • jose строго следует RFC 7516
  • Web Crypto требует ArrayBuffer

Расхождения проявляются в:

  • отсутствии padding
  • различиях в обработке UTF-8 строк
  • двойном кодировании JSON

Типичная ошибка:

Invalid Compact JWE

Причина почти всегда связана с несовпадением base64url представления.


Практика миграции с jsrsasign на jose

Миграция редко выполняется одномоментно, чаще используется промежуточный слой совместимости:

  • этап 1: jsrsasign генерирует JWE
  • этап 2: jose добавляется для валидации
  • этап 3: генерация полностью переносится в jose
  • этап 4: jsrsasign остаётся только для legacy JWT

Ключевой момент миграции — унификация алгоритмов и отказ от нестандартных конфигураций.


Совместное использование в микросервисной архитектуре

В распределённых системах jsrsasign часто встречается на границе:

  • frontend (браузер)
  • API gateway
  • legacy сервисы

При этом jose или native crypto используются внутри микросервисов.

Типовая схема:

  • браузер: Web Crypto → JWE
  • gateway: jsrsasign проверка токена
  • backend: jose дешифрование и валидация claims

Такой подход снижает зависимость от одного криптографического стека и облегчает обновление компонентов без полной переработки системы.