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