gematik lib-vau / lib-vau-csharp
AES-GCM-Nonce-Wiederverwendung in der VAU-Server-Verschlüsselung
lib-vau und lib-vau-csharp sind die Referenzimplementierungen des VAU-Protokolls von gematik — der Sicherheitsschicht, die den Datenverkehr zum Backend der elektronischen Patientenakte (ePA) Deutschlands schützt und seit 2025 für die rund 73 Millionen gesetzlich Versicherten im Einsatz ist, sofern sie nicht widersprochen haben. Der VAU-Server in beiden Referenzimplementierungen verwendet den vom Client gelieferten Request-Counter-Wert als 64-Bit-Counter-Teil seines eigenen AES-GCM-Initialisierungsvektors, anstatt einen unabhängigen serverseitigen Verschlüsselungscounter zu führen, wie es gemSpec_Krypt A_24631 und A_24632 verlangen. Die IV-Eindeutigkeit reduziert sich auf die 4 zufälligen Bytes, die der Server voranstellt, sodass der verschlüsselte Server-zu-Client-Kanal nach ~77.163 Antworten mit gleichem Counter in Reichweite des Joux Forbidden Attack gerät. Erfasst als MS-LIB-VAU-774212 (Java) und MS-LIB-VAU-CSHARP-60819d (C#).
Beschreibung
Die VAU-Protokollspezifikation (gemSpec_Krypt V2.40.0) verlangt in A_24631, dass der Server seinen eigenen unabhängigen 64-Bit-Verschlüsselungscounter für den Application-Data-Key K2_s2c_app_data führt. Der Counter muss bei 0 beginnen und vor jeder Verschlüsselung inkrementiert werden. A_24632 spezifiziert weiter, dass der AES-GCM-IV des Servers als random(4) || server_encryption_counter(8) konstruiert wird, während das Request-Counter-Feld im Antwort-Header separat den vom Client gespeicherten Wert aus A_24630 zurückspiegelt.
Beide Referenzimplementierungen weichen davon ab. VauServerStateMachine hat kein serverseitiges Counter-Feld und überschreibt die Verschlüsselungsmethode nicht. getRequestCounter() auf der Server-Seite gibt clientRequestCounter zurück — den aus der jüngsten Client-Anfrage gespeicherten Wert — und derselbe Wert wird sowohl für das Request-Counter-Feld im Antwort-Header als auch für den AES-GCM-IV verwendet.
In der Java-Referenzimplementierung (lib-vau) verwendet der Server den Counter des Clients für den IV:
lib-vau VauServerStateMachine.java:181-184
@Overrideprotected long getRequestCounter() { return clientRequestCounter;}Der Server speichert den vom Client gelieferten Counter ohne Monotonie- oder Replay-Prüfung:
lib-vau VauServerStateMachine.java:191-194
@Overrideprotected void checkRequestCounter(long reqCtr) { this.clientRequestCounter = reqCtr;}Die IV-Konstruktion verwendet getRequestCounter() für den Counter-Teil:
lib-vau AbstractVauStateMachine.java:112-122
public byte[] encryptVauMessage(byte[] cleartext) { byte[] reqCtrBytes = ByteBuffer.allocate(8).putLong(getRequestCounter()).array(); byte[] header = unionByteArrays(versionByte, puByte, reqByte, reqCtrBytes, getKeyId()); byte[] a = new byte[4]; new SecureRandom().nextBytes(a); byte[] iv = unionByteArrays(a, reqCtrBytes);}Im Gegensatz dazu inkrementiert die Client-Seite ihren eigenen Counter korrekt vor jeder Verschlüsselung, was zeigt, dass das fehlende serverseitige Inkrement asymmetrisch ist:
lib-vau VauClientStateMachine.java:169-173
@Overridepublic byte[] encryptVauMessage(byte[] cleartext) { try { requestCounter++; return super.encryptVauMessage(cleartext);Die C#-Referenzimplementierung (lib-vau-csharp) trägt dieselbe Logik und erzeugt denselben Effekt:
lib-vau-csharp VauServerStateMachine.cs:58-70
protected override void CheckRequestCounter(long requestCounter){ clientRequestCounter = requestCounter;}
protected override long GetRequestCounter(){ return clientRequestCounter;}lib-vau-csharp AbstractVauStateMachine.cs:47-98
public virtual byte[] EncryptVauMessage(byte[] plaintext){ long requestCounter = GetRequestCounter(); // ... byte[] iv = new byte[12]; // iv[0..4] = random // iv[4..12] = requestCounter (client-supplied)}Da A_24623 in der aktuellen ePA-Ausbaustufe Replay-Schutz und Sequenzordnung explizit nicht erzwingt (ERP=false, ESO=false), kann ein Client jeden Counter-Wert senden, den er möchte — einschließlich eines bereits verwendeten. Die GCM-Nonce-Eindeutigkeit der Server-Antworten hängt dann nur von den 32 Zufallsbits ab, die der Server voranstellt.
Nach dem Geburtstagsparadoxon wächst die Kollisionswahrscheinlichkeit für das 4-Byte-Zufallspräfix schnell, wenn der Counter-Teil konstant gehalten wird:
Geburtstags-Kollisionswahrscheinlichkeit bei konstantem 64-Bit-Counter
Nachrichten P(IV-Kollision) 100 < 0,01 % 1.000 0,01 % 10.000 1,16 % 50.000 25,23 % 77.163 50,00 % 100.000 68,55 %AES-GCM bietet bei Nonce-Wiederverwendung keine Vertraulichkeits- oder Integritätsgarantien mehr. Der Joux Forbidden Attack (2006) erlaubt einem Angreifer, der zwei unter demselben Schlüssel und IV verschlüsselte Ciphertexte beobachtet, aus den beiden Authentifizierungs-Tags den GHASH-Authentifizierungsschlüssel H zu rekonstruieren und durch XOR der beiden Ciphertexte Klartext-Bytes zurückzugewinnen.
Auswirkung
- In ePA-Begriffen umfassen die Payloads, die die innere VAU-Schicht schützt, Medikationsdaten, Diagnoseberichte, Verordnungshistorien, Dokumenten-Reads und -Writes sowie die Autorisierungstransaktionen, die den Zugriff auf eine Patientenakte steuern. Die folgenden beiden Effekte betreffen genau diese Payloads.
- Ein legitimer VAU-Client (oder ein Angreifer im Netzwerk, der einen VAU-Handshake abgeschlossen hat) kann den Counter-Teil des Server-IV konstant halten, indem er einen Request-Counter-Wert wiederverwendet, und so lange Server-Antworten sammeln, bis zwei denselben 12-Byte-IV teilen.
- Sobald zwei Antworten denselben IV teilen, rekonstruiert der Joux Forbidden Attack den GHASH-Authentifizierungsschlüssel
H. MitHkann der Angreifer das GCM-Authentifizierungs-Tag für Ciphertexte unter jedem IV fälschen, für den eine Kollision beobachtet wurde, und so Server-zu-Client-VAU-Nachrichten in einer Sitzung mit fortlaufender Nonce-Wiederverwendung manipulieren. - Das XOR der beiden kollidierenden Ciphertexte ergibt das XOR der beiden Klartexte und gibt damit Informationen über die durch die innere VAU-AES-GCM-Schicht geschützten ePA-Antwort-Payloads preis.
- Oberhalb der inneren VAU-Schicht existiert zwar weiterhin TLS zum ePA-Backend, doch die innere VAU-Schicht ist die Eigenschaft, mit der das ePA-Bedrohungsmodell Patientendaten gegen die Kompromittierung von TLS-Infrastruktur außerhalb der TEE-Grenze schützt. Das Brechen dieser Schicht entfernt diese Defense-in-Depth-Grenze.
- In Kombination mit der fehlenden Server-Authentifizierung (MS-LIB-VAU-eaea8d) ist die Position des Angreifers nicht hypothetisch. Ein MITM, der während des Handshakes seine eigenen Schlüssel eingeschleust hat, kann den Client-Request-Counter bei jeder weitergeleiteten Anfrage auf einen festen Wert fixieren — und reduziert damit die Kollisionssammlung von einem aktiven Angriff auf passive Beobachtung eines Kanals, den der Angreifer bereits kontrolliert.
Abhilfe
Konsumenten, die eine der Bibliotheken produktiv einsetzen, sollten einen unabhängigen serverEncryptionCounter zu VauServerStateMachine (oder dessen C#-Äquivalent) hinzufügen, ihn auf 0 initialisieren und encryptVauMessage() so überschreiben, dass dieser Counter vor der Verschlüsselung inkrementiert wird. Eine reine Überschreibung von getRequestCounter() reicht nicht aus — super.encryptVauMessage() verwendet den Rückgabewert sowohl für den IV als auch für den Header, sodass der Server encryptVauMessage() vollständig überschreiben muss, um die beiden Counter-Verwendungen explizit zu trennen. Die Überschreibung muss gemäß A_24632 zwei unterschiedliche Counter-Werte verwenden: den eigenen Counter des Servers für den Counter-Teil des IV und den gespeicherten Client-Wert für das Request-Counter-Feld im Antwort-Header. Bis diese Änderung umgesetzt ist, sollte der innere VAU-Server-zu-Client-Kanal so behandelt werden, als biete er Integrität und Vertraulichkeit nur in der Größenordnung von 2^32 Nachrichten pro Sitzung, bevor die GCM-Garantien nachlassen.
Checkliste für Betreiber
Prüfen, ob Sie lib-vau / lib-vau-csharp ausliefern.
Wenn Ihr ePA-Client (oder irgendein Produkt, das VAU spricht) lib-vau oder lib-vau-csharp direkt, über einen Fork oder über ein Git-Submodul einbindet, betrifft Sie die Lücke. Die Java-Bibliothek wurde von mindestens einem produktiven Konsumenten unverändert übernommen (med-united/epa4all); prüfen Sie Ihren eigenen Abhängigkeitsbaum, bevor Sie davon ausgehen, nicht betroffen zu sein.
Einen serverseitigen Counter in Ihrem Build hinzufügen.
Überschreiben Sie
encryptVauMessage()des Servers so, dass ein unabhängiger 64-Bit-Counter geführt, vor jeder Verschlüsselung inkrementiert und genau dieser Counter (nicht der Wert des Clients) für den Counter-Teil des IV verwendet wird. Lassen Sie das Request-Counter-Feld im Antwort-Header gemäß A_24632 weiterhin den Client-Wert zurückspiegeln.Sitzungslänge als Sicherheitsparameter behandeln.
Bis ein serverseitiger Counter etabliert ist, rotieren Sie VAU-Sitzungen deutlich unterhalb der 2^32-Nachrichten-Grenze. Die IV-Kollisionswahrscheinlichkeit übersteigt bereits bei rund 10.000 Antworten mit gleichem Counter die 1-Prozent-Schwelle; das ist Ihre operative Marge.
Auf dem Server gesehene Request-Counter-Werte protokollieren.
Auch wenn Sie das Protokollverhalten nicht ändern, ist ein Counter, der sich innerhalb einer Sitzung über viele Antworten hinweg wiederholt oder rückwärts läuft, erkennbar. Erfassen und prüfen Sie ihn; dieselbe Metrik deckt fehlkonfigurierte Clients und aktiven Missbrauch ab.
Bewertung im Detail
Referenzen
- gemSpec_Krypt V2.40.0 (A_24631, A_24632, A_24623)
- NIST SP 800-38D (AES-GCM)
- Joux (2006) — Authentication Failures in NIST version of GCM
- gematik-lib-vau-Repository (Java)
- gematik-lib-vau-csharp-Repository
- Verwandt: Fehlende VAU-Server-Authentifizierung (MS-LIB-VAU-eaea8d)
- Verwandt: ePA-VAU-Client-Sicherheit (Übersicht)
So können wir helfen
Wer wir sind
Die Sicherheitsforscher hinter diesem Sicherheitshinweis.

Dr. rer. nat. Simon Weber
Senior Pentester & MedSec-Forscher
Ich evaluiere Ihr SaMD mit derselben branchenprägenden Sicherheitsexpertise, die ich dem BAK MV für die Überarbeitung des B3S-Standards beigetragen habe.
- Promotion über Krankenhaus-Cybersicherheit
- Kritische Schwachstellen in Krankenhaussystemen gefunden
- Alumni der THB MedSec-Forschungsgruppe
- gematik Security Hero

Dipl.-Inf. Volker Schönefeld
Senior Application Security Expert
Als ehemaliger CTO und Entwickler, der zum Pentester wurde, arbeite ich mit Ihrem Team zusammen, um Schwachstellen aufzudecken und Lösungen zu finden, die zu Ihrer Architektur passen.
- 20+ Jahre als CTO, 50+ Mio. App-Downloads
- Architektur und Absicherung großer IoT-Flotten
- Certified Web Exploitation Specialist
- gematik Security Hero
Penetrationstest gesucht?
Machine Spirits ist spezialisiert auf Sicherheitsbewertungen für Medizinprodukte und Gesundheits-IT. Von MDR-Penetrationstests bis C5-Cloud-Compliance helfen wir MedTech-Unternehmen, regulatorische Anforderungen zu erfüllen.
