Start · Sprachen · JavaScript · Referenz · HkdfParams

HkdfParams

Schnittstelle

Parameter-Wörterbuch für den HKDF-Algorithmus, das als <code>algorithm</code>-Argument an <code>SubtleCrypto.deriveKey()</code> oder <code>deriveBits()</code> übergeben wird.

seit JavaScript Baseline: alle modernen Browser (Chrome 60+, Firef Kategorie: webapi

Signatur

interface HkdfParams extends Algorithm

Beschreibung

HkdfParams ist kein Konstruktor, sondern ein einfaches Objekt-Wörterbuch der Web Crypto API. Es beschreibt, wie der HKDF-Algorithmus (HMAC-based Key Derivation Function, RFC 5869) aus vorhandenem Schlüsselmaterial neue Schlüssel ableiten soll. Übergeben wird es als erstes Argument an crypto.subtle.deriveKey() oder crypto.subtle.deriveBits().

HKDF eignet sich, wenn schon hochwertiges, zufälliges Schlüsselmaterial vorliegt – etwa ein gemeinsames Geheimnis aus einem ECDH-Schlüsselaustausch oder ein zufälliger Master-Schlüssel. Daraus kann man mehrere unabhängige Teilschlüssel ableiten (z. B. je einen für Verschlüsselung und Authentifizierung), indem man unterschiedliche info-Werte verwendet.

Für Passwörter ist HKDF nicht geeignet, da es absichtlich schnell ist. Für passwortbasierte Ableitung sollte man Pbkdf2Params (PBKDF2) verwenden.

Das Ausgangsmaterial muss vorher per crypto.subtle.importKey("raw", …, "HKDF", false, ["deriveKey"]) als CryptoKey importiert werden; der Import-Schlüssel muss nicht extrahierbar sein (extractable: false ist sogar Pflicht).

Parameter

Name Typ Default Beschreibung
$name Pflicht string Muss "HKDF" sein.
$hash Pflicht string | Algorithm Die intern für HMAC verwendete Hash-Funktion: "SHA-256", "SHA-384" oder "SHA-512". "SHA-1" ist möglich, aber nicht empfohlen.
$salt Pflicht ArrayBuffer | TypedArray | DataView Salt-Wert. Laut RFC 5869 optional, in der Web Crypto API aber Pflichtfeld – ein leeres Array ist erlaubt. Idealerweise zufällig und so lang wie die Hash-Ausgabe (z. B. 32 Byte bei SHA-256). Muss nicht geheim sein.
$info Pflicht ArrayBuffer | TypedArray | DataView Anwendungs- bzw. kontextspezifische Information (z. B. "app-v1 encryption"), die den abgeleiteten Schlüssel an einen Zweck bindet. Darf leer sein. Unterschiedliche info-Werte ergeben unabhängige Schlüssel.

Rückgabewert

Typ
object
Beschreibung
Kein Rückgabewert im eigentlichen Sinn – HkdfParams ist ein reines Konfigurationsobjekt. deriveKey() liefert damit ein Promise<CryptoKey>, deriveBits() ein Promise<ArrayBuffer>.

Beispiele

AES-GCM-Schlüssel aus einem Master-Geheimnis ableiten

const encoder = new TextEncoder();

// Hochwertiges Ausgangsmaterial (z. B. vom Server oder aus ECDH)
const masterSecret = crypto.getRandomValues(new Uint8Array(32));

const baseKey = await crypto.subtle.importKey(
  "raw", masterSecret, "HKDF", false, ["deriveKey"]
);

/** @type {HkdfParams} */
const hkdfParams = {
  name: "HKDF",
  hash: "SHA-256",
  salt: crypto.getRandomValues(new Uint8Array(32)),
  info: encoder.encode("meine-app v1: Verschlüsselung"),
};

const aesKey = await crypto.subtle.deriveKey(
  hkdfParams,
  baseKey,
  { name: "AES-GCM", length: 256 },
  false,
  ["encrypt", "decrypt"]
);

console.log(aesKey.algorithm);
{ name: "AES-GCM", length: 256 }

Mehrere unabhängige Teilschlüssel per info trennen

const enc = new TextEncoder();
const baseKey = await crypto.subtle.importKey(
  "raw", crypto.getRandomValues(new Uint8Array(32)), "HKDF", false, ["deriveBits"]
);
const salt = new Uint8Array(32); // fester Salt, z. B. pro Sitzung ausgehandelt

const derive = async (label) => {
  const bits = await crypto.subtle.deriveBits(
    { name: "HKDF", hash: "SHA-256", salt, info: enc.encode(label) },
    baseKey,
    256 // Anzahl Bits
  );
  return new Uint8Array(bits);
};

const encKeyBytes = await derive("encryption");
const macKeyBytes = await derive("authentication");

console.log(encKeyBytes.length, macKeyBytes.length);
console.log(encKeyBytes.every((b, i) => b === macKeyBytes[i]));
32 32 false

ECDH-Geheimnis mit HKDF zu einem Sitzungsschlüssel machen

const alice = await crypto.subtle.generateKey(
  { name: "ECDH", namedCurve: "P-256" }, false, ["deriveBits"]
);
const bob = await crypto.subtle.generateKey(
  { name: "ECDH", namedCurve: "P-256" }, false, ["deriveBits"]
);

// Rohes gemeinsames Geheimnis – nicht direkt als Schlüssel verwenden!
const shared = await crypto.subtle.deriveBits(
  { name: "ECDH", public: bob.publicKey }, alice.privateKey, 256
);

const hkdfKey = await crypto.subtle.importKey("raw", shared, "HKDF", false, ["deriveKey"]);

const sessionKey = await crypto.subtle.deriveKey(
  {
    name: "HKDF",
    hash: "SHA-256",
    salt: new Uint8Array(0), // leerer Salt ist erlaubt
    info: new TextEncoder().encode("chat-session"),
  },
  hkdfKey,
  { name: "AES-GCM", length: 128 },
  false,
  ["encrypt", "decrypt"]
);

console.log(sessionKey.type, sessionKey.usages);
secret ["encrypt", "decrypt"]

// Wichtig · Fallstricke

  • Nicht für Passwörter: HKDF ist schnell und bietet keinen Schutz gegen Brute-Force. Für Passwörter PBKDF2 (Pbkdf2Params) mit hoher Iterationszahl verwenden.
  • salt und info sind Pflicht: Fehlen sie, wirft deriveKey() einen TypeError. Leere Puffer (new Uint8Array(0)) sind zulässig.
  • Salt aufbewahren: Wer denselben Schlüssel später erneut ableiten will, muss exakt denselben salt, dieselbe info und denselben hash verwenden. Der Salt ist nicht geheim und kann mit den Daten gespeichert werden.
  • Import-Einschränkungen: HKDF-Schlüssel können nur im Format "raw" und nur mit extractable: false importiert werden, sonst gibt es einen SyntaxError/NotSupportedError. generateKey() wird für HKDF nicht unterstützt.
  • Ausgabelänge: Bei deriveBits() ist die maximale Länge 255 × Hash-Länge (z. B. 8160 Byte bei SHA-256); die Länge muss ein Vielfaches von 8 Bit sein.
  • Kompatibilität: Nur in sicheren Kontexten (HTTPS, localhost) verfügbar. In allen modernen Browsern unterstützt; in Node.js über globalThis.crypto.subtle bzw. require("node:crypto").webcrypto.