PEM-формат представляет собой текстовое представление
криптографических ключей и сертификатов, основанное на Base64 с
заголовками вида -----BEGIN PUBLIC KEY-----. Он широко
используется в инфраструктуре PKI, TLS и OpenSSL-экосистеме. JWK (JSON
Web Key), напротив, является JSON-структурой, описывающей ключ в
стандарте JOSE и активно применяется в JWT, OAuth 2.0 и современных
веб-протоколах.
В практической разработке часто возникает необходимость преобразования ключей между PEM и JWK. В библиотеке Jsrsasign основная работа с такими преобразованиями сосредоточена вокруг объекта KEYUTIL, который предоставляет функции парсинга, экспорта и конвертации криптографических ключей.
PEM представляет собой контейнер, который может содержать:
Пример PEM RSA публичного ключа:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr...
-----END PUBLIC KEY-----
Внутри Jsrsasign PEM воспринимается как входной формат, который может быть распарсен в объект ключа:
const keyObj = KEYUTIL.getKey(pemString);
Этот объект далее может быть преобразован в другие форматы, включая 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 и используется в браузерных сценариях без необходимости работы с бинарными структурами.
В Jsrsasign преобразование PEM в JWK не выполняется напрямую одной
функцией getPEM. Вместо этого используется связка:
KEYUTIL.getKey(pem)KEYUTIL.getJWKFromKey(keyObj)Таким образом, 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 библиотека выполняет:
После этого getJWKFromKey извлекает математические
параметры:
n и экспоненту ex и y, а также
кривую crvЭти значения затем кодируются в Base64URL, соответствующий спецификации JWK.
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"
}
Хотя основная тема связана с getPEM, важно понимать
симметричный процесс, который часто используется вместе:
const keyObj = KEYUTIL.getKey(jwk);
const pem = KEYUTIL.getPEM(keyObj);
Здесь:
Таким образом, KEYUTIL работает как универсальный мост между форматами.
Когда ключ представлен в JWK, его часто требуется преобразовать обратно в PEM для совместимости с:
Пример:
const jwk = {
kty: "RSA",
n: "0vx7agoebGcQSuuPiLJXZptN...",
e: "AQAB"
};
const keyObj = KEYUTIL.getKey(jwk);
const pem = KEYUTIL.getPEM(keyObj);
console.log(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 ключей структура JWK включает кривую:
Пример:
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": "..."
}
При преобразовании в JWK используется Base64URL вместо стандартного Base64:
+ заменяется на -/ заменяется на _=Jsrsasign выполняет это автоматически, однако при ручной обработке важно учитывать формат.
На практике встречаются типовые проблемы:
Если строка не содержит корректных заголовков:
Error: unsupported PEM format
Любые лишние символы или пробелы могут нарушить декодирование ASN.1 структуры.
Попытка интерпретировать EC ключ как RSA приводит к ошибкам при извлечении параметров.
Объект keyObj, создаваемый после getKey, содержит:
type — тип ключаisPrivate — приватный или публичныйprvKeyHex — приватные параметры в hexpubKeyHex — публичная частьn, e для RSAcurveName, x, y для ECЭти поля используются при генерации JWK.
Преобразование PEM в JWK через KEYUTIL используется в сценариях:
JWK часто используется для проверки подписи JWT. В связке с Jsrsasign процесс выглядит так:
const keyObj = KEYUTIL.getKey(jwk);
const isValid = KJUR.jws.JWS.verifyJWT(token, keyObj, {
alg: ["RS256"]
});
Если ключ изначально был PEM, его можно предварительно конвертировать в JWK для унификации хранения.
KEYUTIL является центральным модулем, который объединяет:
Фактически он выступает как слой абстракции между ASN.1 структурой и JSON Web Key спецификацией.
PEM:
JWK:
KEYUTIL обеспечивает двустороннюю трансформацию без потери криптографических параметров, что делает возможным свободное переключение между экосистемами.