Signatur
Beschreibung
crypto.subtle.digest() berechnet einen Hashwert fester Länge aus beliebigen Binärdaten. Eine Hash-Funktion ist eine Einwegfunktion: Aus dem Digest lassen sich die Originaldaten nicht zurückgewinnen, und schon eine winzige Änderung der Eingabe ergibt einen völlig anderen Wert. Das eignet sich gut für Integritätsprüfungen (Prüfsummen von Downloads), inhaltsbasierte Cache-Schlüssel, Deduplizierung und das Erzeugen von Kennungen, zum Beispiel für die PKCE-code_challenge bei OAuth.
Die Methode arbeitet asynchron und gibt ein Promise zurück, das mit einem ArrayBuffer erfüllt wird. Die Eingabe muss als ArrayBuffer, TypedArray oder DataView vorliegen. Texte wandelt man vorher mit TextEncoder in Bytes (UTF-8) um, Dateien liest man mit Blob.prototype.arrayBuffer() ein. Zum Anzeigen oder Vergleichen wandelt man das Ergebnis meist in einen Hex- oder Base64-String um.
Unterstützt werden "SHA-1", "SHA-256", "SHA-384" und "SHA-512". Für neue Anwendungen ist SHA-256 oder stärker die richtige Wahl. SHA-1 gilt als gebrochen und taugt nur noch für Altsysteme, die es ausdrücklich verlangen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $algorithm Pflicht | string | { name: string } | Name der Hash-Funktion: "SHA-1", "SHA-256", "SHA-384" oder "SHA-512". Alternativ ein Objekt wie { name: "SHA-256" }. Groß-/Kleinschreibung spielt keine Rolle. |
|
| $data Pflicht | ArrayBuffer | TypedArray | DataView | Die zu hashenden Binärdaten. Strings werden nicht angenommen und müssen vorher z. B. mit new TextEncoder().encode(text) umgewandelt werden. |
Rückgabewert
Promise, das mit einem ArrayBuffer erfüllt wird, der den Digest enthält: 20 Byte bei SHA-1, 32 bei SHA-256, 48 bei SHA-384 und 64 bei SHA-512. Bei einem unbekannten Algorithmus wird es mit einer NotSupportedError-DOMException abgelehnt, bei falschem Datentyp mit einem TypeError.Beispiele
SHA-256-Hash eines Strings als Hex-Wert
const sha256Hex = async (text) => {
const bytes = new TextEncoder().encode(text);
const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
return [...new Uint8Array(hashBuffer)]
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
};
console.log(await sha256Hex('hallo'));
Prüfsumme einer hochgeladenen Datei mit einer erwarteten Prüfsumme vergleichen
const input = document.querySelector('input[type=file]');
const expected = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
input.addEventListener('change', async () => {
const file = input.files[0];
if (!file) return;
const buffer = await file.arrayBuffer();
const hash = await crypto.subtle.digest('SHA-256', buffer);
const hex = Array.from(new Uint8Array(hash), (b) => b.toString(16).padStart(2, '0')).join('');
console.log(hex === expected ? 'Datei ist unverändert' : `Abweichung: ${hex}`);
});
PKCE-code_challenge für OAuth 2.0 erzeugen (Base64URL)
const base64Url = (buffer) =>
btoa(String.fromCharCode(...new Uint8Array(buffer)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
const createPkcePair = async () => {
const verifier = base64Url(crypto.getRandomValues(new Uint8Array(32)));
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
return { verifier, challenge: base64Url(digest) };
};
const { verifier, challenge } = await createPkcePair();
console.log(verifier.length, challenge.length);
Node.js: Web-Crypto-API ohne Import nutzen
// Node.js 19+ stellt crypto global bereit (ab 15 über require('node:crypto').webcrypto)
const hash = await crypto.subtle.digest('SHA-512', new TextEncoder().encode('abc'));
console.log(hash.byteLength);
// Wichtig · Fallstricke
- Nur in sicherem Kontext: Im Browser gibt es
crypto.subtlenur über HTTPS oderlocalhost. Auf einer HTTP-Seite ist esundefined, und der Aufruf scheitert mit einemTypeError. - Kein Passwort-Hashing: SHA-Hashes sind absichtlich schnell und damit für Brute-Force-Angriffe anfällig. Für Passwörter nimmt man
deriveBits()/deriveKey()mit PBKDF2 oder serverseitig bcrypt, scrypt bzw. Argon2. - Kein MAC:
hash(geheimnis + daten)ist anfällig für Length-Extension-Angriffe. Zum Authentifizieren von Nachrichten gehört HMAC übercrypto.subtle.sign(). - Kein Streaming: Die Methode braucht die kompletten Daten auf einmal im Speicher. Sehr große Dateien (mehrere GB) lassen sich damit nicht stückweise hashen. Dafür braucht man eine Bibliothek oder in Node.js
crypto.createHash(). - MD5 wird nicht unterstützt. SHA-1 geht zwar, gilt aber als unsicher (Kollisionen sind praktisch erzeugt worden).
- Bei großen Puffern läuft
String.fromCharCode(...bytes)in einen Stack-Überlauf. Den Base64-Code aus Beispiel 3 sollte man nur für kurze Digests verwenden. - Kompatibilität: Läuft in allen aktuellen Browsern, in Web Workers und in Node.js 15+ (
require('node:crypto').webcrypto, ab Node.js 19 global alscrypto). Deno und Bun unterstützen die Methode ebenfalls.