Signatur
Beschreibung
Die Methode decrypt() der Schnittstelle SubtleCrypto ist das Gegenstück zu encrypt(). Sie nimmt verschlüsselte Binärdaten, einen passenden Schlüssel und dieselben Algorithmus-Parameter, die beim Verschlüsseln verwendet wurden, und gibt ein Promise zurück, das mit dem entschlüsselten Klartext als ArrayBuffer erfüllt wird.
Unterstützt werden diese Algorithmen:
- RSA-OAEP: asymmetrisch, entschlüsselt wird mit dem privaten Schlüssel (
{ name: "RSA-OAEP", label? }). - AES-GCM: authentifizierte Verschlüsselung, braucht dieselbe
ivund optional dieselbenadditionalDataund dieselbetagLength. Das wird in den meisten Fällen empfohlen. - AES-CBC: braucht dieselbe 16-Byte-
iv. - AES-CTR: braucht denselben
counterund dieselbelength.
Der Schlüssel muss mit der Verwendung "decrypt" in keyUsages erzeugt oder importiert worden sein, und sein Algorithmus muss zu algorithm.name passen. Das Ergebnis ist immer ein ArrayBuffer. Text gewinnst du daraus typischerweise mit TextDecoder zurück.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $algorithm Pflicht | RsaOaepParams | AesGcmParams | AesCbcParams | AesCtrParams | Objekt mit name und den algorithmusspezifischen Parametern, z. B. { name: "AES-GCM", iv }. Die Werte müssen identisch mit denen beim Verschlüsseln sein. |
|
| $key Pflicht | CryptoKey | Schlüssel zum Entschlüsseln. Bei RSA-OAEP der private Schlüssel, bei AES der geheime Schlüssel. Er muss "decrypt" in usages enthalten. |
|
| $data Pflicht | ArrayBuffer | TypedArray | DataView | Die verschlüsselten Daten (Chiffretext). Bei AES-GCM hängt das Authentifizierungs-Tag am Ende. |
Rückgabewert
ArrayBuffer erfüllt wird. Es wird mit InvalidAccessError abgelehnt, wenn der Schlüssel nicht passt oder nicht zum Entschlüsseln freigegeben ist, und mit OperationError, wenn die Daten beschädigt sind, das GCM-Tag nicht stimmt oder Parameter wie die IV falsch sind.Beispiele
Text mit AES-GCM verschlüsseln und wieder entschlüsseln
const { subtle } = globalThis.crypto;
const key = await subtle.generateKey(
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"]
);
// Für jede Verschlüsselung eine neue, zufällige 12-Byte-IV erzeugen
const iv = crypto.getRandomValues(new Uint8Array(12));
const plaintext = new TextEncoder().encode("Geheime Nachricht");
const ciphertext = await subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext);
// Entschlüsseln – mit derselben IV
const decrypted = await subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext);
console.log(new TextDecoder().decode(decrypted));
Manipulierte Daten erkennen (AES-GCM)
const key = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 128 }, false, ["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const ct = new Uint8Array(
await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, new TextEncoder().encode("Betrag: 100 €"))
);
ct[0] ^= 0xff; // ein Byte verfälschen
try {
await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ct);
} catch (err) {
console.log(err.name); // Integritätsprüfung schlägt fehl
}
RSA-OAEP: mit öffentlichem Schlüssel verschlüsseln, mit privatem entschlüsseln
const { publicKey, privateKey } = await crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"
},
false,
["encrypt", "decrypt"]
);
const data = new TextEncoder().encode("Sitzungs-Token 42");
const encrypted = await crypto.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, data);
const decrypted = await crypto.subtle.decrypt({ name: "RSA-OAEP" }, privateKey, encrypted);
console.log(new TextDecoder().decode(decrypted));
Gespeicherte Base64-Daten (IV + Chiffretext) entschlüsseln
const fromBase64 = (b64) => Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
// Format: die ersten 12 Byte sind die IV, danach folgt der Chiffretext mit Tag
async function decryptPayload(b64, key) {
const bytes = fromBase64(b64);
const iv = bytes.slice(0, 12);
const ciphertext = bytes.slice(12);
const buf = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ciphertext);
return JSON.parse(new TextDecoder().decode(buf));
}
// Verwendung: const obj = await decryptPayload(localStorage.getItem("daten"), key);
// Wichtig · Fallstricke
- Nur in sicheren Kontexten:
crypto.subtlegibt es nur über HTTPS oderlocalhost. Auf unsicheren Seiten ist esundefined. In Node.js steht es ab Version 15 alsglobalThis.crypto.subtlebzw. überrequire(\"node:crypto\").webcryptozur Verfügung. - Parameter müssen exakt übereinstimmen: IV, Counter,
additionalData,tagLengthund bei RSA-OAEPlabelund Hash müssen dieselben sein wie beim Verschlüsseln. Sonst folgt einOperationErrorohne weitere Details. - Die IV ist nicht geheim, muss aber gespeichert werden: Üblich ist, sie dem Chiffretext voranzustellen. Eine IV darf bei AES-GCM mit demselben Schlüssel nie wiederverwendet werden.
- AES-CBC und AES-CTR prüfen die Integrität nicht: Manipulierte Daten können unbemerkt zu falschem Klartext werden. Setze AES-GCM ein oder ergänze einen HMAC.
- Fehlermeldungen verraten absichtlich wenig. Gib sie nicht ungefiltert an Nutzer weiter, damit keine Padding-Oracle-Angriffe möglich werden (relevant bei CBC).
- RSA-OAEP taugt nur für kleine Datenmengen. Die Grenze liegt bei etwa Schlüssellänge minus Hash-Overhead, bei 2048 Bit mit SHA-256 also rund 190 Byte. Für größere Daten nimmst du hybride Verschlüsselung: AES-Schlüssel mit RSA verpacken (
wrapKey/unwrapKey). - Rückgabewert ist ein
ArrayBuffer, kein String. Du brauchstTextDecoderfür die Umwandlung.