KeyStore (Android) est une implémentation du fournisseur cryptographique Java Cryptography Architecture (JCA) intégrée à Android pour le stockage sécurisé de clés avec capacité d'isolation matérielle. Depuis Android 4.3 (API 18), KeyStore prend en charge les clés matérielles via Keymaster HAL, et à partir d'Android 9 (API 28), StrongBox Keymaster pour les clés dans un Secure Element dédié. Selon la Documentation de sécurité Android, le fournisseur « AndroidKeyStore » remplace le Bouncy Castle ou OpenSSL KeyStore standard, offrant une protection au niveau système contre l'extraction non autorisée de clés.
Points clés
KeyStore dans Android n'est pas une application ou un fichier séparé, mais un fournisseur cryptographique implémentant l'interface java.security.KeyStore. Il fournit une API unifiée pour stocker et utiliser les clés privées, les clés symétriques et les certificats CA de confiance. Le fournisseur est enregistré sous le nom « AndroidKeyStore » et est accessible via KeyStore.getInstance() standard.
Avant Android 4.3, les opérations cryptographiques étaient effectuées via Bouncy Castle. Android 4.3 a introduit Keymaster HAL 1.0, permettant l'utilisation de TEE sur ARM TrustZone. Android 6.0 (API 23) a ajouté Keymaster 2.0 avec authentification biométrique matérielle. Android 9 (API 28) a présenté Keymaster 4.0 et StrongBox Keymaster pour un Secure Element dédié.
Chaque version de Keymaster ajoute de nouvelles capacités et améliore l'isolation des clés. Les appareils modernes (2022+) doivent prendre en charge Keymaster 4.0 pour la certification Google Mobile Services, garantissant ainsi la disponibilité de TEE pour toutes les applications Android.
Android KeyStore se compose de trois couches : API Java (KeyStore, KeyPairGenerator), processus système keystore (C++, exécuté en tant que service système) et Keymaster HAL (bibliothèque dans TEE ou Secure Element). L'application appelle l'API, le service keystore achemine la requête vers Keymaster et l'opération est exécutée dans l'environnement sécurisé.
Toutes les clés privées sont stockées dans le TEE et ne peuvent pas être lues depuis l'espace utilisateur. Même le service keystore système n'a pas accès aux clés brutes — seulement aux handles pointant vers les clés à l'intérieur de Keymaster.
Android KeyStore implémente l'interface standard de fournisseur de services JCA. Lorsqu'une application appelle Cipher.getInstance(« RSA/ECB/PKCS1Padding », « AndroidKeyStore »), le fournisseur de sécurité Android délègue l'opération à Keymaster via la chaîne : Java → JNI → service keystore → Keymaster HAL.
Le fournisseur AndroidKeyStore est enregistré automatiquement au démarrage du processus. Sa priorité est supérieure à celle de Bouncy Castle ou Conscrypt. Par conséquent, lors de l'appel de KeyStore.getInstance() sans spécifier de fournisseur, AndroidKeyStore est retourné dans la plupart des cas. Pour un appel explicite, utilisez KeyStore.getInstance(« AndroidKeyStore »).
Chaque application Android dispose d'un conteneur isolé dans KeyStore. Les applications ayant le même UID (shared userId) peuvent partager l'accès à certaines clés, mais la configuration standard garantit que l'application A ne peut pas lire les clés de l'application B.
load(null) — initialisation de KeyStore. Le paramètre est toujours null pour AndroidKeyStore. setEntry — enregistre une clé avec KeyProtection spécifiée (objectifs, digest, padding). getEntry — récupère KeyStore.PrivateKeyEntry, SecretKeyEntry ou TrustedCertificateEntry. containsAlias — vérifie si une clé existe. deleteEntry — supprime définitivement une clé.
import java.security.KeyStore
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
object KeyStoreManager {
private val keyStore by lazy {
KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
}
fun createRsaKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).setKeySize(2048)
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
.build()
val kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
kpg.initialize(spec)
kpg.generateKeyPair()
}
}
Android KeyStore prend en charge un large ensemble d'algorithmes cryptographiques, variant selon la version de Keymaster HAL sur l'appareil. Un développeur peut obtenir la liste des algorithmes pris en charge via KeyGenParameterSpec.Builder lors de la tentative de génération — les paramètres incompatibles lèvent InvalidAlgorithmParameterException.
RSA (1024–4096 bits) — pour la signature (PKCS1, PSS avec SHA-1/SHA-256/SHA-384/SHA-512) et le chiffrement (OAEP avec SHA-1/SHA-256). EC (P-224, P-256, P-384, P-521) — pour la signature ECDSA et l'échange de clés ECDH. X25519 et Ed25519 — depuis Android 12 (API 31) pour les protocoles cryptographiques modernes.
Pour les clés asymétriques, générez toujours à l'intérieur de Keymaster, N'importez JAMAIS de clés privées. Les clés privées importées ne sont pas protégées matériellement — elles sont stockées dans la couche logicielle et sont vulnérables si le processus de l'application est compromis.
AES (128, 256 bits) — pour le chiffrement symétrique en modes CBC, CTR, GCM. HMAC (SHA-1, SHA-256, SHA-512) — pour l'authentification de messages. ChaCha20 (Android 12+) — pour le chiffrement de flux haute performance avec authentification Poly1305.
| Algorithme | Keymaster | Objectif | API |
|---|---|---|---|
| RSA | KM 1.0+ | Signature, Chiffrement | 18+ |
| EC | KM 1.0+ | ECDSA, ECDH | 18+ |
| AES | KM 2.0+ | Chiffrement symétrique | 23+ |
| HMAC | KM 2.0+ | Code d'authentification | 23+ |
| ChaCha20 | KM 3.0+ | Chiffrement de flux | 31+ |
| X25519/Ed25519 | KM 3.0+ | Échange de clés | 31+ |
KeyStore.PrivateKeyEntry — contient une clé privée (non exportable) et une chaîne de certificats. KeyStore.SecretKeyEntry — pour les clés symétriques. KeyStore.TrustedCertificateEntry — pour les certificats CA de confiance. Les clés publiques sont exportables via keyStore.getCertificate(alias).publicKey.
Examinons un scénario complet : générer une clé AES pour le chiffrement de données et générer une clé EC pour la signature avec protection biométrique. Les deux clés sont créées dans Android KeyStore avec prise en charge matérielle.
Une clé AES est créée via KeyGenerator avec KeyGenParameterSpec. Paramètres : PURPOSE_ENCRYPT + PURPOSE_DECRYPT, BLOCK_MODE_GCM (mode recommandé avec authentification), ENCRYPTION_PADDING_NONE (aucun padding nécessaire pour GCM).
import javax.crypto.KeyGenerator
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
fun generateAndEncrypt(alias: String, plainText: ByteArray): ByteArray {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.build()
val kg = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
kg.initialize(spec)
kg.generateKey()
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, getKeyFromStore(alias))
return cipher.doFinal(plainText)
}
Une clé EC avec userAuthenticationRequired=true nécessite une authentification de l'utilisateur avant chaque opération de signature. Pour cela, BiometricPrompt avec CryptoObject contenant l'objet Signature est utilisé. Après une vérification biométrique réussie, Keymaster autorise l'opération.
fun createBiometricSignKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN
).setAlgorithmParameterSpec(
ECGenParameterSpec("secp256r1")
).setDigests(KeyProperties.DIGEST_SHA256)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build()
val kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC,
"AndroidKeyStore"
)
kpg.initialize(spec)
kpg.generateKeyPair()
}
Android KeyStore fournit des garanties de sécurité au niveau matériel que les KeyStore logiciels (JKS, BKS) ne peuvent pas offrir. Les clés sont protégées au niveau du SoC, et même le contrôle total de l'espace utilisateur Android ne permet pas d'extraire la clé privée.
Key Attestation est un mécanisme qui permet à une application (et au serveur) de vérifier l'environnement dans lequel une clé a été créée. Android Keystore signe un certificat contenant une liste de caractéristiques de la clé : algorithme, taille, objectifs, matériel (True/False), origine (GENERATED, IMPORTED). Le serveur vérifie la chaîne de certificats jusqu'au certificat racine de Google.
C'est essentiel pour les applications financières : le serveur peut exiger que la clé ait été créée dans un environnement matériel (Hardware-Backed = True) et rejeter les clés créées dans un Keystore logiciel. Key Attestation prévient les attaques où un attaquant remplace le Keystore par un émulateur.
setInvalidatedByBiometricEnrollment(true) signifie que Keymaster supprimera automatiquement la clé lorsque les modèles biométriques sont modifiés ou supprimés. Cela protège contre les attaques où un attaquant ajoute son empreinte digitale à un compte existant. Après l'ajout d'une nouvelle empreinte, les anciennes clés deviennent inaccessibles.
Le compteur de tentatives échouées d'authentification biométrique est également géré par Keymaster. Après maxBiometricAttempt (configurable par le fabricant, généralement 5), Keymaster bloque toutes les opérations avec des clés biométriques pendant 30 secondes. Après 10 tentatives échouées — jusqu'à la saisie du mot de passe de l'appareil (PIN secret).
Questions fréquentes
Bouncy Castle (BKS) est un KeyStore logiciel qui stocke les clés dans un fichier protégé par mot de passe. Android KeyStore utilise l'isolation matérielle TEE/StrongBox. Les clés BKS peuvent être extraites avec un accès root, les clés Android KeyStore non. BKS convient aux certificats CA, Android KeyStore aux clés privées.
Oui, si vous spécifiez PURPOSE_ENCRYPT ou PURPOSE_DECRYPT ou PURPOSE_SIGN ou PURPOSE_VERIFY lors de la génération. Cependant, la meilleure pratique est de créer des clés séparées pour différentes opérations. Cela limite les dégâts si une clé est compromise et respecte le principe du moindre privilège.
Utilisez KeyStore.getKeyCharacteristics(alias), disponible via android.security.keystore. La méthode retourne un ensemble de drapeaux : FLAG_HARDWARE — clé dans TEE, FLAG_SECURE_ELEMENT — clé dans StrongBox. S'il n'y a pas de drapeaux, la clé est uniquement logicielle.
Toutes les clés créées avec setInvalidatedByBiometricEnrollment(true) seront automatiquement invalidées par Keymaster. Lors de la tentative d'utilisation, l'application recevra KeyPermanentlyInvalidatedException. Les données chiffrées avec ces clés seront perdues définitivement.
Les clés matérielles (dans TEE/StrongBox) ne prennent pas en charge la sauvegarde — elles sont liées à un appareil spécifique. Les clés logicielles peuvent être incluses dans la sauvegarde Google Drive. Pour transférer des données entre appareils, chiffrez les données sur le serveur et déchiffrez sur le nouvel appareil.
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