Mit dem Android Keystore-System können Sie kryptografische Schlüssel in einem Container speichern, um das Entfernen von Geräten zu erschweren. Sobald sich Schlüssel im Schlüsselspeicher befinden, können Sie sie für kryptografische Vorgänge verwenden. Das Schlüsselmaterial kann jedoch nicht exportiert werden. Außerdem können Sie mit dem Keystore-System einschränken, wann und wie Schlüssel verwendet werden können, z. B. die Nutzerauthentifizierung für die Schlüsselnutzung erfordern oder die Verwendung von Schlüsseln auf bestimmte kryptografische Modi beschränken. Weitere Informationen finden Sie im Abschnitt Sicherheitsfunktionen.
Das Keystore-System wird von der KeyChain
API verwendet, die in Android 4.0 (API-Level 14) eingeführt wurde, sowie von der Android Keystore-Anbieterfunktion, die in Android 4.3 (API-Level 18) eingeführt wurde. In diesem Dokument wird beschrieben, wann und wie Sie das Android Keystore-System verwenden.
Sicherheitsfunktionen
Das Android Keystore-System schützt Schlüsselmaterial auf zwei Arten vor unbefugter Verwendung. Erstens wird das Risiko einer unbefugten Verwendung von Schlüsselmaterial außerhalb des Android-Geräts verringert, da das Schlüsselmaterial nicht aus Anwendungsprozessen und nicht aus dem Android-Gerät insgesamt extrahiert werden kann. Zweitens reduziert das Schlüsselspeichersystem das Risiko einer unbefugten Nutzung von Schlüsselmaterial auf dem Android-Gerät, indem Apps die autorisierten Verwendungen ihrer Schlüssel angeben und diese Einschränkungen dann außerhalb der Prozesse der Apps erzwingen.
Extraktion verhindern
Das Schlüsselmaterial von Android Keystore-Schlüsseln wird durch zwei Sicherheitsmaßnahmen vor dem Extrahieren geschützt:
- Schlüsselmaterial wird nie in den Anwendungsvorgang aufgenommen. Wenn eine App kryptografische Vorgänge mit einem Android-Schlüsselspeicherschlüssel ausführt, werden im Hintergrund Klartext, Geheimtext und zu signierende oder zu verifizierende Nachrichten an einen Systemprozess übergeben, der die kryptografischen Vorgänge ausführt. Wenn der Prozess der App manipuliert wird, kann der Angreifer möglicherweise die Schlüssel der App verwenden, aber nicht das Schlüsselmaterial extrahieren, um es beispielsweise außerhalb des Android-Geräts zu verwenden.
- Schlüsselmaterial kann an die sichere Hardware des Android-Geräts gebunden werden, z. B. an die Trusted Execution Environment (TEE) oder an ein Secure Element (SE). Wenn diese Funktion für einen Schlüssel aktiviert ist, wird das Schlüsselmaterial niemals außerhalb sicherer Hardware freigegeben. Wenn das Android-Betriebssystem manipuliert wurde oder ein Angreifer den internen Speicher des Geräts lesen kann, kann er möglicherweise die Android Keystore-Schlüssel einer beliebigen App auf dem Android-Gerät verwenden, sie aber nicht vom Gerät extrahieren. Diese Funktion ist nur aktiviert, wenn die sichere Hardware des Geräts die jeweilige Kombination aus Schlüsselalgorithmus, Blockmodus, Padding-Schema und Hashwert unterstützt, für die der Schlüssel verwendet werden darf.
Wenn Sie prüfen möchten, ob die Funktion für einen Schlüssel aktiviert ist, rufen Sie
KeyInfo
für den Schlüssel ab. Der nächste Schritt hängt von der SDK-Zielversion Ihrer App ab:- Wenn Ihre App auf Android 10 (API-Level 29) oder höher ausgerichtet ist, prüfen Sie den Rückgabewert von
getSecurityLevel()
. Rückgabewerte, die mitKeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT
oderKeyProperties.SecurityLevelEnum.STRONGBOX
übereinstimmen, geben an, dass sich der Schlüssel auf sicherer Hardware befindet. - Wenn Ihre App auf Android 9 (API-Level 28) oder niedriger ausgerichtet ist, prüfen Sie den booleschen Rückgabewert von
KeyInfo.isInsideSecurityHardware()
.
- Wenn Ihre App auf Android 10 (API-Level 29) oder höher ausgerichtet ist, prüfen Sie den Rückgabewert von
Hardwaresicherheitsmodul
Unterstützte Geräte mit Android 9 (API-Level 28) oder höher können einen StrongBox Keymaster haben, eine Implementierung der Keymaster- oder Keymint-HAL, die sich in einem Secure Element befindet, das einem Hardware Security Module ähnelt. Hardwaresicherheitsmodule können sich auf viele verschiedene Implementierungen des Schlüsselspeichers beziehen, bei denen ein Linux-Kernel-Kompromittierungsversuch nicht auf sie zugreifen kann, z. B. TEE. StrongBox bezieht sich ausdrücklich auf Geräte wie eingebettete sichere Elemente (eSE) oder sichere On-SoC-Verarbeitungseinheiten (iSE).
Das Modul enthält Folgendes:
- Eigene CPU
- Sichere Speicherung
- Ein echter Zufallszahlengenerator
- Zusätzliche Mechanismen zum Schutz vor Manipulation von Paketen und nicht autorisiertem Sideloading von Apps
- Ein sicherer Timer
- Ein Neustart-Benachrichtigungspin (oder ein vergleichbarer Pin), z. B. ein GPIO (General Purpose Input/Output)
Zur Unterstützung von Low-Power-StrongBox-Implementierungen wird eine Teilmenge von Algorithmen und Schlüsselgrößen unterstützt:
- RSA-2048
- AES 128 und 256
- ECDSA, ECDH P-256
- HMAC-SHA256 (unterstützt Schlüsselgrößen zwischen 8 Byte und 64 Byte)
- Triple DES
- APDUs mit erweiterter Länge
- Schlüsselattestierung
- Unterstützung für Upgrade gemäß Änderung H
Wenn Sie Schlüssel mit der Klasse KeyStore
generieren oder importieren, können Sie angeben, dass der Schlüssel im StrongBox Keymaster gespeichert werden soll. Dazu übergeben Sie true
an die Methode setIsStrongBoxBacked()
.
Obwohl StrongBox im Vergleich zu TEE etwas langsamer und ressourcenbeschränkt ist (d. h., es werden weniger gleichzeitige Vorgänge unterstützt), bietet StrongBox bessere Sicherheitsgarantien gegen physische und Side-Channel-Angriffe. Wenn Sie höhere Sicherheitsgarantien gegenüber der Effizienz von App-Ressourcen priorisieren möchten, empfehlen wir die Verwendung von StrongBox auf den Geräten, auf denen es verfügbar ist. Wenn StrongBox nicht verfügbar ist, kann Ihre App zum Speichern von Schlüsselmaterialien immer auf TEE zurückgreifen.
Autorisierungen für die Schlüsselverwendung
Um eine unbefugte Verwendung von Schlüsseln auf dem Android-Gerät zu vermeiden, können Apps mit Android Keystore beim Generieren oder Importieren von Schlüsseln autorisierte Verwendungen ihrer Schlüssel angeben. Nachdem ein Schlüssel generiert oder importiert wurde, können seine Autorisierungen nicht mehr geändert werden. Autorisierungen werden dann vom Android Keystore erzwungen, wenn der Schlüssel verwendet wird. Dies ist eine erweiterte Sicherheitsfunktion, die im Allgemeinen nur dann nützlich ist, wenn Ihre Anforderungen besagen, dass eine Manipulation Ihres Anwendungsprozesses nach der Schlüsselgenerierung/dem Schlüsselimport (aber nicht davor oder währenddessen) nicht zu einer unbefugten Verwendung des Schlüssels führen darf.
Die unterstützten Autorisierungen für die Schlüsselnutzung fallen in die folgenden Kategorien:
- Kryptografie: Der Schlüssel kann nur mit autorisierten Schlüsselalgorithmen, Vorgängen oder Zwecken (Verschlüsseln, Entschlüsseln, Signieren, Verifizieren), Padding-Schemata, Blockmodi oder Digests verwendet werden.
- Zeitliches Gültigkeitsintervall:Der Schlüssel darf nur innerhalb eines bestimmten Zeitraums verwendet werden.
- Nutzerauthentifizierung:Der Schlüssel kann nur verwendet werden, wenn sich der Nutzer in letzter Zeit authentifiziert hat. Weitere Informationen finden Sie unter Nutzerauthentifizierung für die Schlüsselnutzung erforderlich machen.
Als zusätzliche Sicherheitsmaßnahme für Schlüssel, deren Schlüsselmaterial sich in sicherer Hardware befindet (siehe KeyInfo.isInsideSecurityHardware()
oder für Apps, die auf Android 10 (API-Level 29) oder höher ausgerichtet sind, KeyInfo.getSecurityLevel()
), werden einige Autorisierungen zur Schlüsselnutzung je nach Android-Gerät möglicherweise von der sicheren Hardware erzwungen.
Sichere Hardware erzwingt normalerweise kryptografische und Nutzerauthentifizierungsautorisierungen. Bei sicherer Hardware werden jedoch in der Regel keine Autorisierungen für zeitliche Gültigkeitsintervalle erzwungen, da sie normalerweise keine unabhängige, sichere Echtzeituhr haben.
Mit KeyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware()
können Sie prüfen, ob die Autorisierung der Nutzerauthentifizierung eines Schlüssels von der sicheren Hardware erzwungen wird.
Zwischen einem Schlüsselbund und dem Android Keystore-Anbieter wählen
Verwenden Sie die KeyChain
API, wenn Sie systemweite Anmeldedaten benötigen. Wenn eine App die Verwendung von Anmeldedaten über die KeyChain
API anfordert, können Nutzer über eine vom System bereitgestellte Benutzeroberfläche auswählen, auf welche der installierten Anmeldedaten eine App zugreifen darf. So können mehrere Apps mit der Einwilligung des Nutzers dieselben Anmeldedaten verwenden.
Mit dem Android Keystore-Anbieter können Sie einer einzelnen App erlauben, eigene Anmeldedaten zu speichern, auf die nur diese App zugreifen kann.
So können Apps Anmeldedaten verwalten, die nur von ihnen verwendet werden können, und gleichzeitig dieselben Sicherheitsvorteile nutzen, die die KeyChain
API für systemweite Anmeldedaten bietet.
Bei dieser Methode müssen die Anmeldedaten nicht vom Nutzer ausgewählt werden.
Android Keystore-Anbieter verwenden
Für diese Funktion verwenden Sie die Standardklassen KeyStore
und KeyPairGenerator
oder KeyGenerator
zusammen mit dem AndroidKeyStore
-Anbieter, der in Android 4.3 (API-Ebene 18) eingeführt wurde.
AndroidKeyStore
ist als KeyStore
-Typ für die Verwendung mit der KeyStore.getInstance(type)
-Methode und als Anbieter für die Verwendung mit den Methoden KeyPairGenerator.getInstance(algorithm, provider)
und KeyGenerator.getInstance(algorithm, provider)
registriert.
Da kryptografische Vorgänge zeitaufwendig sein können, sollten Apps AndroidKeyStore
nicht im Hauptthread verwenden, damit die Benutzeroberfläche der App reaktionsschnell bleibt. Mit StrictMode
können Sie Orte finden, an denen dies nicht der Fall ist.
Neuen privaten oder geheimen Schlüssel generieren
Wenn Sie eine neue KeyPair
mit einer PrivateKey
generieren möchten, müssen Sie die ursprünglichen X.509-Attribute des Zertifikats angeben. Mit KeyStore.setKeyEntry()
können Sie das Zertifikat später durch ein von einer Zertifizierungsstelle signiertes Zertifikat ersetzen.
Verwenden Sie zum Generieren des Schlüsselpaars KeyPairGenerator
mit KeyGenParameterSpec
:
Kotlin
/* * Generate a new EC key pair entry in the Android Keystore by * using the KeyPairGenerator API. The private key can only be * used for signing or verification and only with SHA-256 or * SHA-512 as the message digest. */ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore" ) val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY ).run { setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) build() } kpg.initialize(parameterSpec) val kp = kpg.generateKeyPair()
Java
/* * Generate a new EC key pair entry in the Android Keystore by * using the KeyPairGenerator API. The private key can only be * used for signing or verification and only with SHA-256 or * SHA-512 as the message digest. */ KeyPairGenerator kpg = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); kpg.initialize(new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .build()); KeyPair kp = kpg.generateKeyPair();
Verschlüsselte Schlüssel in sichere Hardware importieren
Unter Android 9 (API-Level 28) und höher können Sie verschlüsselte Schlüssel mit einem ASN.1-codierten Schlüsselformat sicher in den Keystore importieren. Der Keymaster entschlüsselt dann die Schlüssel im Schlüsselspeicher, sodass der Inhalt der Schlüssel nie als Klartext im Hostspeicher des Geräts angezeigt wird. Dieser Prozess bietet zusätzliche Sicherheit bei der Schlüsselentschlüsselung.
Führen Sie die folgenden Schritte aus, um den sicheren Import verschlüsselter Schlüssel in den Schlüsselspeicher zu unterstützen:
Generieren Sie ein Schlüsselpaar mit dem Zweck
PURPOSE_WRAP_KEY
. Wir empfehlen, auch diesem Schlüsselpaar eine Attestierung hinzuzufügen.Erstellen Sie auf einem vertrauenswürdigen Server oder Computer die ASN.1-Nachricht für die
SecureKeyWrapper
.Der Wrapper enthält das folgende Schema:
KeyDescription ::= SEQUENCE { keyFormat INTEGER, authorizationList AuthorizationList } SecureKeyWrapper ::= SEQUENCE { wrapperFormatVersion INTEGER, encryptedTransportKey OCTET_STRING, initializationVector OCTET_STRING, keyDescription KeyDescription, secureKey OCTET_STRING, tag OCTET_STRING }
Erstelle ein
WrappedKeyEntry
-Objekt und übergebe die ASN.1-Nachricht als Byte-Array.Übergeben Sie dieses
WrappedKeyEntry
-Objekt an die Überladung vonsetEntry()
, die einKeystore.Entry
-Objekt akzeptiert.
Mit Keystore-Einträgen arbeiten
Sie können über alle standardmäßigen KeyStore
APIs auf den AndroidKeyStore
-Anbieter zugreifen.
Einträge auflisten
Rufen Sie die Methode aliases()
auf, um Einträge im Schlüsselspeicher aufzulisten:
Kotlin
/* * Load the Android KeyStore instance using the * AndroidKeyStore provider to list the currently stored entries. */ val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val aliases: Enumeration<String> = ks.aliases()
Java
/* * Load the Android KeyStore instance using the * AndroidKeyStore provider to list the currently stored entries. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); Enumeration<String> aliases = ks.aliases();
Daten signieren und bestätigen
Daten signieren, indem du die KeyStore.Entry
aus dem Schlüsselspeicher abrufst und die Signature
APIs verwendest, z. B. sign()
:
Kotlin
/* * Use a PrivateKey in the KeyStore to create a signature over * some data. */ val ks: KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val entry: KeyStore.Entry = ks.getEntry(alias, null) if (entry !is KeyStore.PrivateKeyEntry) { Log.w(TAG, "Not an instance of a PrivateKeyEntry") return null } val signature: ByteArray = Signature.getInstance("SHA256withECDSA").run { initSign(entry.privateKey) update(data) sign() }
Java
/* * Use a PrivateKey in the KeyStore to create a signature over * some data. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); return null; } Signature s = Signature.getInstance("SHA256withECDSA"); s.initSign(((PrivateKeyEntry) entry).getPrivateKey()); s.update(data); byte[] signature = s.sign();
Prüfen Sie die Daten auch mit der verify(byte[])
-Methode:
Kotlin
/* * Verify a signature previously made by a private key in the * KeyStore. This uses the X.509 certificate attached to the * private key in the KeyStore to validate a previously * generated signature. */ val ks = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val entry = ks.getEntry(alias, null) as? KeyStore.PrivateKeyEntry if (entry == null) { Log.w(TAG, "Not an instance of a PrivateKeyEntry") return false } val valid: Boolean = Signature.getInstance("SHA256withECDSA").run { initVerify(entry.certificate) update(data) verify(signature) }
Java
/* * Verify a signature previously made by a private key in the * KeyStore. This uses the X.509 certificate attached to the * private key in the KeyStore to validate a previously * generated signature. */ KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); ks.load(null); KeyStore.Entry entry = ks.getEntry(alias, null); if (!(entry instanceof PrivateKeyEntry)) { Log.w(TAG, "Not an instance of a PrivateKeyEntry"); return false; } Signature s = Signature.getInstance("SHA256withECDSA"); s.initVerify(((PrivateKeyEntry) entry).getCertificate()); s.update(data); boolean valid = s.verify(signature);
Nutzerauthentifizierung für die Schlüsselnutzung erforderlich machen
Wenn Sie einen Schlüssel generieren oder in die AndroidKeyStore
importieren, können Sie angeben, dass der Schlüssel nur verwendet werden darf, wenn der Nutzer authentifiziert wurde. Der Nutzer wird mit einem Teil seiner sicheren Sperrbildschirm-Anmeldedaten (Muster/PIN/Passwort, biometrische Anmeldedaten) authentifiziert.
Dies ist eine erweiterte Sicherheitsfunktion, die in der Regel nur dann nützlich ist, wenn Ihre Anforderungen besagen, dass ein manipulierter Anwendungsvorgang nach der Schlüsselgenerierung/dem Schlüsselimport (aber nicht davor oder währenddessen) die Anforderung nicht umgehen kann, dass der Nutzer für die Verwendung des Schlüssels authentifiziert werden muss.
Wenn ein Schlüssel nur dann verwendet werden darf, wenn sich der Nutzer authentifiziert hat, kannst du setUserAuthenticationParameters()
aufrufen, um ihn für einen der folgenden Modi zu konfigurieren:
- Autorisierung für einen bestimmten Zeitraum
- Alle Schlüssel sind zur Verwendung autorisiert, sobald sich der Nutzer mit einer der angegebenen Anmeldedaten authentifiziert.
- Autorisierung für die Dauer eines bestimmten kryptografischen Vorgangs
Jeder Vorgang, der einen bestimmten Schlüssel umfasst, muss vom Nutzer einzeln autorisiert werden.
Ihre App startet diesen Vorgang, indem sie
authenticate()
auf einer Instanz vonBiometricPrompt
aufruft.
Für jeden Schlüssel, den Sie erstellen, können Sie starke biometrische Anmeldedaten, Anmeldedaten für den Sperrbildschirm oder beide Anmeldedatentypen unterstützen. Rufe canAuthenticate()
auf, um zu prüfen, ob der Nutzer die Anmeldedaten eingerichtet hat, auf die der Schlüssel deiner App angewiesen ist.
Wenn ein Schlüssel nur biometrische Anmeldedaten unterstützt, wird er standardmäßig ungültig, wenn neue biometrische Registrierungen hinzugefügt werden. Sie können den Schlüssel so konfigurieren, dass er gültig bleibt, wenn neue biometrische Registrierungen hinzugefügt werden. Übergeben Sie dazu false
an setInvalidatedByBiometricEnrollment()
.
Weitere Informationen zum Hinzufügen von Funktionen für die biometrische Authentifizierung in Ihre App, einschließlich der Anzeige eines Dialogfelds für die biometrische Authentifizierung
Unterstützte Algorithmen
Cipher
KeyGenerator
KeyFactory
KeyStore
(unterstützt dieselben Schlüsseltypen wieKeyGenerator
undKeyPairGenerator
)KeyPairGenerator
Mac
Signature
SecretKeyFactory
Blogartikel
Weitere Informationen finden Sie im Blogpost Umstellung des Zugriffs auf den Schlüsselspeicher in ICS.