Signatur
Beschreibung
AesGcmParams ist keine Klasse, sondern ein Wörterbuch (Dictionary) der Web Crypto API, also ein normales Objekt-Literal. Du übergibst es als algorithm-Argument an crypto.subtle.encrypt(), decrypt(), wrapKey() oder unwrapKey(), wenn du den Modus AES-GCM (Galois/Counter Mode) nutzt.
AES-GCM ist ein Verfahren für authentifizierte Verschlüsselung (AEAD). Die Daten werden verschlüsselt und bekommen zusätzlich einen Authentifizierungs-Tag. Wird der Geheimtext verändert, schlägt decrypt() mit einem OperationError fehl. Deshalb ist AES-GCM in der Web Crypto API meist die empfohlene Wahl für symmetrische Verschlüsselung.
Das Wichtigste ist der Initialisierungsvektor (iv). Er muss für jede Verschlüsselung mit demselben Schlüssel eindeutig sein. Geheim muss er nicht sein. Du speicherst oder überträgst ihn üblicherweise zusammen mit dem Geheimtext. Mit additionalData lassen sich unverschlüsselte Metadaten (z. B. Header oder Benutzer-IDs) an den Geheimtext binden. Sie werden mit authentifiziert, aber nicht verschlüsselt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $name Pflicht | string | Muss "AES-GCM" sein. |
|
| $iv Pflicht | ArrayBuffer|TypedArray|DataView (BufferSource) | Initialisierungsvektor. Empfohlen sind 12 Byte (96 Bit), z. B. aus crypto.getRandomValues(new Uint8Array(12)). Er darf mit demselben Schlüssel niemals wiederverwendet werden. Beim Entschlüsseln brauchst du exakt denselben IV. |
|
| $additionalData | ArrayBuffer|TypedArray|DataView (BufferSource) | leer | Optionale Zusatzdaten (AAD). Sie werden authentifiziert, aber nicht verschlüsselt. Beim Entschlüsseln müssen sie byte-genau gleich übergeben werden, sonst schlägt die Prüfung fehl. |
| $tagLength | number | 128 | Länge des Authentifizierungs-Tags in Bit. Erlaubt sind 32, 64, 96, 104, 112, 120 und 128. Empfohlen ist 128. Beim Ver- und Entschlüsseln muss derselbe Wert gelten. |
Rückgabewert
encrypt() liefert mit diesem Objekt ein Promise<ArrayBuffer>: den Geheimtext, an dessen Ende der Tag angehängt ist.Beispiele
Text verschlüsseln und wieder entschlüsseln
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12)); // pro Nachricht neu!
const plaintext = new TextEncoder().encode('Geheime Nachricht');
/** @type {AesGcmParams} */
const params = { name: 'AES-GCM', iv };
const ciphertext = await crypto.subtle.encrypt(params, key, plaintext);
console.log('Länge Geheimtext:', ciphertext.byteLength); // 17 + 16 Byte Tag
const decrypted = await crypto.subtle.decrypt(params, key, ciphertext);
console.log(new TextDecoder().decode(decrypted));
Metadaten mit additionalData binden
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 128 }, false, ['encrypt', 'decrypt']
);
const enc = new TextEncoder();
const iv = crypto.getRandomValues(new Uint8Array(12));
const aad = enc.encode('user-id=42');
const ct = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv, additionalData: aad, tagLength: 128 },
key,
enc.encode('Kontostand: 1000 €')
);
try {
// Falsche Zusatzdaten: Die Authentifizierung schlägt fehl
await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv, additionalData: enc.encode('user-id=43') },
key,
ct
);
} catch (err) {
console.log(err.name);
}
IV zusammen mit dem Geheimtext speichern (Base64)
const toB64 = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)));
const fromB64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
const encryptString = async (key, text) => {
const iv = crypto.getRandomValues(new Uint8Array(12));
const ct = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv }, key, new TextEncoder().encode(text)
);
const out = new Uint8Array(iv.length + ct.byteLength);
out.set(iv);
out.set(new Uint8Array(ct), iv.length);
return toB64(out);
};
const decryptString = async (key, b64) => {
const data = fromB64(b64);
const iv = data.slice(0, 12);
const pt = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv }, key, data.slice(12)
);
return new TextDecoder().decode(pt);
};
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt']
);
const token = await encryptString(key, 'Hallo Welt');
console.log(await decryptString(key, token));
// Wichtig · Fallstricke
- IV niemals wiederverwenden: Wenn derselbe Schlüssel zweimal mit demselben IV verwendet wird, bricht die Sicherheit von GCM komplett zusammen. Angreifer können dann Klartexte per XOR vergleichen und Tags fälschen. Nimm pro Nachricht einen neuen Zufalls-IV mit 12 Byte oder einen streng monoton steigenden Zähler. Bei Zufalls-IVs solltest du den Schlüssel nach etwa 232 Nachrichten wechseln.
- Tag im Geheimtext: Die Web Crypto API hängt den Tag an das Ende des
ArrayBufferan. Andere Bibliotheken wie Node.jscrypto.createCipherivgeben den Tag dagegen getrennt aus. Das musst du bei der Zusammenarbeit beachten. - Kurze Tags (unter 96 Bit) schwächen die Integritätsprüfung deutlich. Verwende sie nur, wenn du genau weißt, warum.
- Ein Fehler beim Entschlüsseln (falscher Schlüssel, IV, AAD, Tag oder manipulierte Daten) führt immer zu einem allgemeinen
OperationError. Genauere Angaben gibt es absichtlich nicht. crypto.subtlesteht nur in sicheren Kontexten (HTTPS, localhost) zur Verfügung. Von den modernen Browsern unterstützen es alle. In Node.js ist es überglobalThis.crypto.subtleerreichbar (global ab Version 19).- Die maximale Klartextlänge liegt bei etwa 239−256 Bit pro Aufruf. Sehr große Dateien solltest du in Blöcke aufteilen, jeweils mit eigenem IV.