# 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. ## Weboberfläche (`web/index.html`) Eine **einzige, self-contained HTML-Datei** — kein Framework, kein CDN, kein Build. Verschlüsselung und Steganografie laufen zu 100 % im Browser (client-side): Pad, Klartext und Nachricht verlassen das Gerät nie. Ein Server, der die Datei ausliefert, ist ein reiner „dummer" Fileserver und sieht nichts. * **Überall erreichbar, iOS inklusive.** Nutzt nur Safari-Standard-APIs (Canvas, FileReader, `crypto.getRandomValues`). * **Format-kompatibel zum CLI.** Am Terminal verstecken, am Handy im Browser aufdecken — und umgekehrt. Byte-Interop ist per Test abgesichert (`web/_interop_test.mjs` lädt exakt den Krypto-Kern aus der ausgelieferten `index.html` und prüft beide Richtungen gegen das Python-CLI). * **Offset-Tracking** merkt sich pro Pad (via `localStorage`) den nächsten freien Offset. Achtung: Der Zähler ist pro Browser/Gerät. Wer abwechselnd über mehrere Instanzen sendet, muss den Offset manuell synchron halten — sonst droht Pad-Wiederverwendung. ### Deployment Es ist eine statische Datei — einfach irgendwo hinlegen: ```bash # lokal testen python3 -m http.server -d web 8000 # -> http://localhost:8000 # produktiv: web/index.html hinter einen beliebigen Webserver / Static-Host ``` ### ⚠️ iOS-Eigenheit Stego-Bild über **„In Dateien sichern"** ablegen und als **Datei** teilen — nicht in „Fotos" speichern. iOS re-komprimiert Bilder aus der Fotos-Mediathek und würde die Nachricht zerstören. ## 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.