KEYUTIL.getPEM в формат JWK

PEM-формат представляет собой текстовое представление криптографических ключей и сертификатов, основанное на Base64 с заголовками вида -----BEGIN PUBLIC KEY-----. Он широко используется в инфраструктуре PKI, TLS и OpenSSL-экосистеме. JWK (JSON Web Key), напротив, является JSON-структурой, описывающей ключ в стандарте JOSE и активно применяется в JWT, OAuth 2.0 и современных веб-протоколах.

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


PEM представляет собой контейнер, который может содержать:

  • RSA public/private keys
  • EC keys (ECDSA)
  • PKCS#8 структуры
  • X.509 сертификаты

Пример PEM RSA публичного ключа:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr...
-----END PUBLIC KEY-----

Внутри Jsrsasign PEM воспринимается как входной формат, который может быть распарсен в объект ключа:

const keyObj = KEYUTIL.getKey(pemString);

Этот объект далее может быть преобразован в другие форматы, включая JWK.


JWK как структурированное представление ключа

JWK представляет ключ в виде JSON-объекта. Для RSA публичного ключа типичная структура выглядит так:

{
  "kty": "RSA",
  "n": "base64url-modulus",
  "e": "AQAB",
  "alg": "RS256",
  "ext": true
}

Для EC ключей структура меняется:

{
  "kty": "EC",
  "crv": "P-256",
  "x": "base64url-x",
  "y": "base64url-y"
}

JWK удобен тем, что легко сериализуется, передаётся через API и используется в браузерных сценариях без необходимости работы с бинарными структурами.


KEYUTIL.getKey как промежуточный этап

В Jsrsasign преобразование PEM в JWK не выполняется напрямую одной функцией getPEM. Вместо этого используется связка:

  • KEYUTIL.getKey(pem)
  • KEYUTIL.getJWKFromKey(keyObj)

Таким образом, PEM сначала преобразуется в внутреннее представление ключа, а затем в JWK.


Преобразование PEM → JWK

Основной поток преобразования выглядит следующим образом:

const pem = `
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr...
-----END PUBLIC KEY-----
`;

const keyObj = KEYUTIL.getKey(pem);
const jwk = KEYUTIL.getJWKFromKey(keyObj);

console.log(jwk);

Результатом будет объект JWK, содержащий параметры ключа.


Разбор внутреннего процесса конвертации

При вызове KEYUTIL.getKey библиотека выполняет:

  1. Определение типа PEM (RSA, EC, PKCS#8)
  2. Декодирование Base64 содержимого
  3. Парсинг ASN.1 структуры
  4. Построение внутреннего объекта keyObj

После этого getJWKFromKey извлекает математические параметры:

  • для RSA: модуль n и экспоненту e
  • для EC: координаты точки x и y, а также кривую crv

Эти значения затем кодируются в Base64URL, соответствующий спецификации JWK.


Пример полного преобразования RSA ключа

import { KEYUTIL } from "jsrsasign";

const pem = `
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAvf...
-----END RSA PUBLIC KEY-----
`;

const keyObj = KEYUTIL.getKey(pem);

const jwk = KEYUTIL.getJWKFromKey(keyObj);

console.log(jwk);

Результат:

{
  "kty": "RSA",
  "n": "0vx7agoebGcQSuuPiLJXZptN...",
  "e": "AQAB"
}

Обратное преобразование JWK → PEM

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

const keyObj = KEYUTIL.getKey(jwk);
const pem = KEYUTIL.getPEM(keyObj);

Здесь:

  • JWK преобразуется в keyObj
  • keyObj экспортируется в PEM

Таким образом, KEYUTIL работает как универсальный мост между форматами.


Использование KEYUTIL.getPEM после JWK

Когда ключ представлен в JWK, его часто требуется преобразовать обратно в PEM для совместимости с:

  • OpenSSL
  • серверными библиотеками Node.js
  • системами подписи, требующими PEM

Пример:

const jwk = {
  kty: "RSA",
  n: "0vx7agoebGcQSuuPiLJXZptN...",
  e: "AQAB"
};

const keyObj = KEYUTIL.getKey(jwk);
const pem = KEYUTIL.getPEM(keyObj);

console.log(pem);

Типы PEM, поддерживаемые при экспорте

KEYUTIL.getPEM может возвращать разные типы ключей:

  • PUBLIC KEY (SPKI формат)
  • RSA PRIVATE KEY (PKCS#1)
  • PRIVATE KEY (PKCS#8)
  • EC PRIVATE KEY

Тип выбирается автоматически или задаётся параметрами:

const pem = KEYUTIL.getPEM(keyObj, "PKCS8PRV");

Работа с EC ключами при конвертации

Для EC ключей структура JWK включает кривую:

  • P-256
  • P-384
  • P-521

Пример:

const pem = `
-----BEGIN EC PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEl...
-----END EC PUBLIC KEY-----
`;

const keyObj = KEYUTIL.getKey(pem);
const jwk = KEYUTIL.getJWKFromKey(keyObj);

Результат:

{
  "kty": "EC",
  "crv": "P-256",
  "x": "...",
  "y": "..."
}

Особенности кодирования Base64URL

При преобразовании в JWK используется Base64URL вместо стандартного Base64:

  • + заменяется на -
  • / заменяется на _
  • отсутствуют =

Jsrsasign выполняет это автоматически, однако при ручной обработке важно учитывать формат.


Ошибки при конвертации PEM → JWK

На практике встречаются типовые проблемы:

Неверный PEM формат

Если строка не содержит корректных заголовков:

Error: unsupported PEM format

Повреждённый Base64 блок

Любые лишние символы или пробелы могут нарушить декодирование ASN.1 структуры.

Несоответствие типа ключа

Попытка интерпретировать EC ключ как RSA приводит к ошибкам при извлечении параметров.


Внутренние структуры KEYUTIL

Объект keyObj, создаваемый после getKey, содержит:

  • type — тип ключа
  • isPrivate — приватный или публичный
  • prvKeyHex — приватные параметры в hex
  • pubKeyHex — публичная часть
  • n, e для RSA
  • curveName, x, y для EC

Эти поля используются при генерации JWK.


Практическое применение конвертации

Преобразование PEM в JWK через KEYUTIL используется в сценариях:

  • выдача ключей через REST API
  • интеграция с OAuth 2.0 Authorization Server
  • работа с JWT в браузере
  • миграция ключей между системами
  • хранение ключей в JSON-формате в NoSQL базах

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

JWK часто используется для проверки подписи JWT. В связке с Jsrsasign процесс выглядит так:

const keyObj = KEYUTIL.getKey(jwk);
const isValid = KJUR.jws.JWS.verifyJWT(token, keyObj, {
  alg: ["RS256"]
});

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


Структурная роль KEYUTIL в экосистеме Jsrsasign

KEYUTIL является центральным модулем, который объединяет:

  • парсинг PEM
  • генерацию ключей
  • экспорт в PEM
  • экспорт в JWK
  • импорт из JWK

Фактически он выступает как слой абстракции между ASN.1 структурой и JSON Web Key спецификацией.


Сравнение PEM и JWK в контексте KEYUTIL

PEM:

  • текстовый формат с заголовками
  • ориентирован на инфраструктуру X.509
  • используется в TLS

JWK:

  • JSON-структура
  • ориентирован на веб-протоколы
  • используется в JWT и OAuth

KEYUTIL обеспечивает двустороннюю трансформацию без потери криптографических параметров, что делает возможным свободное переключение между экосистемами.