====== std.crypto.hmac — HMAC-SHA256 ====== ''import std.crypto.hmac;'' HMAC-SHA256 nach RFC 2104 / FIPS 198-1. Kombiniert einen geheimen Schlüssel mit einer Nachricht zu einem Message Authentication Code (MAC) — schützt sowohl Integrität als auch Authentizität der Daten. Abhängigkeit: [[lyx_-_programmiersprache:units:crypto:sha256|std.crypto.sha256]]. → [[lyx_-_programmiersprache:units:crypto|std.crypto Paket]] · [[lyx_-_programmiersprache:units:crypto:sha256|std.crypto.sha256]] · [[lyx_-_programmiersprache:units:crypto:rand|std.crypto.rand]] ---- ===== Funktionen ===== ^ Funktion ^ Signatur ^ Beschreibung ^ | ''HMAC_SHA256'' | ''(key: int64, keyLen: int64, data: int64, dataLen: int64, out: int64): void'' | Schreibt 32-Byte-MAC in ''out'' | | ''HMAC_SHA256_Hex'' | ''(key: int64, keyLen: int64, data: int64, dataLen: int64, out: int64): void'' | Schreibt 64-Zeichen Lowercase-Hex + NUL in ''out'' (65 Bytes) | Schlüssel beliebiger Länge sind gültig. Schlüssel > 64 Bytes werden intern mit SHA-256 auf 32 Bytes komprimiert. Empfohlen: 32 Bytes. ---- ===== Verwendung ===== ==== Nachricht authentifizieren ==== import std.crypto.hmac; import std.alloc; fn main(): int64 { var key: pchar := "geheim"; var data: pchar := "Nachricht die authentifiziert werden soll"; var mac: int64 := alloc(32); HMAC_SHA256(key as int64, 6, data as int64, 41, mac); // mac: 32-Byte-HMAC — zum Senden oder Vergleichen free(mac, 32); return 0; } ==== Hex-Ausgabe (z.B. für HTTP-Header) ==== import std.crypto.hmac; import std.alloc; import std.io; fn SignRequest(key: pchar, keyLen: int64, body: pchar, bodyLen: int64): void { var hex: int64 := alloc(65); HMAC_SHA256_Hex(key as int64, keyLen, body as int64, bodyLen, hex); PrintLn("X-Signature: " + hex as pchar); free(hex, 65); } ==== MAC-Vergleich (konstante Zeit) ==== import std.crypto.hmac; import std.alloc; // Zeitkonstanter Vergleich — verhindert Timing-Angriffe fn HmacEqual(a: int64, b: int64): bool { var diff: int64 := 0; var i: int64 := 0; while (i < 32) { diff := diff | (peek8(a + i) ^ peek8(b + i)); i := i + 1; } return diff = 0; } fn VerifyHmac(key: pchar, keyLen: int64, data: pchar, dataLen: int64, expectedMac: int64): bool { var computed: int64 := alloc(32); HMAC_SHA256(key as int64, keyLen, data as int64, dataLen, computed); var ok: bool := HmacEqual(computed, expectedMac); free(computed, 32); return ok; } ==== Abgeleiteten Schlüssel erzeugen (einfaches HKDF-Extract) ==== import std.crypto.hmac; import std.alloc; // HKDF-Extract-Schritt: PRK = HMAC-SHA256(salt, inputKeyMaterial) fn HKDFExtract(salt: pchar, saltLen: int64, ikm: int64, ikmLen: int64, prk: int64): void { HMAC_SHA256(salt as int64, saltLen, ikm, ikmLen, prk); } ---- ===== Hinweise ===== * **MAC ≠ Signatur**: HMAC authentifiziert, wer den geheimen Schlüssel kennt. Für asymmetrische Signaturen (Dritte können verifizieren ohne Schlüsselkenntnis) → [[lyx_-_programmiersprache:units:crypto:ecc|std.crypto.ecc]] (ECDSA). * **AES-CBC + HMAC**: AES-CBC verschlüsselt, aber authentifiziert nicht. Für encrypt-then-MAC: zuerst verschlüsseln, dann HMAC über den Chiffretext berechnen und mitsenden. * **Konstanter Zeitvergleich**: MACs **niemals** mit direktem Byte-Vergleich oder ''StrCmp'' prüfen — Timing-Angriffe können den Schlüssel offenlegen. Immer alle 32 Bytes vergleichen (wie im Beispiel oben). * **Schlüssellänge**: Empfohlen sind 32 Bytes (= SHA-256-Ausgabelänge). Kürzere Schlüssel reduzieren die Sicherheit; längere werden intern auf 32 Bytes gehasht. * **Schlüssel geheim halten**: Der HMAC-Schlüssel ist das Geheimnis — mit ''std.crypto.rand'' → ''RandBytesExact'' generieren, nie hartkodieren. ---- Letzte Aktualisierung: 2026-06-06