JavaCard@KeePassDX: Difference between revisions

From
Jump to navigation Jump to search
Content deleted Content added
Weigtvin (talk | contribs)
initial entry; coarse description of the project
 
Weigtvin (talk | contribs)
neu: ergebnis, ausblick, vorarbeiten
 
Line 1: Line 1:
Dieser Artikel ist Teil des Studienprojekts:
Dieser Artikel ist Teil des Studienprojekts:
"JavaCard als Secure Element für FIDO2-Passkeys in KeePassDX".
"JavaCard als Secure Element für FIDO2-Passkeys in KeePassDX".
Der zugehörige Quellcode ist in der Gitlab-Instanz des CMS zu finden.
Der zugehörige Quellcode ist in der Gitlab-Instanz des CMS
zu finden.
<ref>https://scm.cms.hu-berlin.de/sar/javacard-keepassdx
<ref>https://scm.cms.hu-berlin.de/sar/javacard-keepassdx
abgerufen am 15.06.2026</ref>
abgerufen am 15.06.2026</ref>
Line 19: Line 20:
== Ist-Zustand ==
== Ist-Zustand ==


Für die Implementierung eines mobilen Schlüsselrings wurde der Open-Source-Passwortmanager KeePassDX ausgewählt.
Für die Implementierung eines mobilen Schlüsselrings wurde der Open-Source-Passwortmanager KeePassDX
<ref>https://github.com/Kunzisoft/KeePassDX
<ref>https://github.com/Kunzisoft/KeePassDX
abgerufen am 21.04.2026</ref>
abgerufen am 21.04.2026</ref>
ausgewählt.
Die Android-App verwaltet Datenbanken im KeePass-Format und unterstützt bereits Autofill sowie Passkeys.
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,
Zudem ermöglicht sie die Entsperrung einer KeePass-Datenbank mittels Yubikey,
Line 28: Line 30:
Da KeePassDX keine direkte Kommunikation mit Hardware-Keys unterstützt,
Da KeePassDX keine direkte Kommunikation mit Hardware-Keys unterstützt,
wurde vom Entwickler eine separate App,
wurde vom Entwickler eine separate App,
der „Hardware Key Driver“,
der „Hardware Key Driver“
entwickelt.
<ref>https://gitlab.com/kunzisoft/android-hardware-key-driver
<ref>https://gitlab.com/kunzisoft/android-hardware-key-driver
abgerufen am 26.04.2026</ref>
abgerufen am 26.04.2026</ref>,
entwickelt.
Bei der Entsperrung wird der Datenbank-Seed als Challenge an den Hardware-Key gesendet.
Bei der Entsperrung wird der Datenbank-Seed als Challenge an den Hardware-Key gesendet.
Dieser berechnet den HMAC-SHA1 der Challenge,
Dieser berechnet den HMAC-SHA1 der Challenge,
Line 43: Line 45:


Als Testumgebung diente ein Google Pixel 9a mit GrapheneOS (basierend auf Android 16).
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.
Die Funktionalität der Passkeys wurde mit dem Browser Vanadium auf der Seite 'webauthn.io' getestet.
Vanadium ist eine Chromium-Variante,
Vanadium ist eine Chromium-Variante,
die eine native Android-Autofill-Implementierung und Credential-Manager-Support für Passkeys nutzt,
die eine native Android-Autofill-Implementierung und Credential-Manager-Support für Passkeys nutzt,
Line 101: Line 103:
Der Initialisierungsvektor (IV) wird zufällig gewählt.
Der Initialisierungsvektor (IV) wird zufällig gewählt.
Anschließend wird über IV und Ciphertext ein HMAC berechnet.
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.
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,
Der AES-256-Schlüssel wird,
analog zum HMAC-Schlüssel,
analog zum HMAC-Schlüssel,
Line 114: Line 117:
Bei erfolgreicher Verifikation wird der Signaturschlüssel entschlüsselt und die Daten signiert.
Bei erfolgreicher Verifikation wird der Signaturschlüssel entschlüsselt und die Daten signiert.
Die Signatur wird anschließend als Antwort zurückgegeben.
Die Signatur wird anschließend als Antwort zurückgegeben.

== Ergebnis ==

Ein Ergebnis dieser Arbeit ist,
dass sich keine privaten Schlüssel im Klartext außerhalb der Smartcard befinden.
Die KeePass-Datenbank wird zwar verschlüsselt im persistenten Speicher des Geräts gehalten,
zur Nutzung der Datenbank muss diese jedoch entschlüsselt werden.
Dies bedeutet eventuell,
dass sich die Passkeys dann im Klartext im Speicher des Geräts befinden.
In diesem Fall wäre wohl der Zugriff durch das Betriebssystem möglich.
Es ist also Vertrauen in das Betriebssystem notwendig.
Bei der JavaCard-Lösung ist dieses Vertrauen nicht notwendig;
die Passkeys befinden sich zu keinem Zeitpunkt im Klartext auf dem Gerät.

