Конвертация форматов ключей

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

Основные форматы:

  • PEM (Privacy-Enhanced Mail) — текстовый формат с Base64-кодированием и служебными заголовками
  • DER (Distinguished Encoding Rules) — бинарное представление ASN.1-структур
  • PKCS#1 — формат для RSA-ключей (отдельно приватные и публичные)
  • PKCS#8 — универсальный формат для приватных ключей
  • X.509 SubjectPublicKeyInfo — формат для публичных ключей
  • JWK (JSON Web Key) — JSON-представление ключей

PEM и DER: текст против бинарного формата

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

-----BEGIN RSA PRIVATE KEY-----
(base64)
-----END RSA PRIVATE KEY-----

DER — это тот же набор данных, но в бинарной форме.

В Jsrsasign конвертация между ними выполняется через утилиты:

var pem = KEYUTIL.getPEM(keyObj, "PKCS1PRV");
var derHex = KEYUTIL.getHexFromPEM(pem);

Обратное преобразование:

var pem = KEYUTIL.getPEMFromHex(derHex, "RSA PRIVATE KEY");

PKCS#1 и PKCS#8: различия форматов приватных ключей

PKCS#1 используется исключительно для RSA и содержит структуру:

  • modulus (n)
  • publicExponent (e)
  • privateExponent (d)
  • дополнительные параметры CRT

PKCS#8 является универсальным контейнером, поддерживающим:

  • RSA
  • EC
  • DSA

Конвертация PKCS#1 → PKCS#8:

var keyObj = KEYUTIL.getKey(pemPKCS1);
var pemPKCS8 = KEYUTIL.getPEM(keyObj, "PKCS8PRV");

Обратное преобразование:

var keyObj = KEYUTIL.getKey(pemPKCS8);
var pemPKCS1 = KEYUTIL.getPEM(keyObj, "PKCS1PRV");

Публичные ключи: PKCS#1 vs X.509

Публичный ключ может быть представлен:

  • PKCS#1 (RSA PUBLIC KEY) — содержит только modulus и exponent
  • X.509 (SubjectPublicKeyInfo) — включает алгоритм и ключ

Конвертация:

var keyObj = KEYUTIL.getKey(pkcs1PubPEM);
var x509PubPEM = KEYUTIL.getPEM(keyObj);

Jsrsasign по умолчанию экспортирует публичные ключи в формате X.509.


Работа с JWK (JSON Web Key)

JWK используется в веб-протоколах (JWT, OAuth). Пример:

{
  "kty": "RSA",
  "n": "...",
  "e": "AQAB",
  "d": "..."
}

Импорт JWK:

var keyObj = KEYUTIL.getKey(jwkObject);

Экспорт в JWK:

var jwk = KEYUTIL.getJWKFromKey(keyObj);

Особенности:

  • Все параметры кодируются в Base64URL
  • Формат удобен для передачи по API
  • Не содержит ASN.1

Конвертация RSA-ключей между форматами

Пример полного цикла:

// PEM PKCS#1 → объект
var keyObj = KEYUTIL.getKey(pemPKCS1);

// → PKCS#8
var pkcs8 = KEYUTIL.getPEM(keyObj, "PKCS8PRV");

// → JWK
var jwk = KEYUTIL.getJWKFromKey(keyObj);

// → обратно в PEM
var keyObj2 = KEYUTIL.getKey(jwk);
var pem = KEYUTIL.getPEM(keyObj2, "PKCS1PRV");

Конвертация EC-ключей

Для эллиптических кривых используется только PKCS#8:

var keyObj = KEYUTIL.getKey(ecPem);
var jwk = KEYUTIL.getJWKFromKey(keyObj);

Обратное преобразование:

var keyObj = KEYUTIL.getKey(jwk);
var pem = KEYUTIL.getPEM(keyObj, "PKCS8PRV");

Шифрованные приватные ключи

PKCS#8 поддерживает шифрование:

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

Импорт:

var keyObj = KEYUTIL.getKey(encryptedPem, "password");

Экспорт:

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

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

  • AES
  • DES-EDE3
  • PBKDF2

ASN.1 и внутренняя структура ключей

Jsrsasign оперирует ASN.1-структурами через hex-представление.

Пример извлечения DER:

var hex = KEYUTIL.getHexFromPEM(pem);

ASN.1 структура RSA:

SEQUENCE {
  INTEGER (n)
  INTEGER (e)
  INTEGER (d)
  ...
}

Это позволяет:

  • анализировать ключи
  • вручную модифицировать структуры
  • валидировать формат

Автоматическое определение формата

Метод KEYUTIL.getKey() определяет формат автоматически:

var keyObj = KEYUTIL.getKey(input);

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

  • PEM строки
  • DER hex
  • JWK объекты
  • сертификаты

Частые проблемы при конвертации

Несоответствие формата:

  • PKCS#1 не подходит для EC-ключей
  • X.509 обязателен для публичных ключей в большинстве API

Ошибки кодировки:

  • Base64 vs Base64URL
  • лишние переносы строк

Пароли:

  • неправильный пароль → исключение
  • несовместимые алгоритмы шифрования

Практика: нормализация ключей

Приведение ключей к единому формату:

function normalizeKey(input) {
  var keyObj = KEYUTIL.getKey(input);
  return {
    pem: KEYUTIL.getPEM(keyObj, "PKCS8PRV"),
    jwk: KEYUTIL.getJWKFromKey(keyObj)
  };
}

Особенности совместимости

  • OpenSSL чаще использует PKCS#1
  • WebCrypto API работает с JWK и SPKI
  • JWT-библиотеки требуют JWK

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


Валидация после конвертации

После преобразования важно проверять ключ:

var keyObj = KEYUTIL.getKey(pem);
if (keyObj.isPrivate === true) {
  // корректный приватный ключ
}

Для RSA:

if (keyObj.n && keyObj.e) {
  // валидный ключ
}

Выводы по архитектуре Jsrsasign

  • единый объект keyObj используется как промежуточное представление
  • вся конвертация сводится к преобразованию в/из этого объекта
  • поддержка множества стандартов реализована через абстракцию ASN.1

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