Eine einzelne index.html ohne Framework/CDN. Krypto + LSB-Steganografie laufen komplett im Browser (iOS-tauglich). Format-identisch zum CLI; Byte-Interop in beide Richtungen per Node-Test gegen das Python-CLI abgesichert (laedt den Krypto-Kern direkt aus der ausgelieferten index.html). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.3 KiB
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:
- Der Schlüssel (das Pad) ist echt zufällig.
- Das Pad ist mindestens so lang wie die Nachricht.
- 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
pip install Pillow
Sonst nur Python-Stdlib.
Benutzung
1. Pad erzeugen (einmalig)
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
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)
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.offsetmerkt sich den nächsten unbenutzten Byte-Offset im Pad.hideverschlüsselt ab diesem Offset, schreibt den Offset in den Stego-Header und zählt den Zähler um die Nachrichtenlänge weiter.revealliest 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.mjslädt exakt den Krypto-Kern aus der ausgeliefertenindex.htmlund 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:
# 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
.gitignoreblockt*.keyund*.offsetbewusst.