Diese Lösung geht jedoch mit einer Einschränkung in der Nutzbarkeit einher,
da die Smartcard bei jedem Authentifizierungsvorgang dem Gerät präsentiert werden muss.
Dies könnte jedoch umgangen werden,
wenn das JavaCard-Applet nicht auf einer externen Java Card läuft,
sondern auf einem Secure Element innerhalb des Geräts;
dies könnte zum Beispiel eine eSIM sein.

Bei dieser Lösung fehlt die Verwaltung der Schlüssel,
mit denen die Passkeys verschlüsselt und authentisiert werden.
Diese werden auf der Karte generiert und lassen sich nicht exportieren.
Das bedeutet, dass bei Kartenverlust praktisch kein Zugriff mehr auf die KeePass-Datenbank möglich ist.

== Passwortunterstützung ==

Diese Lösung betrachtet ausschließlich Passkeys.
Keepass-Datenbanken speichern jedoch auch andere Credentials,
beispielsweise Passwörter.
Die Implementierung einer Passwort-Unterstützung ist denkbar.

Eine Keepass-Datenbank ist im Wesentlichen eine verschlüsselte XML-Datei.
<ref>https://palant.info/2023/03/29/documenting-keepass-kdbx4-file-format/</ref>
Die Passwörter liegen in dieser Datei nicht im Klartext vor,
sondern sind zusätzlich mit einer Stromchiffre verschlüsselt.
Der entsprechende Schlüssel ist ebenfalls in der XML-Datei hinterlegt.
Diese Verschlüsselung dient primär der Obfuskierung der Passwörter.

Eine Implementierung ist denkbar,
die anstelle des Schlüssels einen datenbankspezifischen Seed ablegt.
Dieser könnte an die JavaCard übertragen werden,
um daraus den Schlüssel abzuleiten.
Die Passwörter würden dann auf der JavaCard mit diesem abgeleiteten Schlüssel verschlüsselt
und in verschlüsselter Form in die Datenbank geschrieben.
Somit wäre eine Entschlüsselung der Passwörter ohne die JavaCard nicht mehr möglich,
selbst wenn die Datenbank insgesamt bereits entschlüsselt vorliegt.

== Vorarbeiten ==

Bevor mit der Arbeit an KeePassDX begonnen wurde,
wurden zunächst andere Ansätze getestet.
Diese sollen in diesem Abschnitt beschrieben werden.

=== Authnkey und Yubikey ===

Zunächst wurde die App Authnkey
<ref>https://github.com/mimi89999/Authnkey</ref>
ausprobiert.
Diese ermöglicht die Nutzung von FIDO2-Security-Keys über NFC unter Android.
Die App implementiert das CTAP2-Protokoll
<ref>https://fidoalliance.org/specifications/download/</ref>
direkt,
sodass keine Abhängigkeiten zu Google Play Services bestehen.

Die App ist im F-Droid Store
<ref>https://f-droid.org/packages/pl.lebihan.authnkey/</ref>
und als Fork im Google Play Store
<ref>https://play.google.com/store/apps/details?id=com.token2.fidobridge</ref>
verfügbar.

Die App wurde mit einem Yubikey getestet.
Zunächst wurde die FIDO-Konfiguration des Yubikey zurückgesetzt.
Dafür wurde der Yubikey Manager
<ref>https://developers.yubico.com/yubikey-manager/</ref>
installiert
und mit <code>ykman fido reset</code> alle FIDO-Credentials sowie die FIDO-PIN gelöscht.
Alternativ kann dazu die Yubikey Authenticator App für Android
<ref>https://www.yubico.com/products/yubico-authenticator/</ref>
verwendet werden,
die neben dem Play Store ebenfalls in F-Droid verfügbar ist.
<ref>https://f-droid.org/packages/com.yubico.yubioath/</ref>

Mit diesem Setup war eine Registrierung und Authentifizierung im Browser bei 'webauthn.io' möglich.
Dabei wurde ein Resident Key
<ref>https://developers.yubico.com/WebAuthn/WebAuthn_Developer_Guide/Resident_Keys.html</ref>
auf dem Yubikey erstellt.

Die Resident Keys werden im persistenten Speicher des Authenticators gespeichert.
Der Yubikey hat eine Kapazität von ungefähr 30 Resident Keys.
Verglichen mit der JavaCard-Lösung ist das sehr wenig,
da durch das Wrappen der Passkeys und deren Ablage auf dem Android-Gerät die Kapazität einige Größenordnungen größer ist.


