Files
schattenpost/README.md
Artemis d5e7c979d8 schattenpost: OTP + LSB-Steganografie
One-Time-Pad-Verschluesselung mit os.urandom-Pad, automatischer Schutz
gegen Pad-Wiederverwendung via Offset-Zaehler, LSB-Einbettung in Traegerfoto.
CLI mit genkey/hide/reveal, einzige Abhaengigkeit Pillow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 20:41:21 +00:00

109 lines
3.8 KiB
Markdown

# schattenpost
Vertrauliche Nachrichten via **One-Time-Pad** + **LSB-Steganografie**.
Verschlüsselt Text mit einem echten One-Time-Pad (XOR gegen `os.urandom`-Zufall)
und versteckt den Ciphertext in den niederwertigsten Bits eines Trägerfotos. Das
Ergebnis sieht aus wie ein ganz normales Bild, trägt die Nachricht aber bit-genau
in sich. Gedacht als unauffälliger Kanal, dessen Inhalt selbst bei Mitlesen des
Transports nicht rekonstruierbar ist.
## Warum das (theoretisch) unknackbar ist
One-Time-Pad ist der einzige Cipher mit *informationstheoretischer* Sicherheit —
nicht nur „rechnerisch schwer", sondern beweisbar unknackbar. Das gilt aber nur,
solange **alle drei** Regeln eingehalten werden:
1. Der Schlüssel (das *Pad*) ist echt zufällig.
2. Das Pad ist mindestens so lang wie die Nachricht.
3. Jeder Pad-Abschnitt wird **nur ein einziges Mal** benutzt.
Regel 3 ist der klassische Todesstoß (`two-time-pad`). schattenpost erzwingt sie
automatisch über einen Offset-Zähler (siehe unten).
## Installation
```bash
pip install Pillow
```
Sonst nur Python-Stdlib.
## Benutzung
### 1. Pad erzeugen (einmalig)
```bash
python3 schattenpost.py genkey -o pad.key -s 1000000 # 1 MB Pad
```
Das erzeugte `pad.key` **sicher und persönlich** an den Gesprächspartner
übergeben (USB-Stick, kein digitaler Kanal!). Beide Seiten brauchen die
byte-identische Datei. Daneben entsteht `pad.key.offset` — der Verbrauchszähler.
### 2. Nachricht verstecken
```bash
python3 schattenpost.py hide \
-t "Treffpunkt morgen 18 Uhr am alten Hafen." \
-k pad.key \
-c urlaubsfoto.jpg \
-o harmlos.png
```
Alternativ `-i datei.txt` statt `-t`, oder Text über stdin.
### 3. Nachricht rausholen (Gegenseite)
```bash
python3 schattenpost.py reveal -s harmlos.png -k pad.key
```
Mit `-o klartext.txt` in eine Datei statt auf stdout.
## ⚠️ Der eine wichtige Haken
**Verschicke das Stego-PNG immer als Datei/Dokument, niemals als „Foto".**
Messenger (WhatsApp, Telegram-„Foto", …) jagen Fotos durch verlustbehaftete
JPEG-Kompression. Das verändert die Pixelwerte und **zerstört die versteckten
Bits sofort** — `reveal` schlägt dann fehl. Als Dokument/Datei bleibt das PNG
bit-genau erhalten.
## Wie der Pad-Wiederverwendungsschutz funktioniert
- `pad.key.offset` merkt sich den nächsten unbenutzten Byte-Offset im Pad.
- `hide` verschlüsselt ab diesem Offset, schreibt den Offset **in den
Stego-Header** und zählt den Zähler um die Nachrichtenlänge weiter.
- `reveal` liest den Offset aus dem Bild und weiß automatisch, welcher
Pad-Abschnitt gilt.
So wird garantiert kein Pad-Byte doppelt verwendet — solange der Zähler nicht
manuell zurückgedreht wird. Der Sender führt den Zähler; der Empfänger braucht
ihn nicht (der Offset steckt im Bild).
## Container-Format
Vor der LSB-Einbettung wird ein kleiner Header vorangestellt:
| Feld | Größe | Inhalt |
|---------|-------|-------------------------------|
| magic | 4 B | `SPST` |
| version | 1 B | `1` |
| offset | 8 B | Pad-Offset (uint64, BE) |
| length | 4 B | Ciphertext-Länge (uint32, BE) |
| ciphertext | n B | XOR(plaintext, pad[offset…]) |
Die Bits werden linear (MSB zuerst) in die LSBs der R/G/B-Kanäle geschrieben.
## Grenzen / Hinweise
- **Steganografie versteckt, authentifiziert aber nicht.** Ein Angreifer, der
das Format kennt, könnte Bits kippen. Für Manipulationsschutz bräuchte es
zusätzlich einen MAC (z.B. HMAC mit einem separaten Pad-Bereich).
- Die Sicherheit steht und fällt mit der **geheimen, sicheren Übergabe des
Pads**. Das ist der eigentliche Aufwand bei OTP — es gibt kein Schlüssel-
Austauschprotokoll, das dir das abnimmt.
- Pads gehören **niemals** in ein Repository. Die `.gitignore` blockt `*.key`
und `*.offset` bewusst.