Aktualisiert

Zero-Knowledge-Verschlüsselung: Wie Vaulted deine Geheimnisse privat hält

Von

Zero-Knowledge-Verschlüsselung bedeutet, dass der Server niemals deinen Klartext oder deine Verschlüsselungsschlüssel zu sehen bekommt. Vaulted setzt das um, indem jedes Geheimnis in deinem Browser mit AES-256-GCM verschlüsselt wird, bevor irgendwelche Daten den Server erreichen. Der Server speichert ausschließlich Geheimtext — er hat keinen Zugriff auf den Entschlüsselungsschlüssel, der ausschließlich im URL-Fragment lebt.

Dieser Artikel erklärt die genaue kryptografische Implementierung: wie Schlüssel erzeugt werden, wie Daten verschlüsselt werden, wie der Schlüssel beim Empfänger ankommt und was passiert, wenn du eine Passphrase hinzufügst. Jedes Detail hier spiegelt den tatsächlichen Code wider, der in deinem Browser läuft.

Eine Übersicht darüber, warum clientseitige Verschlüsselung wichtig ist, findest du in unserem früheren Artikel über clientseitige Verschlüsselung. Dieser Artikel geht tiefer in die kryptografischen Primitive.

Schlüsselerzeugung

Jedes Mal, wenn du ein Geheimnis erstellst, erzeugt Vaulted mithilfe der Web Crypto API einen frischen AES-256-GCM-Verschlüsselungsschlüssel:

crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, [
  'encrypt',
  'decrypt',
]);

Ein paar Dinge, die es zu beachten gilt:

  • AES-GCM (Galois/Counter Mode) bietet sowohl Vertraulichkeit als auch Integrität — er erkennt Manipulationen, nicht nur unbefugtes Lesen.
  • 256-Bit-Schlüssellänge ist die stärkste verfügbare Option für AES und wird von Regierungen und Finanzinstituten weltweit eingesetzt.
  • Extractable: true — der Schlüssel kann als rohe Bytes exportiert werden, damit er für den Empfänger ins URL-Fragment gelegt werden kann.

Die Web Crypto API delegiert an die native kryptografische Engine des Browsers (z. B. BoringSSL in Chromium, NSS in Firefox). Der Schlüssel wird sicher im Arbeitsspeicher erzeugt und berührt weder Festplatte noch Netzwerk.

Verschlüsselung

Mit dem erzeugten Schlüssel verschlüsselt Vaulted deinen Klartext:

const iv = crypto.getRandomValues(new Uint8Array(12));

crypto.subtle.encrypt(
  { name: 'AES-GCM', iv },
  key,
  new TextEncoder().encode(plaintext),
);

Der Initialisierungsvektor (IV): AES-GCM erfordert für jede Verschlüsselungsoperation einen zufälligen 12-Byte-(96-Bit-)IV. Der IV muss nicht geheim sein — er wird zusammen mit dem Geheimtext gespeichert —, darf aber mit demselben Schlüssel niemals wiederverwendet werden. Da Vaulted für jedes Geheimnis einen neuen Schlüssel erzeugt, ist eine IV-Wiederverwendung konstruktionsbedingt unmöglich.

Kodierung: Sowohl der Geheimtext als auch der IV werden als base64url-Strings kodiert (Standard-base64, bei dem + durch -, / durch _ ersetzt und abschließende = entfernt werden). Das macht sie sicher für die Verwendung in URLs und JSON-Payloads.

Der verschlüsselte Geheimtext und der IV werden zur Speicherung an den Server gesendet. Der Klartext verlässt den Browser niemals.

Schlüsselübermittlung per URL-Fragment

Nach der Verschlüsselung wird der Schlüssel exportiert und ins URL-Fragment gelegt — den Teil nach #:

const rawKey = await crypto.subtle.exportKey('raw', key);
// rawKey → base64url-encoded string

Der resultierende verschlüsselte Link sieht so aus:

https://vaulted.fyi/s/abc123#dGhpcyBpcyBhIGtleQ
                              ^^^^^^^^^^^^^^^^^^^^^^^^
                              encryption key (base64url)

