Signatur
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 mitexportKey()oderwrapKey()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
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);
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));
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);
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');
// Wichtig · Fallstricke
- Nur in sicheren Kontexten:
crypto.subtleund damitCryptoKeygibt es nur unter HTTPS oder auflocalhost. Auf reinen HTTP-Seiten istcrypto.subtleundefined. - Kein Konstruktor:
new CryptoKey()löst einenTypeErroraus. extractablemöglichst auffalsesetzen: 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: falseersetzt 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. usagessind endgültig: Nachträglich lassen sie sich nicht erweitern. Falsche Verwendungen führen zu einerInvalidAccessError-DOMException. Istusagesbei einem geheimen oder privaten Schlüssel leer, wird einSyntaxErrorausgelö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.cryptoab Version 19 bereit, davor überrequire('node:crypto').webcrypto. Ed25519 und X25519 werden erst in neueren Browser-Versionen unterstützt.