So funktioniert unsere Ende-zu-Ende-Verschlüsselung
Stand: Juni 2026
Kurz gesagt
- Deine Daten werden auf deinem Gerät verschlüsselt und verlassen es nur als unlesbarer Chiffretext. Unser Server speichert ausschließlich verschlüsselte Blobs und hat keinen Zugriff auf den Klartext.
- Alle Schlüssel werden aus einem 128-Bit-Recovery-Code abgeleitet, der dein Gerät nie verlässt. Wir kennen ihn nicht und können ihn nicht wiederherstellen.
- Jeder einzelne Record wird mit einem eigenen Schlüssel verschlüsselt und vor der Entschlüsselung auf Echtheit geprüft (Verify-before-Decrypt mit Ed25519).
- E2EE schützt nicht alles: Bestimmte Metadaten (Datenmenge, Zugriffszeiten) bleiben sichtbar, und ein kompromittiertes Gerät oder ein verlorener Recovery-Code lässt sich nicht durch Kryptographie retten.
Was „Ende-zu-Ende" bei uns bedeutet
Ende-zu-Ende-Verschlüsselung heißt: Der Klartext deiner Daten existiert nur auf deinen eigenen Geräten. Die Ver- und Entschlüsselung passiert ausschließlich lokal. Was zwischen Geräten synchronisiert und auf unserem Server abgelegt wird, ist immer schon verschlüsselt, bevor es das Gerät verlässt.
Konkret: Eine Datenzeile wird auf dem Client kanonisch zu JSON kodiert und dann mit einem AEAD-Verfahren verschlüsselt. Der Server empfängt nur einen opaken Byte-Blob plus einige Verwaltungsfelder. Er besitzt keinen der Schlüssel, die zum Entschlüsseln nötig wären. Das ist eine architektonische Eigenschaft, kein Versprechen: Da die Schlüssel das Gerät nie erreichen, kann der Server den Inhalt technisch nicht lesen.
Klicke auf die Komponenten für Details:
Gerät A (Sender)
Daten werden lokal auf dem Gerät mit AES-256-GCM verschlüsselt. Der Recovery-Code und alle abgeleiteten Schlüssel verlassen das Gerät nie.
Wie deine Daten verschlüsselt werden
Wir verwenden bewährte, standardisierte Bausteine aus den Bibliotheken @noble/ciphers, @noble/hashes und @noble/curves:
- AES-256-GCM verschlüsselt deine Records. AES-256-GCM ist ein AEAD-Verfahren, das gleichzeitig Vertraulichkeit (niemand liest mit) und Integrität (Manipulation fällt auf) sichert. Jeder Record nutzt eine zufällige 12-Byte-Nonce und einen 16-Byte-Authentifizierungscode (MAC). Format: nonce(12) ‖ ciphertext ‖ mac(16).
- XChaCha20-Poly1305 verschlüsselt das Schlüsselmaterial beim Geräte-Pairing (Key-Wrapping). Es ist ebenfalls ein AEAD-Verfahren, nutzt aber eine längere 24-Byte-Nonce, was zufällige Nonces unkritisch macht.
- AAD (Associated Data) bindet jeden Chiffretext an seine Metadaten — Header, Bucket, Record-UUID, Revision, Key-Epoch, Schema-Version und paddierte Länge. Diese Felder sind mitauthentifiziert: Wird auch nur eines verändert, schlägt die Entschlüsselung fehl. Leere AAD wird hart abgelehnt (Confused-Deputy-Schutz).
- Padding verschleiert die genaue Größe: Jeder Record wird auf eine Bucket-Größe aufgefüllt (256, 1024, 4096, 16384 oder 65536 Bytes; darüber Vielfache von 65536). So verrät die Blob-Größe nur eine grobe Klasse, nicht die exakte Datenmenge.
- Ed25519-Signatur (blob_sig) signiert jeden Blob. Vor jeder Entschlüsselung prüft der Client diese Signatur gegen die autorisierten Geräteschlüssel (Verify-before-Decrypt). Die Prüfung läuft RFC-8032-strikt (zip215:false), was Fälschungen über Low-Order-Punkte ausschließt. Manipulierte Daten ergeben sofort einen Fehler, keinen stillen Defekt.
Deine Schlüssel bleiben auf deinem Gerät
Die Wurzel von allem ist eine 128-Bit-Recovery-Entropie — der Recovery-Code. Aus diesen 16 zufälligen Bytes wird mit HKDF-SHA256 (eine Schlüsselableitungsfunktion, die aus einem Geheimnis viele domänengetrennte Schlüssel erzeugt) deterministisch ein Master-Secret abgeleitet und daraus weitere Schlüssel: eine Account-ID, ein Key-Encryption-Key, der Auth-Schlüssel (authSeed) und der Routing-Schlüssel. Jede Ableitung nutzt ein eigenes, versioniertes Label (z. B. mypep/master/v1), sodass sich die Schlüssel nicht überschneiden.
Pro Collection gibt es einen eigenen Collection-Key, und pro Record und Revision einen eigenen Record-Key (rec/<uuid>/<rev>). Dieser eigene Schlüssel je (Record, Revision) sorgt für eine vollständige Schlüssel-Trennung: Kein AES-GCM-Schlüssel wird je zweimal verwendet — ein starker Schutz gegen Nonce-Reuse-Angriffe.
Das Master-Secret wird bewusst nicht gespeichert. Lokal liegen nur die abgeleiteten Werte und die geräteeigenen Signier-/Wrap-Schlüssel — im Browser in IndexedDB.
Klicke auf einen Schlüssel für Details:
Recovery-Code
128-Bit Zufallsentropie. Der absolute Wurzel-Schlüssel. Wird bei Account-Erstellung generiert und dem Nutzer gezeigt. Verlässt das Gerät nie.
Recovery — Feature und Verantwortung: Der gesamte Schlüsselbaum hängt am Recovery-Code. Wir speichern ihn nicht; eine Hintertür, ein Key-Escrow oder ein serverseitiger Reset sind architektonisch ausgeschlossen — nicht nur per Richtlinie, sondern weil die Schlüssel den Server technisch nie erreichen. Das ist der Kern echter E2EE: Niemand außer dir — auch wir nicht — kann deine Daten ohne den Recovery-Code oder ein gepairtes Gerät wiederherstellen. Geht der Code verloren und existiert kein gekoppeltes Gerät mehr, sind die Daten endgültig unzugänglich.
Was unser Server sieht — und was nicht
Der Server speichert nur verschlüsselte Blobs. Er sieht nicht: den Inhalt deiner Records, die Namen deiner Collections (sie erscheinen nur als opaker HMAC-SHA256-Bucket) oder deine Schlüssel.
Ehrlich gesagt sieht er aber einige Metadaten: die opaken Bucket-Werte, die Record-Revisionen, die grobe Größenklasse über das Padding, die Synchronisations-Häufigkeit, Geräte-IDs (als SHA-256-Hash der Geräteschlüssel) und die Cursor-Position beim Abgleich. Daraus lässt sich ableiten, dass ein Account aktiv ist und ungefähr wie viele bzw. wie große Daten wann bewegt werden — nicht aber, worum es inhaltlich geht.
Die Konfliktauflösung läuft rein über Revisionen (höhere Revision gewinnt, „Last-Write-Wins"), weil der Server den Inhalt nicht kennt und nicht inhaltlich zusammenführen kann. Authentifizierung erfolgt per Challenge-Response mit Ed25519 und einem anschließenden JWT-Token; die Device-Liste wird mit deinem Auth-Schlüssel signiert und ausschließlich clientseitig verifiziert.
Mehrere Geräte (Pairing)
Ein neues Gerät, etwa der Browser, wird per QR-Code mit dem Phone gekoppelt. Der QR überträgt die öffentlichen Geräteschlüssel des Browsers direkt (out-of-band), nicht über den Server — das schützt den Schlüsseltausch vor Man-in-the-Middle-Angriffen. Das Phone verpackt das Identity-Bundle (Account-Daten-Schlüssel, Auth-Schlüssel, Account-ID, Routing-Schlüssel) per X25519-ECDH und XChaCha20-Poly1305 ausschließlich für den Browser und überträgt es verschlüsselt.
Nach dem Entschlüsseln zeigt der Browser einen Fingerprint (SHA-256 der Account-ID, als Hex-Gruppen). Stimmt er mit der Anzeige auf dem Phone überein, ist sichergestellt, dass du das richtige Bundle empfangen hast. Web-Clients haben keinen eigenen Recovery-Code: Bei Verlust des Browser-Speichers koppelst du einfach erneut mit dem Phone.
Geräte-Pairing Ablauf
Der Browser generiert temporäre Geräteschlüssel und zeigt diese als QR-Code. Das Smartphone scannt ihn direkt ab. Da dies direkt per Kamera geschieht (out-of-band), ist der Schlüsseltausch immun gegen Man-in-the-Middle-Angriffe.
Was das NICHT schützt
E2EE ist stark, aber kein Allheilmittel. Ehrlich zu den Grenzen:
- Kompromittiertes Gerät: Schadsoftware im Browser-Kontext oder direkter Zugriff auf IndexedDB kann die lokal gespeicherten Schlüssel lesen und damit alles entschlüsseln. Die lokale Datenbank liegt im Klartext vor.
- Verlorener Recovery-Code: Ohne Code und ohne gekoppeltes Gerät gibt es keinen Weg zurück. Es existiert keine Schlüsselrotation und kein Backup-Mechanismus.
- Metadaten: Datenmengen, Größenklassen, Zugriffsmuster und Zeitpunkte bleiben für den Server sichtbar.
- Foto-Blobs: Fotos sind content-adressiert (
blob_id = sha256(blob)). Wer einen Klartext bereits besitzt, kann prüfen, ob genau dieses Foto hochgeladen wurde. - Bösartiger Server: Er kann den Inhalt nicht lesen oder fälschen (Verify-before-Decrypt schützt), aber er könnte Daten zurückhalten oder alte signierte Device-Listen erneut ausliefern (Replay). Der Schaden eines solchen Replays ist begrenzt: Das Gerät registriert sich idempotent, sodass eine zurückgespielte alte Liste den aktuellen Zustand nicht überschreibt. Neue gültige Daten erfinden kann der Server nicht.
- Auth-Schlüssel: Wer den Auth-Schlüssel erlangt, kann die Device-Liste ändern und sich re-authentifizieren. Er muss geheim bleiben.
Die kryptographischen Bausteine im Überblick
- AES-256-GCM — Record-Verschlüsselung (AEAD); 12-Byte-Nonce, 16-Byte-MAC.
- XChaCha20-Poly1305 — Key-Wrapping beim Pairing (AEAD); 24-Byte-Nonce, 16-Byte-MAC.
- Argon2id v1.3 — passwortbasierte, speicherharte Ableitung (Standard: 64 MiB, 3 Iterationen, 4 Lanes); verfügbar für künftige passwortbasierte Funktionen, aber NICHT für den Recovery-Code — der ist bereits 128 Bit Zufallsentropie und braucht keine Speicher-Härte.
- HKDF-SHA256 — Ableitung aller Schlüssel aus dem Recovery-Code, domänengetrennt über versionierte Labels; 32-Byte-Output.
- HMAC-SHA256 — opakes Routing der Collections (Bucket-Berechnung).
- SHA-256 — Hashing für Fingerprints, Geräte-IDs und Foto-Adressierung.
- Ed25519 (RFC-8032-strikt, zip215:false) — Signaturen für Records, Device-Liste und Authentifizierung.
- X25519-ECDH — Schlüsselaustausch beim Geräte-Pairing.
- Padding-Buckets (256 B bis 65536 B, darüber Vielfache von 65536) — Größenverschleierung.
- Schlüssellänge durchgehend 32 Bytes (256 Bit).