Das #-Trennzeichen ist entscheidend. Gemäß RFC 3986 wird der Fragment-Bezeichner vollständig vom Client verarbeitet. Browser schließen das Fragment niemals in HTTP-Anfragen ein — weder in der URL noch im Referer-Header noch an irgendeiner Stelle, die der Server sehen könnte.

Wenn der Empfänger den Link öffnet:

  1. Der Browser fragt /s/abc123 beim Server an (ohne Fragment)
  2. Der Server gibt den Geheimtext und den IV zurück
  3. JavaScript liest das Fragment aus window.location.hash
  4. Der Schlüssel wird wieder in die Web Crypto API importiert
  5. Der Geheimtext wird lokal entschlüsselt

Der Server ermöglicht die Speicherung und den Abruf des verschlüsselten Blobs. Er nimmt niemals an den kryptografischen Operationen teil.

Optionaler Passphrasen-Schutz

Für Geheimnisse, die zusätzlichen Schutz benötigen, unterstützt Vaulted passphrasenbasiertes Key Wrapping. Das fügt eine zweite Schicht hinzu: Selbst wenn jemand den Link abfängt, kann er das Geheimnis ohne die Passphrase nicht entschlüsseln.

Schlüsselableitung mit PBKDF2

Wenn du eine Passphrase festlegst, leitet Vaulted einen Wrapping-Schlüssel mithilfe von PBKDF2 ab:

crypto.subtle.deriveKey(
  {
    name: 'PBKDF2',
    salt, // 16 bytes, randomly generated
    iterations: 600_000,
    hash: 'SHA-256',
  },
  keyMaterial, // the passphrase, imported as raw key material
  { name: 'AES-KW', length: 256 },
  false,
  ['wrapKey', 'unwrapKey'],
);
  • 600.000 Iterationen machen Brute-Force-Angriffe rechenintensiv.
  • 16-Byte-Zufallssalt stellt sicher, dass identische Passphrasen bei verschiedenen Geheimnissen unterschiedliche abgeleitete Schlüssel erzeugen.
  • SHA-256 ist die Hash-Funktion, die in jeder PBKDF2-Iteration verwendet wird.
  • Der abgeleitete Schlüssel ist ein AES-KW-Schlüssel (AES Key Wrap, RFC 3394), kein AES-GCM-Schlüssel. Key Wrapping ist eine eigenständige Operation, die sich von der Verschlüsselung unterscheidet.

Den Verschlüsselungsschlüssel einwickeln

Der abgeleitete AES-KW-Schlüssel wickelt den ursprünglichen Verschlüsselungsschlüssel ein:

crypto.subtle.wrapKey('raw', encryptionKey, wrappingKey, 'AES-KW');

Das URL-Fragment enthält nun sowohl den eingewickelten Schlüssel als auch den Salt, getrennt durch einen Punkt:

#wrappedKeyBase64url.saltBase64url

Auswickeln beim Entschlüsseln

Wenn der Empfänger die Passphrase eingibt, kehrt Vaulted den Prozess um:

  1. Das Fragment wird am . aufgeteilt, um den eingewickelten Schlüssel und den Salt zu erhalten
  2. Derselbe AES-KW-Wrapping-Schlüssel wird mit PBKDF2 aus der Passphrase und dem Salt abgeleitet
  3. Der Verschlüsselungsschlüssel wird mit crypto.subtle.unwrapKey ausgewickelt
  4. Der Geheimtext wird mit dem ausgewickelten AES-GCM-Schlüssel entschlüsselt

Wenn die Passphrase falsch ist, wirft unwrapKey einen Fehler — es gibt keine partielle Entschlüsselung oder Informationslecks.

Entschlüsselungsablauf

Ohne Passphrase ist die Entschlüsselung unkompliziert:

  1. Den Schlüssel aus dem URL-Fragment importieren (crypto.subtle.importKey)
  2. Den Geheimtext mit dem IV entschlüsseln (crypto.subtle.decrypt)
  3. Den Klartext aus den UTF-8-Bytes dekodieren

