Kiste
DE

The book is currently only available in German.

Standard-Bibliothek — `hash`

Verfügbar — implementiert in Phase B.7.3. Vollständige Spec in docs/hash.md.

Hash-Funktionen verwandeln beliebige Daten in einen kurzen, deterministischen Fingerabdruck. Der gleiche Input ergibt immer den gleichen Hash. Ein einziges Bit Unterschied im Input ergibt einen komplett anderen Hash.

25.1 Aktivieren und einfache Hashes

nutze hash

sag hash.md5("Hallo")            // 32-stelliger Hex-String
sag hash.sha256("Hallo")         // 64-stelliger Hex-String — der Standard
sag hash.sha512("Hallo")         // 128-stelliger Hex-String

25.2 Sicherheits-Einordnung — sehr wichtig

Nicht alle Hashes sind gleich gut. Das ist die Realität:

Algorithmus Status Wofür benutzen?
MD5 kryptographisch gebrochen Caching, ETags, Identifiers — nie für Sicherheit
SHA-1 kryptographisch gebrochen Git-Kompatibilität, Legacy — nie für neue Sicherheit
SHA-256 sicher Datei-Hashes, Inhalts-Verifikation, Standard-Wahl
SHA-512 sicher Wie SHA-256, längerer Output
HMAC-SHA256 sicher API-Tokens, Webhook-Signaturen

Faustregel: Wenn du nicht weißt was du brauchst, nimm SHA-256.

25.3 Was hash NICHT ist

Hash-Funktionen sind nicht für Passwörter gedacht!

// FALSCH — niemals so Passwörter speichern!
nimm gehasht = hash.sha256(passwort)
datei.schreibe("benutzer.txt", gehasht)

Warum nicht? SHA-256 ist zu schnell. Ein Angreifer kann Milliarden Hashes pro Sekunde durchprobieren (Brute-Force). Für Passwörter braucht man absichtlich langsame Funktionen wie Bcrypt, Argon2 oder scrypt. Die kommen später mit dem passwort-Modul.

Auch nicht in hash:

  • Verschlüsselung (AES, RSA) → kommt mit krypto-Modul
  • Sichere Zufallszahlen für Salts/Tokens → kommt mit krypto.zufall_bytes

25.4 Datei-Hashes (Inhalts-Verifikation)

nutze datei
nutze hash

// Hinweis: setzt eine vorhandene Datei voraus (sonst Fehler).
nimm fingerabdruck = hash.sha256(datei.inhalt("./readme.md"))
sag "Datei-Hash: {fingerabdruck}"

// Später: prüfen, ob die Datei sich geändert hat
nimm aktueller = hash.sha256(datei.inhalt("./readme.md"))
wenn aktueller == fingerabdruck {
    sag "Datei unverändert"
}

Heute funktioniert das nur für Text-Dateien, weil datei.inhalt UTF-8 verlangt. Binär-Hashes (Bilder, ZIP, etc.) kommen mit dem bytes-Modul.

25.5 HMAC — authentifiziertes Hashing

HMAC ist wie ein normaler Hash, aber mit einem geheimen Schlüssel. Nur jemand, der den Schlüssel kennt, kann den HMAC reproduzieren — perfekt für API-Tokens und Webhook-Signaturen.

nutze umgebung

// Schlüssel aus Umgebung holen — NIEMALS im Quellcode hartcodieren!
nimm geheim = umgebung.wert_oder("API_SECRET", "")
wenn geheim == "" {
    sag "API_SECRET nicht gesetzt!"
    umgebung.beende(1)
}

nimm payload = "user_id=42&action=transfer"
nimm signatur = hash.hmac_sha256(payload, geheim)

// Ein Angreifer ohne den Schlüssel kann diese Signatur nicht erzeugen.
// Server prüft mit derselben Funktion, ob die Signatur stimmt:
sag hash.hmac_sha256(payload, geheim) == signatur    // wahr

25.6 Base64 und Hex — Encoding

// Base64 — gut für JSON-Übertragung von „beliebigen" Bytes
sag hash.base64_kodiert("Hallo")        // "SGFsbG8="
sag hash.base64_dekodiert("SGFsbG8=")   // "Hallo"

// Hex — gut für menschen-lesbare Hash-Ausgaben (deshalb sind Hash-Funktionen
// ohnehin Hex-formatiert)
sag hash.hex_kodiert("ABC")             // "414243"
sag hash.hex_dekodiert("414243")        // "ABC"

Roundtrip funktioniert garantiert für UTF-8-Text: dekodiert(kodiert(x)) == x.

Caveat: Beim Dekodieren erwartet Kiste, dass die dekodierten Bytes gültiges UTF-8 sind — sonst Fehler. Wer beliebige Bytes braucht, wartet auf das bytes-Modul.

25.7 Was nicht in hash ist

  • Streaming-Hashing für sehr große Dateien — kommt mit bytes/Streaming.
  • URL-Safe-Base64 — kommt später falls Bedarf.
  • Konstanten-Zeit-Vergleich für HMAC-Tags — kommt mit krypto.gleich_konstant_zeit.
  • Bcrypt/Argon2/scrypt/PBKDF2 — eigenes Modul passwort/krypto.
  • Verschlüsselung, Signaturen, Key-Derivationkrypto-Modul.