Start · Sprachen · JavaScript · Referenz · CryptoKey

CryptoKey

Schnittstelle

Stellt einen kryptografischen Schlüssel der Web Crypto API dar, der über <code>SubtleCrypto</code>-Methoden wie <code>generateKey()</code> oder <code>importKey()</code> erzeugt wird.

seit JavaScript Baseline: alle modernen Browser, Node.js 15+ (glob Kategorie: webapi

Signatur

interface CryptoKey

Beschreibung

CryptoKey ist das zentrale Objekt der Web Crypto API für Schlüssel. Man erzeugt es nie direkt mit einem Konstruktor. Man bekommt es immer von einer der SubtleCrypto-Methoden generateKey(), deriveKey(), importKey() oder unwrapKey(). Das eigentliche Schlüsselmaterial bleibt dabei in der Krypto-Implementierung des Browsers und ist für JavaScript nicht direkt lesbar.

Ein CryptoKey hat vier schreibgeschützte Eigenschaften:

  • type: "secret" (symmetrisch, z. B. AES und HMAC), "private" oder "public" (Teil eines asymmetrischen Schlüsselpaars).
  • extractable: Gibt an, ob der Schlüssel mit exportKey() oder wrapKey() exportiert werden darf.
  • algorithm: Ein Objekt mit dem Algorithmus und seinen Parametern, z. B. { name: "AES-GCM", length: 256 }.
  • usages: Ein Array der erlaubten Verwendungen, z. B. ["encrypt", "decrypt"], ["sign", "verify"], ["deriveKey", "deriveBits"] oder ["wrapKey", "unwrapKey"].

Asymmetrische Algorithmen wie RSA-OAEP, ECDSA, ECDH oder Ed25519 liefern ein CryptoKeyPair mit publicKey und privateKey. Beides sind CryptoKey-Objekte. Jede Operation prüft den Schlüssel: Passen Algorithmus oder usages nicht zur Operation, wird das Promise mit einer InvalidAccessError-DOMException abgelehnt.

CryptoKey-Objekte lassen sich per Structured Clone übertragen. Man kann sie also mit postMessage() an Worker schicken oder direkt in IndexedDB speichern. Das gilt auch für Schlüssel mit extractable: false. Deshalb eignen sie sich gut, um Schlüssel dauerhaft im Browser zu halten, ohne dass das Rohmaterial für Skripte erreichbar ist.

Parameter

Name Typ Default Beschreibung
$type "secret" | "private" | "public" Schreibgeschützt. Art des Schlüssels: symmetrisch (secret) oder Teil eines Schlüsselpaars.
$extractable boolean Schreibgeschützt. true, wenn der Schlüssel mit exportKey() oder wrapKey() exportiert werden darf. Wird beim Erzeugen oder Importieren festgelegt.
$algorithm KeyAlgorithm | AesKeyAlgorithm | HmacKeyAlgorithm | RsaHashedKeyAlgorithm | EcKeyAlgorithm Schreibgeschützt. Objekt mit name und algorithmusspezifischen Feldern wie length, hash, namedCurve oder modulusLength.
$usages Array<"encrypt" | "decrypt" | "sign" | "verify" | "deriveKey" | "deriveBits" | "wrapKey" | "unwrapKey"> Schreibgeschützt. Liste der Operationen, für die der Schlüssel verwendet werden darf.

Rückgabewert

Typ
CryptoKey
Beschreibung
Es gibt keinen öffentlichen Konstruktor. Instanzen werden als Promise<CryptoKey> oder Promise<CryptoKeyPair> von den SubtleCrypto-Methoden zurückgegeben.

Beispiele

AES-GCM-Schlüssel erzeugen und Eigenschaften prüfen

const key = await crypto.subtle.generateKey(
  { name: 'AES-GCM', length: 256 },
  false,                    // nicht exportierbar
  ['encrypt', 'decrypt']
);

console.log(key instanceof CryptoKey);
console.log(key.type, key.extractable);
console.log(key.algorithm);
console.log(key.usages);
true secret false { name: 'AES-GCM', length: 256 } ['encrypt', 'decrypt']

Text mit dem Schlüssel ver- und entschlüsseln

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

const iv = crypto.getRandomValues(new Uint8Array(12)); // pro Nachricht neu!
const data = new TextEncoder().encode('Geheime Notiz');

const cipher = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data);
const plain = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, cipher);

console.log(new TextDecoder().decode(plain));
Geheime Notiz

Schlüsselpaar zum Signieren und öffentlichen Schlüssel exportieren

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

console.log(publicKey.type, publicKey.usages);   // public ['verify']
console.log(privateKey.type, privateKey.usages); // private ['sign']

const msg = new TextEncoder().encode('Bestellung #4711');
const algo = { name: 'ECDSA', hash: 'SHA-256' };
const sig = await crypto.subtle.sign(algo, privateKey, msg);
const ok = await crypto.subtle.verify(algo, publicKey, sig, msg);
console.log('Signatur gültig:', ok);

const jwk = await crypto.subtle.exportKey('jwk', publicKey);
console.log(jwk.kty, jwk.crv);
public ['verify'] private ['sign'] Signatur gültig: true EC P-256

Nicht exportierbaren Schlüssel in IndexedDB speichern

const openDb = () => new Promise((resolve, reject) => {
  const req = indexedDB.open('keystore', 1);
  req.onupgradeneeded = () => req.result.createObjectStore('keys');
  req.onsuccess = () => resolve(req.result);
  req.onerror = () => reject(req.error);
});

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

const db = await openDb();
const tx = db.transaction('keys', 'readwrite');
tx.objectStore('keys').put(key, 'main'); // Structured Clone des CryptoKey
tx.oncomplete = () => console.log('Schlüssel gespeichert');
Schlüssel gespeichert

// Wichtig · Fallstricke

  • Nur in sicheren Kontexten: crypto.subtle und damit CryptoKey gibt es nur unter HTTPS oder auf localhost. Auf reinen HTTP-Seiten ist crypto.subtle undefined.
  • Kein Konstruktor: new CryptoKey() löst einen TypeError aus.
  • extractable möglichst auf false setzen: So kann auch schadhaftes Skript (z. B. nach einer XSS-Lücke) das Rohmaterial nicht auslesen. Benutzen kann ein solches Skript den Schlüssel trotzdem, solange es auf der Seite läuft. extractable: false ersetzt also keinen XSS-Schutz.
  • Private Schlüssel nie exportierbar weitergeben: Bei Schlüsselpaaren ist der öffentliche Schlüssel immer exportierbar. Der extractable-Parameter gilt nur für den privaten Schlüssel.
  • usages sind endgültig: Nachträglich lassen sie sich nicht erweitern. Falsche Verwendungen führen zu einer InvalidAccessError-DOMException. Ist usages bei einem geheimen oder privaten Schlüssel leer, wird ein SyntaxError ausgelöst.
  • IV bei AES-GCM: Mit demselben Schlüssel darf ein IV nie zweimal verwendet werden. Wiederholte IVs zerstören die Sicherheit.
  • Kompatibilität: Alle aktuellen Browser unterstützen die API. In Node.js steht sie über globalThis.crypto ab Version 19 bereit, davor über require('node:crypto').webcrypto. Ed25519 und X25519 werden erst in neueren Browser-Versionen unterstützt.