Mit einer Passphrase:

  1. Das Fragment aufteilen, um den eingewickelten Schlüssel und den Salt zu extrahieren
  2. Den Wrapping-Schlüssel aus der Passphrase und dem Salt ableiten (PBKDF2)
  3. Den Verschlüsselungsschlüssel auswickeln (AES-KW)
  4. Den Geheimtext entschlüsseln (AES-GCM)
  5. Den Klartext dekodieren

All das passiert im Browser. Der Server gibt den verschlüsselten Blob und Metadaten zurück (Aufrufzähler, Ablaufzeit) — mehr nicht.

Bedrohungsmodell

Kein Sicherheitswerkzeug schützt gegen alles. Hier ist, wogegen die Architektur von Vaulted ausgelegt ist und was außerhalb ihres Anwendungsbereichs liegt.

Wogegen Vaulted schützt

  • Kompromittierter Server — Der Server speichert nur verschlüsselten Geheimtext. Ohne den Schlüssel (der niemals an den Server gesendet wird) sind die Daten unlesbar. Ein vollständiger Datenbankdump liefert nur verschlüsselte Blobs.
  • Datenbankeinbruch — Wie oben. Geheimtext ohne Schlüssel ist mit AES-256-GCM rechnerisch wertlos.
  • Man-in-the-Middle auf der Serverseite — Der Verschlüsselungsschlüssel lebt im URL-Fragment, das niemals in HTTP-Anfragen übermittelt wird. TLS schützt den Geheimtext während der Übertragung.
  • Dienstbetreiber lesen Geheimnisse — Zero-Knowledge bedeutet genau das. Wir können deine Geheimnisse nicht lesen, selbst wenn wir dazu gezwungen würden, weil wir die Schlüssel nicht haben.

Wogegen Vaulted NICHT schützt

  • Kompromittierter Browser oder kompromittiertes Gerät — Wenn das Gerät des Empfängers Malware oder einen Keylogger enthält, kann der entschlüsselte Klartext nach der Entschlüsselung abgefangen werden.
  • Bösartige Browser-Erweiterungen — Erweiterungen mit Seitenzugriff können das DOM nach der Entschlüsselung lesen, einschließlich des enthüllten Geheimnisses.
  • Link-Abfangen — Die URL enthält den Verschlüsselungsschlüssel im Fragment. Wer die vollständige URL (einschließlich Fragment) erhält, kann das Geheimnis entschlüsseln. Teile Links über sichere Kanäle.
  • Schulter-Surfen — Sobald das Geheimnis auf dem Bildschirm angezeigt wird, kann jeder, der zuschaut, es sehen.
  • Verhalten des Empfängers — Nach der Entschlüsselung kann der Empfänger einen Screenshot machen, den Klartext kopieren oder weitergeben. Vaulted kann das nicht verhindern.

Die Passphrasen-Funktion mindert das Risiko des Link-Abfangens: Selbst mit der vollständigen URL benötigt der Angreifer noch die Passphrase. Teile die Passphrase über einen anderen Kanal (ein Telefonat, eine separate Nachricht) für eine Defense-in-Depth-Strategie.

Zusammenfassung

Die Zero-Knowledge-Verschlüsselung von Vaulted bedeutet:

  1. Für jedes Geheimnis wird ein frischer AES-256-GCM-Schlüssel erzeugt
  2. Die Verschlüsselung findet vollständig in deinem Browser statt
  3. Der Server speichert nur verschlüsselten Geheimtext
  4. Der Entschlüsselungsschlüssel reist ausschließlich im URL-Fragment, das Browser niemals an Server senden
  5. Optionales Passphrasen-Wrapping fügt via PBKDF2 und AES-KW eine zweite Schicht hinzu

Das Ergebnis: Selbst wenn alle Server, Datenbanken und Netzwerkpfade gleichzeitig kompromittiert würden, bleiben deine Geheimnisse verschlüsselt. Die Schlüssel existieren nur in den Links, die du teilst.


Bereit, ein Geheimnis sicher zu teilen? Erstelle ein Geheimnis auf Vaulted — es dauert 10 Sekunden.


Verwandte Artikel