Start · Sprachen · JavaScript · Referenz · SubtleCrypto

SubtleCrypto

Schnittstelle

Die <code>SubtleCrypto</code>-Schnittstelle der Web Crypto API stellt niedrigstufige kryptografische Funktionen wie Hashing, Signieren, Verschlüsseln und Schlüsselverwaltung bereit.

seit JavaScript Baseline: alle modernen Browser (seit 2015), Node. Kategorie: webapi

Signatur

interface SubtleCrypto

Beschreibung

SubtleCrypto ist der Kern der Web Crypto API. Man kann die Schnittstelle nicht selbst instanziieren. Stattdessen greift man über crypto.subtle auf eine vorhandene Instanz zu, im Browser über window.crypto.subtle bzw. in Workern über self.crypto.subtle. Die Operationen laufen nativ und sind damit deutlich schneller und sicherer als Kryptografie-Bibliotheken in reinem JavaScript.

Alle Methoden arbeiten asynchron und geben ein Promise zurück. Die wichtigsten Methoden sind:

  • Hashing: digest() (SHA-1, SHA-256, SHA-384, SHA-512)
  • Verschlüsselung: encrypt() und decrypt() (AES-GCM, AES-CBC, AES-CTR, RSA-OAEP)
  • Signaturen: sign() und verify() (HMAC, ECDSA, RSA-PSS, RSASSA-PKCS1-v1_5, Ed25519)
  • Schlüsselverwaltung: generateKey(), importKey(), exportKey(), deriveKey(), deriveBits() (PBKDF2, HKDF, ECDH, X25519)
  • Schlüssel verpacken: wrapKey() und unwrapKey()

Schlüssel werden als CryptoKey-Objekte übergeben. Deren Eigenschaft extractable legt fest, ob sich der Schlüssel exportieren lässt. usages legt fest, wofür er verwendet werden darf. Daten werden immer als ArrayBuffer, TypedArray oder DataView übergeben. Texte wandelt man vorher mit TextEncoder um.

Der Name „subtle“ ist eine bewusste Warnung: Die API ist mächtig, lässt sich aber leicht falsch bedienen. Typische Fehler sind ein wiederverwendeter Initialisierungsvektor (IV), veraltete Algorithmen oder zu wenige PBKDF2-Iterationen. Wer eigene Protokolle entwirft, sollte das nur mit fundiertem Kryptografie-Wissen tun.

Rückgabewert

Typ
SubtleCrypto
Beschreibung
Man erhält die Instanz über crypto.subtle. Alle Methoden geben ein Promise zurück, das je nach Methode mit einem ArrayBuffer, CryptoKey, CryptoKeyPair, boolean oder JsonWebKey erfüllt wird.

Beispiele

SHA-256-Hash eines Textes als Hex-String

const sha256 = async (text) => {
  const data = new TextEncoder().encode(text);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  return [...new Uint8Array(hashBuffer)]
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
};

console.log(await sha256('hallo'));
d3751d33f9cd5049c4af2b462735457e4d3baf130bcbb87f389e349fbaeb20b9

Daten mit AES-GCM ver- und entschlüsseln

const key = await crypto.subtle.generateKey(
  { name: 'AES-GCM', length: 256 },
  true, // exportierbar
  ['encrypt', 'decrypt']
);

// Für jede Verschlüsselung einen neuen, zufälligen IV verwenden!
const iv = crypto.getRandomValues(new Uint8Array(12));
const klartext = new TextEncoder().encode('Geheime Nachricht');

const chiffrat = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, klartext);
const entschluesselt = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, chiffrat);

console.log(new TextDecoder().decode(entschluesselt));
Geheime Nachricht

HMAC-Signatur erstellen und prüfen (z. B. für Webhooks)

const enc = new TextEncoder();
const key = await crypto.subtle.importKey(
  'raw',
  enc.encode('mein-geheimer-schluessel'),
  { name: 'HMAC', hash: 'SHA-256' },
  false,
  ['sign', 'verify']
);

const payload = enc.encode(JSON.stringify({ id: 42, status: 'paid' }));
const signatur = await crypto.subtle.sign('HMAC', key, payload);
const gueltig = await crypto.subtle.verify('HMAC', key, signatur, payload);

console.log('Signatur gültig:', gueltig);
Signatur gültig: true

Schlüssel aus einem Passwort ableiten (PBKDF2 → AES-GCM)

const passwortZuSchluessel = async (passwort, salt) => {
  const basis = await crypto.subtle.importKey(
    'raw',
    new TextEncoder().encode(passwort),
    'PBKDF2',
    false,
    ['deriveKey']
  );
  return crypto.subtle.deriveKey(
    { name: 'PBKDF2', salt, iterations: 600_000, hash: 'SHA-256' },
    basis,
    { name: 'AES-GCM', length: 256 },
    false,
    ['encrypt', 'decrypt']
  );
};

const salt = crypto.getRandomValues(new Uint8Array(16));
const key = await passwortZuSchluessel('Correct-Horse-Battery', salt);
console.log(key.algorithm, key.usages);
{ name: 'AES-GCM', length: 256 } [ 'encrypt', 'decrypt' ]

// Wichtig · Fallstricke

  • Nur im sicheren Kontext: crypto.subtle gibt es nur unter HTTPS oder localhost. Unter reinem HTTP ist der Wert undefined. Das ist eine häufige Ursache für den Fehler „Cannot read properties of undefined“.
  • IV bzw. Nonce nie wiederverwenden: Wird bei AES-GCM derselbe IV mit demselben Schlüssel mehrfach verwendet, ist die Sicherheit komplett gebrochen. Erzeugen Sie für jede Nachricht einen neuen IV mit crypto.getRandomValues(). Den IV speichern Sie zusammen mit dem Chiffrat, geheim ist er nicht.
  • Veraltete Algorithmen meiden: SHA-1 und AES-CBC ohne Authentifizierung sollten Sie nicht mehr verwenden. RSASSA-PKCS1-v1_5 nur einsetzen, wenn die Kompatibilität es erfordert. Für Passwort-Hashing ist digest() ungeeignet. Nutzen Sie PBKDF2 mit vielen Iterationen oder serverseitig Argon2 bzw. bcrypt.
  • Fehler bei der Entschlüsselung: Mit falschem Schlüssel, falschem IV oder manipulierten Daten wird das Promise von decrypt() mit einer OperationError-DOMException abgelehnt. Die Meldung ist bewusst unspezifisch.
  • Nicht exportierbare Schlüssel: Bei extractable: false verlässt der Rohschlüssel die Engine nicht. Als CryptoKey lässt er sich aber in IndexedDB speichern. Das ist gut geeignet für clientseitige Schlüssel.
  • Kompatibilität: Die Grundfunktionen werden in allen modernen Browsern unterstützt. Ed25519 und X25519 sind erst in neueren Versionen verfügbar (Chrome 137+, Firefox 129+, Safari 17+). In Node.js ist die API über require('node:crypto').webcrypto.subtle erreichbar, ab Node.js 19 auch global als crypto.subtle.
  • Clientseitige Kryptografie ersetzt kein HTTPS: Wer den ausgelieferten JavaScript-Code manipulieren kann, etwa durch XSS, kann auch die Kryptografie umgehen. Eine strenge CSP und Subresource Integrity sind daher weiterhin wichtig.