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

3.8 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:

  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

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 sofortreveal 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.