Android Keystore est un mécanisme système sous Android permettant de stocker en toute sécurité des clés cryptographiques dans un isolement matériel. Le système utilise Trusted Execution Environment (TEE) sur les appareils avec ARM TrustZone ou un Secure Element dédié pour protéger les clés au niveau de la puce. Selon Android Open Source Project, Keystore prend en charge les algorithmes RSA, EC, AES et HMAC avec génération de clés directement dans l'environnement sécurisé.
Points clés
Android Keystore est un fournisseur cryptographique implémenté dans Android depuis l'API 1 (Android 1.0), mais le support matériel complet est apparu avec Android 4.3 (API 18). Keystore résout le problème du stockage sécurisé des clés privées de sorte que même si le système d'exploitation est compromis, un attaquant ne puisse pas extraire les clés en texte clair.
L'architecture Android Keystore se compose de trois niveaux : l'API applicative (java.security.KeyStore), le service système (keystore daemon) et le niveau matériel (Keymaster HAL). L'application accède via l'API standard Java Cryptography Architecture (JCA), et le service système achemine les requêtes vers Keymaster exécuté dans TEE.
Toutes les opérations cryptographiques avec les clés (signature, déchiffrement) sont effectuées dans TEE ou Secure Element. Les clés ne quittent jamais l'environnement sécurisé — l'application reçoit seulement un handle (alias) pour référencer la clé. C'est une différence fondamentale avec les KeyStores logiciels où les clés sont potentiellement accessibles dans la mémoire du processus.
Le JKS (Java KeyStore) standard ou BKS (Bouncy Castle) stockent les clés dans des fichiers protégés par mot de passe. Android Keystore stocke les clés dans un isolement matériel, où elles sont protégées même de l'utilisateur root. JKS est vulnérable à l'accès direct au système de fichiers ; Android Keystore ne l'est pas.
Autre différence : dans Android Keystore, les clés ont des paramètres d'utilisation stricts (purpose — uniquement sign/verify/encrypt/decrypt) spécifiés à la génération. Ils ne peuvent pas être modifiés ultérieurement, ce qui empêche l'utilisation abusive de la clé.
Lors de la création d'une nouvelle clé, l'application appelle KeyPairGenerator ou KeyGenerator avec KeyGenParameterSpec, qui contient tous les paramètres de la future clé. Le système transmet la requête à Keymaster HAL, qui génère la clé dans TEE et retourne un handle.
La méthode KeyGenParameterSpec.Builder accepte des paramètres obligatoires : nom de la clé dans Keystore, objet (PURPOSE_SIGN, PURPOSE_ENCRYPT), algorithme (RSA, EC, AES). Supplémentaires : digest (SHA-256), padding (PKCS7), userAuthenticationRequired (biométrie), keyValidityStart/End (restrictions temporelles).
Après définition des paramètres, KeyPairGenerator.generateKeyPair() retourne une KeyPair, où PrivateKey est un objet déléguant les opérations à Keymaster. La clé publique peut être extraite, la clé privée non. Elle existe seulement dans TEE.
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
fun generateKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
.setUserAuthenticationRequired(true)
.build()
val kpGen = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
kpGen.initialize(spec)
kpGen.generateKeyPair()
}
Signature pour ECDSA ou RSA-PSS est créée via l'API standard : Signature.getInstance(algorithm).initSign(privateKey). L'opération de signature est exécutée dans TEE : l'application transmet les données, Keymaster les signe matériellement et retourne la signature. La clé et les données ne se mélangent pas dans la mémoire partagée.
Pour la protection biométrique, l'utilisateur doit s'authentifier via BiometricPrompt avant de signer. Sans authentification réussie, Keymaster n'exécute pas l'opération et retourne CryptoAuthenticationException.
import java.security.KeyStore
import java.security.Signature
import androidx.biometric.BiometricPrompt
fun signWithBiometric(alias: String) {
val ks = KeyStore.getInstance("AndroidKeyStore")
ks.load(null)
val entry = ks.getEntry(alias, null) as KeyStore.PrivateKeyEntry
val signature = Signature.getInstance("SHA256withRSA")
signature.initSign(entry.privateKey)
// BiometricPrompt avec CryptoObject(signature) demande FaceID/PIN
}
Android prend en charge deux modes de stockage de clés : logiciel (sur les appareils sans TEE) et matériel (sur les appareils avec TEE ou Secure Element). Le mode dépend des capacités du SoC et de la version d'Android.
Sur les appareils sans Trusted Execution Environment (antérieurs à Android 4.3 ou SoCs d'entrée de gamme), les clés sont stockées chiffrées à l'aide d'une clé maître dérivée du mot de passe de l'écran de verrouillage. Ce mode est moins sûr — les clés sont accessibles dans la mémoire du processus lors des opérations cryptographiques.
Le niveau de protection est basé sur le chiffrement du fichier KeyStore avec AES-256-GCM. La clé de chiffrement est générée à partir du mot de passe ou du code PIN de l'utilisateur via Scrypt (PBKDF2 avec un nombre élevé d'itérations).
Sur les appareils modernes, Keymaster 4.x est utilisé dans TEE (ARM TrustZone). Les clés sont générées, stockées et utilisées exclusivement dans TrustZone. Même le noyau Linux n'a pas accès aux clés privées — seul Keymaster HAL peut effectuer des opérations.
Secure Element (par exemple, eSE dans Samsung Knox ou StrongBox dans Google Pixel 3+) est une puce séparée avec son propre processeur et sa propre mémoire. Il est certifié Common Criteria EAL 4+ et offre le niveau de protection maximal, y compris la protection contre l'altération physique.
| Type | Emplacement de stockage | Niveau de protection | Disponible depuis API |
|---|---|---|---|
| Logiciel | Fichier /data/misc/keystore | Moyen (AES-256) | API 1+ |
| Keymaster 3 | TEE (TrustZone) | Élevé | API 23+ |
| Keymaster 4 | TEE + Secure I/O | Très élevé | API 28+ |
| StrongBox | Secure Element matériel | Maximum | API 28+, optionnel |
Android Keystore est intégré dans Java Cryptography Architecture (JCA). Pour accéder au fournisseur, on utilise KeyStore.getInstance("AndroidKeyStore"). L'API est disponible depuis l'API 18.
La méthode KeyStore.load(null) charge le conteneur KeyStore de l'application. Aucun mot de passe n'est requis — Android utilise le contexte de l'application et son UID pour le contrôle d'accès. Chaque application voit seulement ses propres entrées, sauf si un UID partagé est utilisé.
Les méthodes setEntry et getEntry fonctionnent avec KeyStore.PrivateKeyEntry, SecretKeyEntry ou TrustedCertificateEntry. Le paramètre ProtectionParameter est toujours null pour Android Keystore (la protection est implémentée au niveau système).
import java.security.KeyStore
import java.security.cert.Certificate
import android.security.keystore.KeyProtection
fun storeSecretKey(alias: String, key: SecretKey) {
val ks = KeyStore.getInstance("AndroidKeyStore")
ks.load(null)
val prot = KeyProtection.Builder(
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.build()
ks.setEntry(alias, KeyStore.SecretKeyEntry(key), prot)
}
À l'aide de KeyCharacteristics, on peut déterminer dans quel environnement la clé est stockée : KeyStore logiciel, TEE ou StrongBox. La méthode getKeyCharacteristics() retourne un ensemble de drapeaux : FLAG_HARDWARE (keymaster), FLAG_SECURE_ELEMENT (StrongBox), FLAG_TRUSTED_USER_PRESENCE_REQUIRED (biométrie).
Android Keystore prend en charge une large gamme d'algorithmes cryptographiques divisés en trois catégories : asymétriques, symétriques et MAC. La prise en charge d'algorithmes spécifiques dépend de la version de Keymaster HAL.
RSA (1024–4096 bits) — pour la signature (PKCS1, PSS) et le chiffrement (OAEP, PKCS1). EC (P-224, P-256, P-384, P-521) — pour la signature ECDSA et l'échange de clés ECDH. AES (128, 256 bits) — pour le chiffrement symétrique en modes CBC, CTR, GCM. HMAC (SHA1, SHA256, SHA512) — pour l'authentification de messages.
Pour chaque clé, setPurposes est spécifié pour restreindre les opérations possibles. Une clé RSA avec PURPOSE_SIGN ne peut pas être utilisée pour le chiffrement, même si un attaquant a accès à l'API. C'est une application de l'utilisation de la clé au niveau matériel.
Keymaster inclut un compteur de tentatives d'authentification biométrique échouées. Après un nombre spécifié d'échecs (configurable via setInvalidatedByBiometricEnrollment), la clé devient indisponible et nécessite une suppression/régénération. Lorsque tous les modèles biométriques sont supprimés, toutes les clés avec userAuthenticationRequired=true sont automatiquement invalidées.
Key Attestation (Android 8.1+) est également prise en charge : à la demande de l'application, Keymaster signe un certificat avec des informations sur les caractéristiques de la clé (matériel/logiciel, algorithme, objets). Le serveur peut vérifier ce certificat pour confirmer que la clé a été créée dans un environnement de confiance.
Foire aux questions
Java KeyStore stocke les clés dans un fichier protégé par mot de passe (JKS, BKS). Android Keystore utilise l'isolement matériel via TEE ou Secure Element. Java KeyStore est vulnérable à l'accès root ; Android Keystore ne l'est pas, car les clés privées ne quittent jamais l'environnement sécurisé.
Oui, via KeyStore.setEntry avec KeyProtection. Cependant, la clé importée n'aura pas de protection matérielle — elle sera stockée dans le Keystore logiciel, chiffrée avec une clé maître. Pour une sécurité maximale, générez toujours les clés dans Keystore.
Utilisez KeyChain.isBoundKeyAlgorithm ou vérifiez KeyCharacteristics après la génération de la clé. La présence de FLAG_HARDWARE dans les caractéristiques signifie que la clé a été créée dans TEE. Vous pouvez également vérifier android.security.keystore.isHardwareBacked().
Lors de la désinstallation de l'application, Android supprime toutes ses clés du Keystore. Les données sont perdues irréversiblement. Lors de la réinstallation, l'application doit générer de nouvelles clés. La sauvegarde des clés via TEE est architecturalement impossible.
Sur un appareil verrouillé, Keymaster n'effectue aucune opération. Les clés avec userAuthenticationRequired=true nécessitent une confirmation biométrique à chaque fois. Même avec un accès root, un attaquant ne peut pas appeler Keymaster directement — seulement via le service Android Keystore.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi