Start · Sprachen · JavaScript · Referenz · SubtleCrypto.digest()

SubtleCrypto.digest()

Methode

Berechnet asynchron einen kryptografischen Hash (Digest) der übergebenen Daten mit SHA-1, SHA-256, SHA-384 oder SHA-512 und liefert ihn als <code>ArrayBuffer</code>.

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

Signatur

SubtleCrypto.prototype.digest(algorithm, data)

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

Typ
Promise<ArrayBuffer>
Beschreibung
Ein 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'));
d3751d33f9cd5049c4af2b462735457e4d3baf130bcbb87f389e349fbaeb20b9

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}`);
});
Datei ist unverändert // bei einer leeren Datei

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);
43 43

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);
64

// Wichtig · Fallstricke

  • Nur in sicherem Kontext: Im Browser gibt es crypto.subtle nur über HTTPS oder localhost. Auf einer HTTP-Seite ist es undefined, und der Aufruf scheitert mit einem TypeError.
  • 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 über crypto.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 als crypto). Deno und Bun unterstützen die Methode ebenfalls.