Метод subtle.exportKey

Метод SubtleCrypto.exportKey() используется для экспорта криптографического ключа из внутреннего представления Web Crypto API в внешний формат, пригодный для хранения, передачи или последующего импорта через SubtleCrypto.importKey(). Экспорт возможен только для ключей, созданных или импортированных с флагом extractable: true.

Экспортируемый ключ преобразуется в один из стандартных форматов, поддерживаемых API: raw, pkcs8, spki, jwk. Выбор формата зависит от типа ключа и сценария использования.

Метод вызывается на объекте crypto.subtle:

const exportedKey = await crypto.subtle.exportKey(format, key);

Параметры:

  • format — строка, определяющая формат экспорта
  • key — объект CryptoKey, подлежащий экспорту

Возвращаемое значение:

  • Promise:

    • ArrayBuffer (для raw, pkcs8, spki)
    • JsonWebKey (для jwk)

Условие возможности экспорта

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

  • свойство extractable установлено в true
  • формат экспорта совместим с типом ключа
  • ключ поддерживает экспорт в выбранный формат

Попытка экспортировать неэкспортируемый ключ приводит к ошибке InvalidAccessError.


Форматы экспорта ключей

RAW

Используется для симметричных ключей (например, AES).

const keyData = await crypto.subtle.exportKey("raw", key);

Возвращает ArrayBuffer, содержащий «сырые» байты ключа.

Применяется для:

  • AES-CBC
  • AES-GCM
  • HMAC

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

  • не содержит метаданных
  • не подходит для асимметричных ключей

JWK (JSON Web Key)

Формат, представляющий ключ в виде JSON-объекта.

const jwk = await crypto.subtle.exportKey("jwk", key);

Результат:

{
  "kty": "RSA",
  "n": "...",
  "e": "...",
  "alg": "RS256",
  "ext": true,
  "key_ops": ["verify"]
}

Поддерживается для:

  • RSA
  • EC (Elliptic Curve)
  • HMAC
  • Octet key (симметричные ключи)

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

  • удобен для передачи через API
  • совместим с JWT-экосистемой
  • содержит метаданные ключа

PKCS#8

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

const pkcs8 = await crypto.subtle.exportKey("pkcs8", privateKey);

Возвращает ArrayBuffer в формате ASN.1 DER.

Поддерживается для:

  • RSA private keys
  • EC private keys

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

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

SPKI

Используется для экспорта публичных ключей.

const spki = await crypto.subtle.exportKey("spki", publicKey);

Возвращает ArrayBuffer в формате SubjectPublicKeyInfo (X.509).

Применяется для:

  • RSA public keys
  • EC public keys

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

  • стандартное представление публичных ключей
  • совместим с сертификатами X.509

Пример экспорта симметричного ключа AES

const key = await crypto.subtle.generateKey(
  {
    name: "AES-GCM",
    length: 256
  },
  true,
  ["encrypt", "decrypt"]
);

const rawKey = await crypto.subtle.exportKey("raw", key);

console.log(new Uint8Array(rawKey));

Пример экспорта RSA ключей в JWK

const keyPair = await crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([1, 0, 1]),
    hash: "SHA-256"
  },
  true,
  ["encrypt", "decrypt"]
);

const publicJwk = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
const privateJwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);

Пример экспорта приватного ключа в PKCS#8

const privateKeyPkcs8 = await crypto.subtle.exportKey(
  "pkcs8",
  keyPair.privateKey
);

const base64 = btoa(
  String.fromCharCode(...new Uint8Array(privateKeyPkcs8))
);

Пример экспорта публичного ключа в SPKI

const publicKeySpki = await crypto.subtle.exportKey(
  "spki",
  keyPair.publicKey
);

Особенности работы с extractable

Ключевой параметр при создании ключа:

crypto.subtle.generateKey(
  algorithm,
  extractable,
  keyUsages
);

Если extractable установлен в false, то:

  • exportKey() всегда выбрасывает исключение
  • ключ может использоваться только внутри Web Crypto API
  • повысается безопасность (ключ невозможно извлечь)

Типы ключей и поддерживаемые форматы

Тип ключа raw jwk spki pkcs8
AES
HMAC
RSA public
RSA private
EC public
EC private

Ошибки при использовании exportKey

InvalidAccessError

  • ключ неэкспортируемый (extractable: false)
  • неподдерживаемый формат

NotSupportedError

  • формат не совместим с типом ключа

DataError

  • повреждённый или некорректный ключ

Преобразование экспортированных данных

Часто экспортированные ключи требуют преобразования:

  • ArrayBuffer → Base64 (для хранения)
  • JWK → JSON.stringify
  • PKCS#8/SPKI → PEM формат

Пример преобразования в Base64:

function arrayBufferToBase64(buffer) {
  return btoa(String.fromCharCode(...new Uint8Array(buffer)));
}

Взаимосвязь exportKey и importKey

Экспортированные ключи почти всегда используются вместе с импортом:

const exported = await crypto.subtle.exportKey("jwk", key);

const imported = await crypto.subtle.importKey(
  "jwk",
  exported,
  algorithm,
  true,
  ["encrypt"]
);

Эта связка обеспечивает:

  • переносимость ключей между окружениями
  • сохранение ключей в хранилищах
  • передачу через API

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

  • сохранение симметричных ключей AES в IndexedDB
  • обмен публичными ключами между клиентами
  • экспорт приватных ключей для резервного копирования
  • интеграция с JWT-системами через JWK
  • миграция ключей между устройствами

Особенности безопасности

Экспорт ключей является критической операцией с точки зрения безопасности:

  • приватные ключи PKCS#8 требуют защищённого хранения
  • JWK может содержать чувствительные данные в открытом виде
  • экспортируемые ключи легко копируются и переносятся
  • рекомендуется ограничивать extractable: true только при необходимости