== Referenzen ==
== Referenzen ==

Latest revision as of 13:37, 27 July 2026

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 [2] ausgewählt. 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“ [3], entwickelt. 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.

Ergebnis

Ein Ergebnis dieser Arbeit ist, dass sich keine privaten Schlüssel im Klartext außerhalb der Smartcard befinden. Die KeePass-Datenbank wird zwar verschlüsselt im persistenten Speicher des Geräts gehalten, zur Nutzung der Datenbank muss diese jedoch entschlüsselt werden. Dies bedeutet eventuell, dass sich die Passkeys dann im Klartext im Speicher des Geräts befinden. In diesem Fall wäre wohl der Zugriff durch das Betriebssystem möglich. Es ist also Vertrauen in das Betriebssystem notwendig. Bei der JavaCard-Lösung ist dieses Vertrauen nicht notwendig; die Passkeys befinden sich zu keinem Zeitpunkt im Klartext auf dem Gerät.

Diese Lösung geht jedoch mit einer Einschränkung in der Nutzbarkeit einher, da die Smartcard bei jedem Authentifizierungsvorgang dem Gerät präsentiert werden muss. Dies könnte jedoch umgangen werden, wenn das JavaCard-Applet nicht auf einer externen Java Card läuft, sondern auf einem Secure Element innerhalb des Geräts; dies könnte zum Beispiel eine eSIM sein.

Bei dieser Lösung fehlt die Verwaltung der Schlüssel, mit denen die Passkeys verschlüsselt und authentisiert werden. Diese werden auf der Karte generiert und lassen sich nicht exportieren. Das bedeutet, dass bei Kartenverlust praktisch kein Zugriff mehr auf die KeePass-Datenbank möglich ist.

Passwortunterstützung

Diese Lösung betrachtet ausschließlich Passkeys. Keepass-Datenbanken speichern jedoch auch andere Credentials, beispielsweise Passwörter. Die Implementierung einer Passwort-Unterstützung ist denkbar.

Eine Keepass-Datenbank ist im Wesentlichen eine verschlüsselte XML-Datei. [6] Die Passwörter liegen in dieser Datei nicht im Klartext vor, sondern sind zusätzlich mit einer Stromchiffre verschlüsselt. Der entsprechende Schlüssel ist ebenfalls in der XML-Datei hinterlegt. Diese Verschlüsselung dient primär der Obfuskierung der Passwörter.

Eine Implementierung ist denkbar, die anstelle des Schlüssels einen datenbankspezifischen Seed ablegt. Dieser könnte an die JavaCard übertragen werden, um daraus den Schlüssel abzuleiten. Die Passwörter würden dann auf der JavaCard mit diesem abgeleiteten Schlüssel verschlüsselt und in verschlüsselter Form in die Datenbank geschrieben. Somit wäre eine Entschlüsselung der Passwörter ohne die JavaCard nicht mehr möglich, selbst wenn die Datenbank insgesamt bereits entschlüsselt vorliegt.

Vorarbeiten

Bevor mit der Arbeit an KeePassDX begonnen wurde, wurden zunächst andere Ansätze getestet. Diese sollen in diesem Abschnitt beschrieben werden.

Authnkey und Yubikey

Zunächst wurde die App Authnkey [7] ausprobiert. Diese ermöglicht die Nutzung von FIDO2-Security-Keys über NFC unter Android. Die App implementiert das CTAP2-Protokoll [8] direkt, sodass keine Abhängigkeiten zu Google Play Services bestehen.

Die App ist im F-Droid Store [9] und als Fork im Google Play Store [10] verfügbar.

Die App wurde mit einem Yubikey getestet. Zunächst wurde die FIDO-Konfiguration des Yubikey zurückgesetzt. Dafür wurde der Yubikey Manager [11] installiert und mit ykman fido reset alle FIDO-Credentials sowie die FIDO-PIN gelöscht. Alternativ kann dazu die Yubikey Authenticator App für Android [12] verwendet werden, die neben dem Play Store ebenfalls in F-Droid verfügbar ist. [13]

Mit diesem Setup war eine Registrierung und Authentifizierung im Browser bei 'webauthn.io' möglich. Dabei wurde ein Resident Key [14] auf dem Yubikey erstellt.

Die Resident Keys werden im persistenten Speicher des Authenticators gespeichert. Der Yubikey hat eine Kapazität von ungefähr 30 Resident Keys. Verglichen mit der JavaCard-Lösung ist das sehr wenig, da durch das Wrappen der Passkeys und deren Ablage auf dem Android-Gerät die Kapazität einige Größenordnungen größer ist.

Referenzen