Start · Sprachen · JavaScript · Referenz · SubtleCrypto.exportKey()

SubtleCrypto.exportKey()

Methode

Exportiert ein <code>CryptoKey</code>-Objekt in ein externes, portables Format (<code>raw</code>, <code>pkcs8</code>, <code>spki</code> oder <code>jwk</code>) und liefert ein Promise.

seit JavaScript Baseline: alle modernen Browser (Web Crypto API), Kategorie: webapi

Signatur

SubtleCrypto.prototype.exportKey(format, key)

Beschreibung

exportKey() wandelt einen Schlüssel, der als undurchsichtiges CryptoKey-Objekt vorliegt, in eine speicher- oder übertragbare Form um. So lassen sich Schlüssel an einen Server senden, in localStorage bzw. IndexedDB ablegen, als PEM-Datei weitergeben oder mit anderen Systemen (z. B. OpenSSL, Node.js, JOSE-Bibliotheken) austauschen. Das Gegenstück ist SubtleCrypto.importKey().

Unterstützt werden vier Formate:

  • "raw" – rohe Schlüsselbytes; für symmetrische Schlüssel (AES, HMAC) sowie öffentliche Schlüssel von ECDSA/ECDH/Ed25519/X25519.
  • "pkcs8" – DER-kodierter privater Schlüssel (RSA, EC, Ed25519, X25519).
  • "spki" – DER-kodierter öffentlicher Schlüssel (SubjectPublicKeyInfo).
  • "jwk" – JSON Web Key als JavaScript-Objekt; für fast alle Schlüsseltypen.

Ein Schlüssel kann nur exportiert werden, wenn seine Eigenschaft extractable auf true steht. Diese wird beim Erzeugen (generateKey()) oder Importieren (importKey()) festgelegt. Öffentliche Schlüssel eines Schlüsselpaars sind immer exportierbar, unabhängig vom übergebenen Wert.

Für das verschlüsselte Exportieren (Key Wrapping) gibt es SubtleCrypto.wrapKey(), das intern exportiert und das Ergebnis mit einem weiteren Schlüssel verschlüsselt.

Parameter

Name Typ Default Beschreibung
$format Pflicht "raw" | "pkcs8" | "spki" | "jwk" Zielformat des Exports. Muss zum Schlüsseltyp passen (z. B. "pkcs8" nur für private, "spki" nur für öffentliche Schlüssel).
$key Pflicht CryptoKey Der zu exportierende Schlüssel. Muss extractable: true besitzen (außer bei öffentlichen Schlüsseln).

Rückgabewert

Typ
Promise<ArrayBuffer | JsonWebKey>
Beschreibung
Ein Promise, das bei "jwk" mit einem JsonWebKey-Objekt und bei allen anderen Formaten mit einem ArrayBuffer erfüllt wird. Es wird mit InvalidAccessError abgelehnt, wenn der Schlüssel nicht exportierbar ist, und mit NotSupported bzw. NotSupportedError, wenn das Format nicht zum Schlüssel passt.

Beispiele

AES-Schlüssel im Rohformat exportieren

const key = await crypto.subtle.generateKey(
  { name: "AES-GCM", length: 256 },
  true, // extractable – sonst schlägt exportKey fehl
  ["encrypt", "decrypt"]
);

const raw = await crypto.subtle.exportKey("raw", key);
const bytes = new Uint8Array(raw);

// Als Hex-String darstellen
const hex = [...bytes].map(b => b.toString(16).padStart(2, "0")).join("");
console.log(bytes.length, hex.length);
32 64

Öffentlichen RSA-Schlüssel als PEM (SPKI) exportieren

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

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

// ArrayBuffer -> Base64 -> PEM
const base64 = btoa(String.fromCharCode(...new Uint8Array(spki)));
const pem = [
  "-----BEGIN PUBLIC KEY-----",
  ...base64.match(/.{1,64}/g),
  "-----END PUBLIC KEY-----"
].join("\n");

console.log(pem.split("\n")[0]);
-----BEGIN PUBLIC KEY-----

ECDSA-Schlüssel als JWK exportieren und an den Server senden

const { publicKey, privateKey } = await crypto.subtle.generateKey(
  { name: "ECDSA", namedCurve: "P-256" },
  true,
  ["sign", "verify"]
);

const jwk = await crypto.subtle.exportKey("jwk", publicKey);
console.log(jwk.kty, jwk.crv, Object.keys(jwk).sort().join(","));

// Nur den öffentlichen Schlüssel übertragen!
await fetch("/api/keys", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(jwk)
});
EC P-256 crv,ext,key_ops,kty,x,y

Fehler bei nicht exportierbarem Schlüssel abfangen

const key = await crypto.subtle.generateKey(
  { name: "HMAC", hash: "SHA-256" },
  false, // nicht exportierbar
  ["sign", "verify"]
);

try {
  await crypto.subtle.exportKey("raw", key);
} catch (err) {
  console.log(err.name);
}
InvalidAccessError

// Wichtig · Fallstricke

  • Sicherer Kontext: crypto.subtle gibt es nur in sicheren Kontexten (HTTPS oder localhost); sonst ist es undefined.
  • Sicherheit: Setze extractable nur dann auf true, wenn du wirklich exportieren musst. Nicht exportierbare Schlüssel lassen sich trotzdem in IndexedDB speichern (per Structured Clone), und ein XSS-Angreifer kann das Schlüsselmaterial dann nicht auslesen. Private Schlüssel im Klartext niemals in localStorage ablegen oder unverschlüsselt übertragen – nutze dafür wrapKey().
  • Formatwahl: "pkcs8" auf einen öffentlichen oder "spki" auf einen privaten Schlüssel führt zu einem InvalidAccessError. "raw" funktioniert nicht für RSA-Schlüssel und nicht für private EC-Schlüssel.
  • PEM: Die API liefert DER-Binärdaten, kein PEM. Kopf-/Fußzeilen und Base64-Kodierung musst du selbst hinzufügen. String.fromCharCode(...bytes) kann bei sehr großen Puffern den Aufrufstapel sprengen – dann blockweise umwandeln.
  • JWK: Das Ergebnis enthält Felder wie ext und key_ops, die bei einem späteren importKey() berücksichtigt werden. Ein privater JWK enthält immer auch die öffentlichen Anteile.
  • Kompatibilität: Wird in allen modernen Browsern unterstützt. Ed25519/X25519 sind erst in neueren Browserversionen verfügbar. In Node.js steht die Methode über globalThis.crypto.subtle (ab Node 19 global) bzw. require("node:crypto").webcrypto.subtle bereit.