Signatur
Beschreibung
AesCbcParams ist kein Konstruktor, sondern ein Wörterbuch (Dictionary) der Web Crypto API: ein gewöhnliches Objekt mit den Feldern name und iv. Du übergibst es als algorithm-Argument, wenn du mit einem AES-Schlüssel im Modus Cipher Block Chaining (CBC) Daten verschlüsseln, entschlüsseln oder Schlüssel ein- bzw. auspacken willst.
Im CBC-Modus wird jeder 16-Byte-Klartextblock vor der Verschlüsselung mit dem vorherigen Chiffratblock per XOR verknüpft. Für den ersten Block wird dafür der Initialisierungsvektor (iv) verwendet. Er muss genau 16 Byte lang und unvorhersehbar sein, also mit crypto.getRandomValues() erzeugt werden. Geheim ist er nicht: Normalerweise wird er zusammen mit dem Chiffrat gespeichert oder übertragen, weil er zum Entschlüsseln exakt wieder gebraucht wird.
Die Web Crypto API füllt den Klartext automatisch nach PKCS#7 auf (Padding). Deshalb ist das Chiffrat immer ein Vielfaches von 16 Byte und mindestens einen Block größer als bei Eingaben, die schon ein Vielfaches von 16 sind. Da AES-CBC keine Authentifizierung bietet, solltest du für neue Anwendungen normalerweise AesGcmParams (AES-GCM) bevorzugen. AES-CBC ist vor allem für die Kompatibilität mit bestehenden Systemen sinnvoll.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $name Pflicht | string | Name des Algorithmus. Muss "AES-CBC" sein (Groß-/Kleinschreibung wird nicht beachtet). |
|
| $iv Pflicht | ArrayBuffer | TypedArray | DataView | Initialisierungsvektor, genau 16 Byte. Muss unvorhersehbar sein, erzeuge ihn also z. B. mit crypto.getRandomValues(new Uint8Array(16)). Beim Entschlüsseln muss derselbe IV wie beim Verschlüsseln übergeben werden. |
Beispiele
Text mit AES-CBC verschlüsseln und wieder entschlüsseln
const key = await crypto.subtle.generateKey(
{ name: 'AES-CBC', length: 256 },
true,
['encrypt', 'decrypt']
);
// AesCbcParams: frischer, zufälliger IV für jede Verschlüsselung
const iv = crypto.getRandomValues(new Uint8Array(16));
const params = { name: 'AES-CBC', iv };
const plaintext = new TextEncoder().encode('Geheime Nachricht');
const ciphertext = await crypto.subtle.encrypt(params, key, plaintext);
console.log('Chiffrat-Länge:', ciphertext.byteLength);
const decrypted = await crypto.subtle.decrypt(params, key, ciphertext);
console.log(new TextDecoder().decode(decrypted));
IV zusammen mit dem Chiffrat speichern
const encryptPacked = async (key, text) => {
const iv = crypto.getRandomValues(new Uint8Array(16));
const data = new TextEncoder().encode(text);
const ct = new Uint8Array(
await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, key, data)
);
// Format: [16 Byte IV][Chiffrat]
const packed = new Uint8Array(iv.length + ct.length);
packed.set(iv);
packed.set(ct, iv.length);
return packed;
};
const decryptPacked = async (key, packed) => {
const iv = packed.slice(0, 16);
const ct = packed.slice(16);
const pt = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, key, ct);
return new TextDecoder().decode(pt);
};
const key = await crypto.subtle.generateKey(
{ name: 'AES-CBC', length: 128 }, false, ['encrypt', 'decrypt']
);
const blob = await encryptPacked(key, 'Hallo Welt');
console.log(blob.length, await decryptPacked(key, blob));
Schlüssel mit AES-CBC ein- und auspacken (wrapKey/unwrapKey)
const wrappingKey = await crypto.subtle.generateKey(
{ name: 'AES-CBC', length: 256 }, false, ['wrapKey', 'unwrapKey']
);
const hmacKey = await crypto.subtle.generateKey(
{ name: 'HMAC', hash: 'SHA-256' }, true, ['sign', 'verify']
);
const iv = crypto.getRandomValues(new Uint8Array(16));
const wrapped = await crypto.subtle.wrapKey(
'raw', hmacKey, wrappingKey, { name: 'AES-CBC', iv }
);
const restored = await crypto.subtle.unwrapKey(
'raw', wrapped, wrappingKey, { name: 'AES-CBC', iv },
{ name: 'HMAC', hash: 'SHA-256' }, true, ['sign', 'verify']
);
console.log(restored.algorithm.name);
// Wichtig · Fallstricke
- Keine Integritätsprüfung: AES-CBC erkennt manipulierte Chiffrate nicht und ist ohne zusätzlichen MAC anfällig für Padding-Oracle-Angriffe. Kombiniere es mit HMAC (Encrypt-then-MAC) oder nimm besser AES-GCM (
AesGcmParams). - IV-Länge: Ein IV, der nicht genau 16 Byte lang ist, führt zu einem
OperationError. - IV nie wiederverwenden: Für jede Verschlüsselung brauchst du einen neuen, zufälligen IV. Ein vorhersehbarer IV (z. B. ein Zähler) macht CBC angreifbar.
- Scheitert das Entschlüsseln (falscher Schlüssel, falscher IV, beschädigte Daten), wird das Promise meist mit einem nicht näher beschriebenen
OperationErrorabgelehnt, weil das Padding ungültig ist. crypto.subtlegibt es nur in sicheren Kontexten (HTTPS oder localhost). In Node.js steht es ab Version 15 überglobalThis.crypto.subtlebzw.require('node:crypto').webcryptozur Verfügung.- Das Padding (PKCS#7) wird automatisch hinzugefügt und entfernt. Füge es nicht zusätzlich selbst hinzu.