Rede Ende-zu-Ende verschlüsselter Messenger

AGPL-3.0 · Protokoll v3

Reden ohne Mithörer.

Rede ist ein Ende-zu-Ende verschlüsselter Messenger mit eigenem Server, Desktop-Client und Terminal-Client. Der Server transportiert ausschließlich Chiffretext. Schlüssel und Klartext verlassen das Endgerät nicht.

Komponenten: Server (~6.800 Zeilen Node.js). Desktop-Client (~18.600 Zeilen C#/Avalonia) für Windows und Linux. Terminal-Client (~4.800 Zeilen JavaScript) im TUI- und CLI-Modus. Wire-Protokoll v3, Hybrid-Handshake X3DH plus PQXDH, Double Ratchet, Sender Keys, Sealed Sender.

Sicherheitsmodell

Rede trennt strikt zwischen Klartext- und Chiffretext-Bereich. Klartext lebt vollständig auf dem Endgerät. Sobald eine Nachricht den Client verlässt, ist sie bereits durch den Krypto-Layer gewandert und liegt nur noch als binärer Chiffretext auf der Leitung. Der Server leitet diese Bytes weiter und persistiert sie kurz für Offline-Zustellung. Er sieht den Inhalt nie.

Architekturüberblick: Klartext-Schicht und Krypto-Schicht beim Client, Server transportiert nur Chiffretext.
Klartext- und Krypto-Schicht liegen ausschließlich beim Client. Der Server transportiert Chiffretext und persistiert ihn kurz für Offline-Zustellung.

Die kryptografischen Bausteine sind im Kern dieselben, die Signal seit Jahren in Produktion führt, ergänzt um eine Post-Quantum-Schicht aus PQXDH. Keine eigenen Primitive, keine Variationen bestehender Verfahren. libsodium auf dem Desktop, geprüfte Bindings im Terminal, ML-KEM-768 aus der Referenz-Implementierung.


Server

Der Server ist ein WebSocket-Daemon. Clients halten eine persistente Verbindung, identifizieren sich mit einer Ed25519-signierten Session und tauschen danach JSON-Frames aus. Das Wire-Protokoll ist in Version 3 spezifiziert.

Ein einzelner Frame für den Versand einer Direktnachricht sieht in etwa so aus:

// Wire-Protokoll v3, vereinfacht
{
  "type": "msg.send",
  "to":   "user:bob@example.org",
  "hdr":  { "n": 42, "pn": 41, "dh": "<ratchet-pub>" },
  "ct":   "<chiffretext>"
}

Was hier nicht auftaucht, ist genauso wichtig wie das, was drin steht. Es gibt keinen Klartext, keinen Schlüssel, keinen identifizierbaren Absender-Header. Die Absender-Identität wird im Sealed-Sender-Verfahren mit verkapselt. Der Server kennt nur das Empfänger-Routing.

Als Datenbankschicht stehen SQLite für kleine, lokale Setups und PostgreSQL für den produktiven Betrieb zur Auswahl. Für Cluster und Föderation tritt Redis als Pub/Sub-Schicht hinzu. Gruppenanrufe laufen über einen mediasoup-SFU, der genauso wenig in die Audio-Frames hineinsieht wie der Wire-Server in die Text-Nachrichten.

Desktop-Client

Der Desktop-Client ist in Avalonia auf .NET 8 gebaut. Er ist in zwei Projekte getrennt: Rede.Core kapselt die Business-Logik und den Krypto-Stack über libsodium, Rede.Desktop ist die UI-Schicht. Die strikte Trennung macht es möglich, denselben Krypto-Code aus beiden Anwendungsfällen heraus zu testen, ohne die UI hochzufahren.

Rede Desktop-Client: 1:1-Chat mit etablierter E2EE-Session
1:1-Chat mit etablierter E2EE-Session. Das Hangschloss-Symbol kennzeichnet eine verifizierte Identität, der Doppelhaken den Zustellstatus.

Bevor ein Account überhaupt erreichbar ist, muss die lokale Profildatei mit einer Passphrase entsperrt werden. Sie hält die langlebigen Identity-Keys, die Pre-Keys und den Session-State. Wer die Datei kopiert ohne die Passphrase zu kennen, kommt nicht hinein.

Rede Login-Screen mit Passphrase und Server-Auswahl
Login: die Passphrase entsperrt den lokalen Profiltresor. Die Server-Auswahl ist pro Identität konfiguriert, sodass dasselbe Gerät mit verschiedenen Heimat-Servern arbeiten kann.

Releases werden mit einem Ed25519-Schlüssel signiert. Der Auto-Updater verifiziert die Signatur des Release-Manifests vor jeder Aktualisierung. Ein Angreifer auf das CDN kann damit kein Schad-Update einschleusen, ohne den Signaturschlüssel zu besitzen.

Ausgeliefert werden Builds für Windows und Linux.

Terminal-Client

Parallel zum Desktop-Client existiert eine Terminal-Variante in JavaScript. Sie ist kein Add-On, sondern eine vollwertige zweite Implementierung: gleicher Wire-Stack, dieselben kryptografischen Primitive, dasselbe Identitätsmodell. Sicherheitsrelevante Änderungen landen verpflichtend in beiden Codebasen.

Beim Start zeigt der Client transparent, welche Bausteine er initialisiert:

Rede Terminal-Client v1: Startbildschirm mit Krypto-Stack-Init
Boot des Terminal-Clients: X3DH, Double Ratchet, XSalsa20-Poly1305, Pre-Keys, Identity-Fingerprint. Was nicht im Init-Log auftaucht, fährt nicht hoch.

Im Alltag erfüllt der Terminal-Client zwei Aufgaben. Erstens ist er auf Headless-Servern über SSH bedienbar. Zweitens dient er als Referenz: zeigt sich dasselbe Verhalten auch im Terminal, liegt es im Protokoll und nicht in der UI.

Places

Places sind das Pendant zu Discord-Servern. Jeder Place hat Kanäle, Rollen und Berechtigungen. Technisch ist ein Kanal nichts anderes als eine besondere Sender-Key-Gruppe: jede Mitgliedschaft bringt einen eigenen Ratchet mit, Member-Changes lösen ein automatisches Re-Keying aus.

Rede Places: Discord-ähnliche Server mit Kanalstruktur
Ein Place mit Kanälen wie off-topic, willkommen, chat, bugs, features. Die Berechtigungsstruktur ist pro Rolle pro Kanal definierbar.

Krypto-Stack

X3DH und PQXDH: Erstkontakt mit Hybrid-Handshake

Wenn Alice zum ersten Mal an Bob schreibt, holt ihr Client ein Pre-Key-Bundle vom Server: Bobs langlebigen Identity-Key, einen signierten Pre-Key, optional einen Einmal-Pre-Key und seit Protokollversion 3 einen ML-KEM-768-Public-Key. Aus vier klassischen Diffie-Hellman-Werten und dem ML-KEM-Shared-Secret leitet sie den initialen Session-Key ab:

// X3DH + PQXDH Schlüsselableitung
SK = HKDF(
  0xff ||  Domain-Separator
  DH(IK_a, SPK_b) ||
  DH(EK_a, IK_b)  ||
  DH(EK_a, SPK_b) ||
  DH(EK_a, OPK_b) ||
  KEM_SS          // ML-KEM-768
)
X3DH PQXDH Handshake-Diagramm
Vier klassische Diffie-Hellman-Werte plus ML-KEM-768 ergeben gemeinsam den Session-Key. Wer heute klassische DHs mitschneidet und morgen quantenfähig ist, sitzt trotzdem nicht auf einer auflesbaren Nachricht.

Double Ratchet: Forward Secrecy ab Nachricht zwei

Nach dem Handshake übernimmt das Double-Ratchet-Protokoll. Es hält zwei verkettete KDFs, einen Root-Chain und einen Sending- bzw. Receiving-Chain. Jede Nachricht verbraucht einen Chain-Key und produziert einen frischen Message-Key, der nach Gebrauch sofort genullt wird. Tauschen Alice und Bob nebenher neue Ratchet-Public-Keys aus, dreht sich auch der Root-Chain weiter.

Double Ratchet KDF-Kette
Root-KDF und Chain-KDF im Zusammenspiel. Wer eine kompromittierte Sitzung übernimmt, bekommt nur die noch nicht verbrauchten Chain-Keys, nicht die vergangenen.

Sprache und Gruppenanrufe

Audio läuft am Server vorbei nie in einer Form, die der Server verarbeiten könnte. Bei 1:1-Anrufen kommt SRTP zum Einsatz: der Schlüssel wird beim Anruf-Setup über den bestehenden Rede-Kanal ausgetauscht, der Media-Stream ist Standard-WebRTC mit verschlüsselten Frames. Bei Gruppenanrufen tritt SFrame dazu und verankert die Verschlüsselung in der Frame-Schicht des SFU.

Audio-Pipeline mit SRTP-Verschlüsselung
Audio-Pipeline beim Senden und Empfangen. SRTP verschlüsselt zwischen den Endpunkten, der SFU sieht ausschließlich opake binäre Frames.

Trust on First Use

Beim Erstkontakt mit einem Rede-Server pinnt der Client zwei Dinge: die Ed25519-Server-Signatur und den TLS-Zertifikats-Fingerprint. Ändert sich danach eines von beiden, fährt der Client die Verbindung sofort herunter und blockiert weitere Versuche, bis der Nutzer den neuen Schlüssel ausdrücklich akzeptiert. Das ist das gleiche TOFU-Prinzip, das auch SSH-Clients seit Jahrzehnten anwenden.

Rede MITM-Warnung beim Hinzufügen eines Kontakts
Pinning in Aktion: bei geändertem Server-Zertifikat wird die Verbindung blockiert. Der Nutzer muss aktiv entscheiden, ob er den neuen Schlüssel akzeptiert.

Keine kryptografische Annahme bleibt in Rede ohne sichtbare Konsequenz im UI. Eine TOFU-Verletzung ist kein Warn-Dialog, den man wegklicken kann, sondern eine harte Pause.


Föderation und Selbst-Hosting

Ein Rede-Server kann standalone laufen oder per WireGuard-Sync mit anderen Knoten föderieren. Identitäten sind an ihren Heimat-Server gebunden, aber Konversationen über Server-Grenzen hinweg sind Teil des Protokolls. Wer eine eigene Instanz betreiben will, braucht eine Domain, ein TLS-Zertifikat und eine PostgreSQL- oder SQLite-Datenbank. Mehr nicht.

Lizenz

Rede steht unter der AGPL-3.0. Quellcode für Server und Clients ist offen einsehbar, Änderungen müssen unter derselben Lizenz veröffentlicht werden, sobald die geänderte Software für andere zugänglich gemacht wird, auch über das Netzwerk.

Dokumentation

Die ausführlichen technischen Dokumente liegen als PDF bereit.