====== std.crypto.aes ====== AES (Advanced Encryption Standard, NIST FIPS 197) ist der weltweit meistgenutzte symmetrische Blockverschlüsselungsalgorithmus. Die Unit implementiert **AES-128** (16-Byte-Schlüssel, 10 Runden) und **AES-256** (32-Byte-Schlüssel, 14 Runden) im **CBC-Modus** (Cipher Block Chaining) mit **PKCS#7-Padding**. Der CBC-Modus verkettet aufeinanderfolgende Blöcke, sodass identische Klartextblöcke zu unterschiedlichen Chiffretextblöcken führen. Ein zufälliger **Initialisierungsvektor (IV)** muss für jede Verschlüsselung neu generiert werden. → [[lyx_-_programmiersprache:units|Standard Library]] · [[lyx_-_programmiersprache:units:crypto:md5|std.crypto.md5]] · [[lyx_-_programmiersprache:units:crypto:sha1|std.crypto.sha1]] ---- ===== Konstanten ===== ^ Konstante ^ Wert ^ Beschreibung ^ | ''AES_BLOCK_SIZE'' | ''16'' | Blockgröße in Bytes (immer 16, unabhängig vom Schlüssel) | | ''AES_128_KEY_SIZE'' | ''16'' | Schlüssellänge AES-128 in Bytes | | ''AES_256_KEY_SIZE'' | ''32'' | Schlüssellänge AES-256 in Bytes | | ''AES_128_ROUNDS'' | ''10'' | Anzahl Verschlüsselungsrunden AES-128 | | ''AES_256_ROUNDS'' | ''14'' | Anzahl Verschlüsselungsrunden AES-256 | ---- ===== Funktionen ===== ^ Signatur ^ Beschreibung ^ | ''AES128CBCEncrypt(key: pchar, iv: pchar, input: pchar, input_len: int64, output: pchar): int64'' | AES-128-CBC-Verschlüsselung mit PKCS#7-Padding. Gibt Länge des Chiffretexts zurück. | | ''AES128CBCDecrypt(key: pchar, iv: pchar, input: pchar, input_len: int64, output: pchar): int64'' | AES-128-CBC-Entschlüsselung mit PKCS#7-Entfernung. Gibt Länge des Klartexts zurück. | | ''AES256CBCEncrypt(key: pchar, iv: pchar, input: pchar, input_len: int64, output: pchar): int64'' | AES-256-CBC-Verschlüsselung mit PKCS#7-Padding. Gibt Länge des Chiffretexts zurück. | | ''AES256CBCDecrypt(key: pchar, iv: pchar, input: pchar, input_len: int64, output: pchar): int64'' | AES-256-CBC-Entschlüsselung mit PKCS#7-Entfernung. Gibt Länge des Klartexts zurück. | | ''AESEncryptOutputSize(input_len: int64): int64'' | Berechnet die benötigte Puffergröße für die Verschlüsselung (PKCS#7 rundet auf nächstes 16-Byte-Vielfaches auf). | | ''AESDecryptOutputSize(input_len: int64): int64'' | Berechnet die maximale Puffergröße für die Entschlüsselung. | | ''AES128KeyExpand(key: pchar, expanded_key: pchar): int64'' | Schlüsselexpansion für AES-128 (für Low-Level-Nutzung, z.B. mehrfache Blockverschlüsselung mit gleichem Schlüssel). | | ''AES256KeyExpand(key: pchar, expanded_key: pchar): int64'' | Schlüsselexpansion für AES-256. | | ''AESEncryptBlockWithKey(block: pchar, expanded_key: pchar, rounds: int64): pchar'' | Verschlüsselt einen einzelnen 16-Byte-Block mit vorexpandiertem Schlüssel. | | ''AESDecryptBlockWithKey(block: pchar, expanded_key: pchar, rounds: int64): pchar'' | Entschlüsselt einen einzelnen 16-Byte-Block mit vorexpandiertem Schlüssel. | ---- ===== Verwendung ===== ==== Nachricht verschlüsseln und entschlüsseln (AES-128) ==== import std.crypto.aes; import std.alloc; import std.string; import std.io; fn main(): int64 { var key: pchar := "0123456789abcdef"; // 16 Bytes für AES-128 var iv: pchar := "abcdef0123456789"; // 16 Bytes IV — für jede Nachricht neu generieren! var plaintext: pchar := "Geheime Nachricht!!"; var ptLen: int64 := StrLen(plaintext); // Ausgabepuffer berechnen und allozieren var encLen: int64 := AESEncryptOutputSize(ptLen); // Aufgerundet auf 16er-Vielfaches var ciphertext: pchar := alloc(encLen) as pchar; // Verschlüsseln var actualLen: int64 := AES128CBCEncrypt(key, iv, plaintext, ptLen, ciphertext); PrintLn("Verschlüsselt: " + IntToStr(actualLen) + " Bytes"); // Entschlüsseln var decBuf: pchar := alloc(AESDecryptOutputSize(actualLen)) as pchar; var decLen: int64 := AES128CBCDecrypt(key, iv, ciphertext, actualLen, decBuf); // Ergebnis prüfen PrintLn("Entschlüsselt: " + decBuf); // Ausgabe: Geheime Nachricht!! free(ciphertext as int64, encLen); free(decBuf as int64, AESDecryptOutputSize(actualLen)); return 0; } ==== AES-256 für höhere Sicherheit ==== import std.crypto.aes; import std.alloc; fn Encrypt256(key32: pchar, iv16: pchar, data: pchar, dataLen: int64): int64 { // key32: 32 Bytes für AES-256 var outLen: int64 := AESEncryptOutputSize(dataLen); var out: int64 := alloc(outLen); if (out == 0) { return 0; } AES256CBCEncrypt(key32, iv16, data, dataLen, out as pchar); return out; // Aufrufer: free(out, outLen) } fn Decrypt256(key32: pchar, iv16: pchar, cipher: pchar, cipherLen: int64): int64 { var outLen: int64 := AESDecryptOutputSize(cipherLen); var out: int64 := alloc(outLen); if (out == 0) { return 0; } AES256CBCDecrypt(key32, iv16, cipher, cipherLen, out as pchar); return out; // Aufrufer: free(out, outLen) } ==== Dateiverschlüsselung ==== import std.crypto.aes; import std.alloc; import std.fs; import std.io; fn EncryptFile(inPath: pchar, outPath: pchar, key: pchar, iv: pchar): bool { // Eingabedatei lesen var inFd: int64 := open(inPath, 0, 0); if (inFd < 0) { return false; } var fileSize: int64 := lseek(inFd, 0, 2); // Größe ermitteln lseek(inFd, 0, 0); var inBuf: int64 := alloc(fileSize); read(inFd, inBuf as pchar, fileSize); close(inFd); // Verschlüsseln var encSize: int64 := AESEncryptOutputSize(fileSize); var outBuf: int64 := alloc(encSize); var written: int64 := AES128CBCEncrypt(key, iv, inBuf as pchar, fileSize, outBuf as pchar); // Ausgabedatei schreiben var outFd: int64 := open(outPath, 577, 0644); // O_WRONLY|O_CREAT|O_TRUNC if (outFd < 0) { free(inBuf, fileSize); free(outBuf, encSize); return false; } write(outFd, outBuf as pchar, written); close(outFd); free(inBuf, fileSize); free(outBuf, encSize); return true; } ==== Vorexpandierter Schlüssel (Performance) ==== Wenn viele Blöcke mit demselben Schlüssel verschlüsselt werden, lohnt sich die einmalige Schlüsselexpansion: import std.crypto.aes; import std.alloc; fn EncryptManyBlocks(key: pchar, blocks: int64, count: int64): void { // Einmalige Schlüsselexpansion: AES-128 → 176 Bytes expanded key var expKey: int64 := alloc(176); AES128KeyExpand(key, expKey as pchar); var i: int64 := 0; while (i < count) limit(1000000) { var block: int64 := blocks + i * 16; AESEncryptBlockWithKey(block as pchar, expKey as pchar, AES_128_ROUNDS); i := i + 1; } free(expKey, 176); } ---- ===== Hinweise ===== * Der **IV muss für jede Verschlüsselung zufällig und einmalig sein** — niemals denselben IV mit demselben Schlüssel für zwei verschiedene Nachrichten verwenden. Ein vorhersehbarer IV macht CBC anfällig gegen Chosen-Plaintext-Angriffe. * Der IV ist **kein Geheimnis** und wird typischerweise zusammen mit dem Chiffretext übertragen (die ersten 16 Bytes der Nachricht). * **PKCS#7-Padding**: Der Chiffretext ist immer ein Vielfaches von 16 Bytes. ''AESEncryptOutputSize(n)'' gibt die korrekte Puffergröße zurück: ''(n / 16 + 1) * 16''. * Für **AES-128** den Schlüssel exakt 16 Bytes lang wählen; für **AES-256** exakt 32 Bytes. * **AES-CBC ist nicht authentifiziert** — es schützt gegen passive Abhörung, nicht gegen aktive Manipulation. Für Integrität zusätzlich einen MAC (HMAC-SHA256) verwenden. * Die Unit ist eine **reine Software-Implementierung** — kein AES-NI. Auf Systemen mit AES-NI-Unterstützung (x86_64 ab Westmere, ARM Cortex-A) ist die Leistung dadurch geringer als eine hardwarebeschleunigte Implementierung. ---- ===== Verwandte Units ===== * ''[[lyx_-_programmiersprache:units:crypto:sha1|std.crypto.sha1]]'' — SHA-1-Hashing (für HMAC-Konstruktionen) * ''[[lyx_-_programmiersprache:units:crypto:md5|std.crypto.md5]]'' — MD5-Hashing * ''[[lyx_-_programmiersprache:units:hash|std.hash]]'' — allgemeine Hash-Utilities (CRC32, FNV, ...) * ''[[lyx_-_programmiersprache:units:net:tls|std.net.tls]]'' — TLS/SSL (verwendet OpenSSL intern, nicht diese Unit) Letzte Aktualisierung: 2026-06-05