Экспорт ключей: exportSPKI, exportPKCS8, exportJWK

В криптографических сценариях WebCrypto API публичные ключи часто представляются в виде стандарта SPKI (Subject Public Key Info). Этот формат используется для сериализации публичных ключей в бинарное представление, совместимое с X.509 инфраструктурой.

В библиотеке jose экспорт SPKI выполняется через функцию exportSPKI.

Основная задача exportSPKI — преобразовать объект CryptoKey публичного ключа в строку PEM:

import { generateKeyPair, exportSPKI } from 'jose'

const { publicKey } = await generateKeyPair('RS256')

const spki = await exportSPKI(publicKey)

console.log(spki)

Результатом будет строка вида:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqh...
-----END PUBLIC KEY-----

Особенности SPKI экспорта

  • применяется только для публичных ключей
  • возвращает PEM-формат (Base64 с заголовками)
  • соответствует стандарту X.509
  • используется для передачи ключей между системами

SPKI особенно часто применяется в сценариях JWT-валидации, где публичный ключ передаётся в виде сертификата или конфигурационного файла.


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

Для приватных ключей используется стандарт PKCS8 (Private-Key Information Syntax Specification). Он описывает структуру хранения приватного ключа независимо от алгоритма.

В jose экспорт осуществляется функцией exportPKCS8.

import { generateKeyPair, exportPKCS8 } from 'jose'

const { privateKey } = await generateKeyPair('RS256')

const pkcs8 = await exportPKCS8(privateKey)

console.log(pkcs8)

Выходные данные:

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqh...
-----END PRIVATE KEY-----

Характеристики PKCS8

  • применяется исключительно для приватных ключей
  • универсальный формат (не зависит от алгоритма)
  • используется для хранения и переноса ключей
  • совместим с OpenSSL и большинством криптобиблиотек

PKCS8 часто используется при сохранении ключей в файлы или при передаче между backend-сервисами.


Экспорт ключа в JWK

Формат JWK (JSON Web Key) представляет ключ как JSON-структуру. Это основной формат в экосистеме JWT/JWS/JWE.

В jose экспорт выполняется функцией exportJWK.

import { generateKeyPair, exportJWK } from 'jose'

const { publicKey } = await generateKeyPair('ES256')

const jwk = await exportJWK(publicKey)

console.log(jwk)

Пример результата:

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

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

  • полностью текстовый JSON формат
  • удобен для API и конфигураций
  • используется в JWKS (JSON Web Key Set)
  • поддерживает как публичные, так и приватные ключи (в зависимости от экспорта)

Сравнение форматов экспорта

SPKI

  • формат: PEM (Base64)
  • только публичные ключи
  • ориентирован на X.509 инфраструктуру
  • удобен для TLS/сертификатов

PKCS8

  • формат: PEM (Base64)
  • только приватные ключи
  • универсальный стандарт хранения
  • совместим с OpenSSL

JWK

  • формат: JSON
  • поддерживает публичные и приватные ключи
  • используется в JWT экосистеме
  • удобен для REST API и JWKS endpoints

Типичные сценарии использования экспорта

Передача публичного ключа в сервис валидации JWT

import { exportSPKI } from 'jose'

const publicKeyPEM = await exportSPKI(publicKey)
// отправка в другой сервис

Сохранение приватного ключа в файл

import { exportPKCS8 } from 'jose'
import { writeFileSync } from 'node:fs'

const privateKeyPEM = await exportPKCS8(privateKey)

writeFileSync('private.pem', privateKeyPEM)

Публикация JWKS endpoint

import { exportJWK } from 'jose'

const jwk = await exportJWK(publicKey)

const jwks = {
  keys: [jwk]
}

console.log(JSON.stringify(jwks, null, 2))

Важные особенности работы с export-функциями

Асинхронная природа

Все операции экспорта возвращают Promise, поскольку используют WebCrypto API:

const key = await exportJWK(publicKey)

Тип ключа имеет значение

  • exportSPKI → только CryptoKey public
  • exportPKCS8 → только CryptoKey private
  • exportJWK → оба типа

Попытка передать неправильный тип приводит к ошибке выполнения.


Взаимосвязь экспорта и импорта ключей

Экспорт в jose часто используется вместе с импортом:

  • exportSPKI ↔︎ importSPKI
  • exportPKCS8 ↔︎ importPKCS8
  • exportJWK ↔︎ importJWK

Это позволяет строить полный цикл:

  1. генерация ключа
  2. экспорт в переносимый формат
  3. хранение или передача
  4. импорт обратно в CryptoKey

Практические нюансы сериализации

PEM vs JWK

PEM (SPKI/PKCS8) удобен для файловой системы и инфраструктуры.

JWK удобен для:

  • REST API
  • JWKS endpoints
  • динамической ротации ключей

Безопасность приватных ключей

При использовании exportPKCS8 или exportJWK для приватных ключей необходимо учитывать:

  • утечка строки равна компрометации ключа
  • хранение требует шифрования на уровне приложения или системы
  • не рекомендуется логировать результат экспорта

Алгоритмическая совместимость

Экспортируемый формат зависит от типа ключа:

  • RSA → SPKI / PKCS8 / JWK (kty: “RSA”)
  • EC → SPKI / PKCS8 / JWK (kty: “EC”)
  • OKP → JWK (например Ed25519)

Некоторые алгоритмы лучше работают с JWK (например EdDSA), поскольку PEM-эквиваленты ограничены.


Работа с JWKS и экспорт JWK

При построении системы аутентификации часто используется JWKS:

const jwk = await exportJWK(publicKey)

const jwks = {
  keys: [jwk]
}

Такой набор публикуется по endpoint:

/.well-known/jwks.json

Клиенты автоматически получают публичные ключи для проверки JWT.


Ошибки при экспорте

Частые проблемы при работе с функциями экспорта:

Неверный тип ключа

TypeError: Key is not extractable

Причина: ключ создан без флага extractable: true.

Несовместимый алгоритм

Некоторые ключи нельзя экспортировать в определённые форматы из-за ограничений WebCrypto.

Отсутствие прав на экспорт

Ключ создан как non-exportable:

crypto.subtle.generateKey(
  {
    name: "RSASSA-PKCS1-v1_5",
    modulusLength: 2048,
    hash: "SHA-256"
  },
  false, // <- extractable = false
  ["sign", "verify"]
)

Роль экспортируемых ключей в архитектуре JWT

Экспорт ключей в jose напрямую влияет на архитектуру систем:

  • SPKI → распространение публичных ключей между сервисами
  • PKCS8 → безопасное хранение приватных ключей
  • JWK → динамическое управление ключами через API

Эти три формата формируют основу совместимости между различными криптосистемами и сервисами идентификации.