JavaCard@KeePassDX
Dieser Artikel ist Teil des Studienprojekts: "JavaCard als Secure Element für FIDO2-Passkeys in KeePassDX". Der zugehörige Quellcode ist in der Gitlab-Instanz des CMS zu finden. [1]
Ziel
Ziel des Studienprojekts ist die Nutzung einer Smartcard als Zugangsmittel für einen mobilen Schlüsselring, der Credentials über die Autofill-Funktion an Anwendungen bereitstellt. Hierfür soll die Smartcard-Funktionalität in einen bestehenden Passwortmanager integriert werden. Neben der Entschlüsselung des Masterpassworts soll ein verschlüsselter Datenblob an die Smartcard übermittelt werden, um alle kryptografischen Operationen auf dieser auszuführen. Das Interface zwischen Smartcard und Passwortmanager wird eigens definiert; standardisierte Interfaces werden nicht verwendet. Während die Passwortdatenbank mit der Smartcard entsperrt wird, erfolgt die Freigabe von Passkeys schlüsselindividuell.
Ist-Zustand
Für die Implementierung eines mobilen Schlüsselrings wurde der Open-Source-Passwortmanager KeePassDX ausgewählt. [2] Die Android-App verwaltet Datenbanken im KeePass-Format und unterstützt bereits Autofill sowie Passkeys. Zudem ermöglicht sie die Entsperrung einer KeePass-Datenbank mittels Yubikey, sofern dieser das Challenge-Response-Verfahren mit HMAC-SHA1 unterstützt.
Da KeePassDX keine direkte Kommunikation mit Hardware-Keys unterstützt, wurde vom Entwickler eine separate App, der „Hardware Key Driver“, entwickelt. [3] Bei der Entsperrung wird der Datenbank-Seed als Challenge an den Hardware-Key gesendet. Dieser berechnet den HMAC-SHA1 der Challenge, und die Response fließt in die Schlüsselableitung ein. Die Verbindung zum Yubikey erfolgt über USB oder NFC.
KeePassDX kann als Credential Provider in den Android-Einstellungen konfiguriert werden, um Passkeys in der Datenbank zu speichern. Bei der Registrierung eines neuen Passkeys wird dieser gespeichert; bei der Authentifizierung bei einem bekannten Dienst kann nach der Datenbankentsperrung der gespeicherte Passkey ausgewählt werden.
Als Testumgebung diente ein Google Pixel 9a mit GrapheneOS (basierend auf Android 16). Die Funktionalität der Passkeys wurde mit dem Browser Vanadium auf der Seite `webauthn.io` getestet. Vanadium ist eine Chromium-Variante, die eine native Android-Autofill-Implementierung und Credential-Manager-Support für Passkeys nutzt, wodurch keine Google Play Services erforderlich sind. [4]
Mit dieser Konfiguration waren die Registrierung und Authentifizierung mit Passkeys erfolgreich. Die Entsperrung einer Datenbank mit einem Yubikey war jedoch nicht möglich.
Entsperrung einer Datenbank mit einer JavaCard
Das erste Ziel bestand darin, eine JavaCard als Hardware-Key zur Datenbankentsperrung zu nutzen. Da diese Funktionalität für Yubikeys in KeePassDX bereits implementiert war, wurde auf Seiten des Passwortmanagers lediglich ein neuer Hardware-Token-Typ hinzugefügt. Die weitere Implementierung basierte weitgehend auf der vorhandenen Logik mit entsprechenden Anpassungen.
Zusätzlich wurde ein JavaCard-Applet entwickelt, welches das Challenge-Response-Verfahren implementiert. Als Algorithmus wurde HMAC-SHA256 gewählt. Da die verfügbare JavaCard diesen Algorithmus nicht nativ unterstützte, wurde eine eigene Implementierung in einer separaten Klasse erstellt, die auch von anderen Applets genutzt werden kann. Diese unterstützt ausschließlich Schlüssellängen von 256 Bit.
Bei der Installation des Applets wird ein zufälliger 256-Bit-Schlüssel generiert, der nicht exportierbar ist. Die Challenge muss eine Länge von 32 Byte aufweisen. Der HMAC-SHA256 wird mit dem bei der Installation generierten Schlüssel berechnet. Die Response hat ebenfalls eine Länge von 32 Byte und wird als Antwort zurückgesendet.
Bei der Erstellung einer neuen Datenbank in KeePassDX kann die Verwendung eines Hardware-Keys gewählt werden, wobei nun zwischen Yubikey und JavaCard unterschieden werden kann. Bei Auswahl der JavaCard muss diese bei jeder Entsperrung über NFC mit dem Gerät verbunden werden. Da der HMAC-Schlüssel nicht exportierbar ist, ist eine Entschlüsselung der Datenbank im Falle des Verlusts der Karte oder einer Neuinstallation des Applets praktisch nicht mehr möglich.
Signaturerstellung auf der JavaCard
Das nächste Ziel bestand darin, kryptografische Operationen, die bei der Nutzung von Credentials in Software durchgeführt werden, auf der JavaCard auszuführen. Der Fokus lag hierbei auf Passkeys.
Bei der Erstellung eines Passkeys wird ein Schlüsselpaar generiert. Als Signaturalgorithmus wurde ECDSA-SHA-256 gewählt, da die JavaCard ML-DSA und EdDSA nicht unterstützt. Webauthn.io priorisiert die Algorithmen in der Reihenfolge ML-DSA, EdDSA, ECDSA-SHA-256 und RSA-Signaturen. [5]
Das JavaCard-Applet wurde um eine Instruktion zur Generierung eines ECDSA-Schlüsselpaars erweitert. Vor der Rückgabe wird der private Schlüssel auf der Karte mit AES-256-CBC verschlüsselt. Der Initialisierungsvektor (IV) wird zufällig gewählt. Anschließend wird über IV und Ciphertext ein HMAC berechnet. Die Antwort der Instruktion umfasst den öffentlichen Schlüssel im Klartext, den IV, den privaten Schlüssel als Ciphertext, sowie den HMAC. Der AES-256-Schlüssel wird, analog zum HMAC-Schlüssel, bei der Installation des Applets zufällig generiert.
Zusätzlich wurde eine Instruktion zur Signaturerstellung auf der JavaCard implementiert. Da die Signaturschlüssel nicht auf der Karte gespeichert werden, müssen der verschlüsselte private Schlüssel (bestehend aus IV, Ciphertext und HMAC) sowie die zu signierenden Daten auf die Karte übertragen werden. Zunächst wird der HMAC verifiziert. Bei erfolgreicher Verifikation wird der Signaturschlüssel entschlüsselt und die Daten signiert. Die Signatur wird anschließend als Antwort zurückgegeben.
Referenzen
- ↑ https://scm.cms.hu-berlin.de/sar/javacard-keepassdx abgerufen am 15.06.2026
- ↑ https://github.com/Kunzisoft/KeePassDX abgerufen am 21.04.2026
- ↑ https://gitlab.com/kunzisoft/android-hardware-key-driver abgerufen am 26.04.2026
- ↑ https://grapheneos.org/features#vanadium abgerufen am 13.04.2026
- ↑ https://github.com/duo-labs/webauthn.io/blob/b35f262688149b95cade28c2ec8d1d1c7190decd/_app/homepage/services/registration.py#L79-L112 abgerufen am 17.05.2026