Signatur
Beschreibung
CryptoKeyPair ist ein einfaches Dictionary (kein Konstruktor, keine Klasse) der Web Crypto API. Es enthält zwei CryptoKey-Objekte: publicKey (öffentlicher Schlüssel) und privateKey (privater Schlüssel). Ein solches Objekt erhältst du als aufgelösten Wert von crypto.subtle.generateKey(), wenn du einen asymmetrischen Algorithmus wie RSA-OAEP, RSA-PSS, RSASSA-PKCS1-v1_5, ECDSA, ECDH, Ed25519 oder X25519 angibst.
Den öffentlichen Schlüssel darfst du weitergeben, zum Beispiel an einen Server oder Kommunikationspartner. Mit ihm werden Daten verschlüsselt (RSA-OAEP) oder Signaturen geprüft (ECDSA, RSA-PSS, Ed25519). Der private Schlüssel bleibt geheim und dient zum Entschlüsseln, Signieren oder zum Ableiten gemeinsamer Geheimnisse (ECDH/X25519).
Wofür welcher Schlüssel verwendet werden darf, bestimmt das keyUsages-Array, das du beim Erzeugen angibst. Die Web Crypto API verteilt es automatisch auf die passenden Schlüssel, z. B. "sign" auf den privaten und "verify" auf den öffentlichen Schlüssel. Der Parameter extractable gilt nur für den privaten Schlüssel. Der öffentliche Schlüssel ist immer exportierbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $publicKey Pflicht | CryptoKey | Öffentlicher Schlüssel (type === "public"). Ist immer exportierbar. Verwendungszwecke z. B. "encrypt", "verify", "wrapKey". |
|
| $privateKey Pflicht | CryptoKey | Privater Schlüssel (type === "private"). Verwendungszwecke z. B. "decrypt", "sign", "deriveKey", "deriveBits", "unwrapKey". Ob er exportierbar ist, bestimmt extractable. |
Rückgabewert
crypto.subtle.generateKey() bei asymmetrischen Algorithmen geliefert: Promise<CryptoKeyPair>.Beispiele
ECDSA-Schlüsselpaar erzeugen und Daten signieren
const keyPair = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' },
false, // privater Schlüssel nicht exportierbar
['sign', 'verify']
);
const daten = new TextEncoder().encode('Bestellung #4711');
const signatur = await crypto.subtle.sign(
{ name: 'ECDSA', hash: 'SHA-256' },
keyPair.privateKey,
daten
);
const gueltig = await crypto.subtle.verify(
{ name: 'ECDSA', hash: 'SHA-256' },
keyPair.publicKey,
signatur,
daten
);
console.log(keyPair.publicKey.type, keyPair.privateKey.type);
console.log(keyPair.privateKey.usages, keyPair.publicKey.usages);
console.log('Signatur gültig:', gueltig);
RSA-OAEP: Verschlüsseln mit publicKey, Entschlüsseln mit privateKey
const { publicKey, privateKey } = await crypto.subtle.generateKey(
{
name: 'RSA-OAEP',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]), // 65537
hash: 'SHA-256'
},
true,
['encrypt', 'decrypt']
);
const klartext = new TextEncoder().encode('Geheime Nachricht');
const chiffrat = await crypto.subtle.encrypt({ name: 'RSA-OAEP' }, publicKey, klartext);
const entschluesselt = await crypto.subtle.decrypt({ name: 'RSA-OAEP' }, privateKey, chiffrat);
console.log(new TextDecoder().decode(entschluesselt));
Öffentlichen Schlüssel als JWK exportieren (z. B. für den Server)
const keyPair = await crypto.subtle.generateKey(
{ name: 'ECDH', namedCurve: 'P-256' },
false,
['deriveKey', 'deriveBits']
);
// publicKey ist immer exportierbar, auch bei extractable = false
const jwk = await crypto.subtle.exportKey('jwk', keyPair.publicKey);
console.log(jwk.kty, jwk.crv);
// privateKey mit extractable = false lässt sich nicht exportieren
try {
await crypto.subtle.exportKey('jwk', keyPair.privateKey);
} catch (err) {
console.log(err.name);
}
Schlüsselpaar dauerhaft in IndexedDB ablegen
const oeffneDb = () => new Promise((resolve, reject) => {
const req = indexedDB.open('schluessel', 1);
req.onupgradeneeded = () => req.result.createObjectStore('paare');
req.onsuccess = () => resolve(req.result);
req.onerror = () => reject(req.error);
});
const keyPair = await crypto.subtle.generateKey(
{ name: 'ECDSA', namedCurve: 'P-256' },
false,
['sign', 'verify']
);
const db = await oeffneDb();
const tx = db.transaction('paare', 'readwrite');
// CryptoKey-Objekte sind strukturiert klonbar, also direkt speicherbar
tx.objectStore('paare').put(keyPair, 'geraet');
tx.oncomplete = () => console.log('Schlüsselpaar gespeichert');
// Wichtig · Fallstricke
- Kein Konstruktor:
new CryptoKeyPair()gibt es nicht. Das Dictionary entsteht nur durchcrypto.subtle.generateKey()mit einem asymmetrischen Algorithmus. Symmetrische Algorithmen wie AES oder HMAC liefern stattdessen einen einzelnenCryptoKey. - Nur Schlüsselerzeugung:
importKey()liefert immer einen einzelnenCryptoKey. Ein Paar importierst du mit zwei getrennten Aufrufen. extractablegilt nur für den privaten Schlüssel. Setze ihn auffalse, wenn der private Schlüssel das Gerät nie verlassen soll. In Kombination mit IndexedDB lässt sich das Paar trotzdem dauerhaft speichern, weilCryptoKeystrukturiert klonbar ist.- Falsche
keyUsages(z. B."encrypt"bei ECDSA) oder ein leeres Nutzungs-Array beim privaten Schlüssel führen zu einemSyntaxError. - Sicherer Kontext:
crypto.subtlesteht nur unter HTTPS oderlocalhostzur Verfügung, sonst ist esundefined. - Kompatibilität: RSA- und EC-Algorithmen funktionieren in allen modernen Browsern.
Ed25519undX25519sind erst seit Kurzem überall verfügbar (Chrome 137+, Firefox 129+/130+, Safari 17+). Prüfe vorher, ob sie unterstützt werden. In Node.js nutzt duglobalThis.crypto.subtle(ab 15 überrequire('node:crypto').webcrypto). - Leistung: Das Erzeugen von RSA-Schlüsseln mit 4096 Bit kann spürbar dauern. EC-Schlüssel sind deutlich schneller erzeugt und kürzer.