====== 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