Android Keystore — este un mecanism de sistem Android pentru stocarea sigură a cheilor criptografice în izolare hardware. Sistemul utilizează Trusted Execution Environment (TEE) pe dispozitive cu ARM TrustZone sau un Secure Element dedicat pentru protejarea cheilor la nivel de cip. Conform Android Open Source Project, Keystore suportă algoritmii RSA, EC, AES și HMAC cu generarea cheilor direct în mediul securizat.
Principalele
Android Keystore — este un furnizor criptografic (provider) implementat în Android începând cu API 1 (Android 1.0), dar suportul hardware complet a apărut cu Android 4.3 (API 18). Keystore rezolvă problema stocării sigure a cheilor private astfel încât chiar și în cazul compromiterii sistemului de operare, atacatorul să nu poată extrage cheile în formă deschisă.
Arhitectura Android Keystore constă din trei niveluri: API aplicativ (java.security.KeyStore), serviciul de sistem (keystore daemon) și nivelul hardware (Keymaster HAL). Aplicația accesează prin API-ul standard Java Cryptography Architecture (JCA), iar serviciul de sistem direcționează cererile către Keymaster care funcționează în TEE.
Toate operațiile criptografice cu chei (semnare, decriptare) se execută în TEE sau Secure Element. Cheile nu părăsesc niciodată mediul securizat — aplicația primește doar un identificator (alias) pentru a se referi la cheie. Aceasta este o diferență fundamentală față de KeyStore-urile software, unde cheile sunt potențial accesibile în memoria procesului.
JKS (Java KeyStore) standard sau BKS (Bouncy Castle) stochează cheile în fișiere protejate prin parolă. Android Keystore stochează cheile în izolare hardware, unde sunt protejate chiar și de utilizatorul root. JKS este vulnerabil la accesul direct la sistemul de fișiere, Android Keystore — nu.
O altă diferență: în Android Keystore cheile au parametri stricti de utilizare (purpose — doar sign/verify/encrypt/decrypt), stabiliți la generare. Nu pot fi modificați ulterior, ceea ce previne utilizarea abuzivă a cheii.
La crearea unei noi chei, aplicația apelează KeyPairGenerator sau KeyGenerator cu KeyGenParameterSpec, care conține toți parametrii viitoarei chei. Sistemul transmite cererea către Keymaster HAL, care generează cheia în TEE și returnează un identificator.
Metoda KeyGenParameterSpec.Builder acceptă parametrii obligatorii: numele cheii în Keystore, scopul (PURPOSE_SIGN, PURPOSE_ENCRYPT), algoritmul (RSA, EC, AES). Suplimentar: digest (SHA-256), padding (PKCS7), userAuthenticationRequired (biometrie), keyValidityStart/End (limitări temporale).
După setarea parametrilor, KeyPairGenerator.generateKeyPair() returnează KeyPair, unde PrivateKey este un obiect care delegă operațiile către Keymaster. Cheia publică poate fi extrasă, cea privată — nu. Există doar în 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 pentru ECDSA sau RSA-PSS se creează prin API-ul standard: Signature.getInstance(algorithm).initSign(privateKey). Operația de semnare se execută în TEE: aplicația trimite datele, Keymaster le semnează hardware și returnează semnătura. Cheia și datele nu se amestecă în memoria partajată.
Pentru protecția biometrică este necesară autentificarea utilizatorului prin BiometricPrompt înainte de semnare. Fără autentificare reușită, Keymaster nu execută operația, returnând 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 cu CryptoObject(signature) solicită FaceID/PIN
}
Android suportă două moduri de stocare a cheilor: software (pe dispozitive fără TEE) și hardware (pe dispozitive cu TEE sau Secure Element). Modul depinde de capacitățile SoC și de versiunea Android.
Pe dispozitivele fără Trusted Execution Environment (înainte de Android 4.3 sau SoC-uri bugetare) cheile sunt stocate în formă criptată folosind o cheie principală derivată din parola ecranului de blocare. Acest mod este mai puțin sigur — cheile sunt accesibile în memoria procesului în timpul operațiilor criptografice.
Nivelul de protecție se bazează pe criptarea fișierului KeyStore cu AES-256-GCM. Cheia de criptare este generată pe baza parolei utilizatorului sau PIN-ului prin Scrypt (PBKDF2 cu un număr mare de iterații).
Pe dispozitivele moderne se utilizează Keymaster 4.x în TEE (ARM TrustZone). Cheile sunt generate, stocate și utilizate exclusiv în TrustZone. Chiar și nucleul Linux nu are acces la cheile private — doar Keymaster HAL poate efectua operații.
Secure Element (de exemplu, eSE în Samsung Knox sau StrongBox în Google Pixel 3+) — este un cip separat cu propriul procesor și memorie. Este certificat Common Criteria EAL 4+ și asigură nivelul maxim de protecție, inclusiv protecția împotriva deschiderii fizice.
| Tip | Locația de stocare | Nivel de protecție | Disponibil de la API |
|---|---|---|---|
| Software | Fișier /data/misc/keystore | Mediu (AES-256) | API 1+ |
| Keymaster 3 | TEE (TrustZone) | Ridicat | API 23+ |
| Keymaster 4 | TEE + Secure I/O | Foarte ridicat | API 28+ |
| StrongBox | Secure Element hardware | Maxim | API 28+, opțional |
Android Keystore este integrat în Java Cryptography Architecture (JCA). Pentru accesul la furnizor se utilizează KeyStore.getInstance("AndroidKeyStore") standard. API-ul este disponibil de la API 18.
Metoda KeyStore.load(null) încarcă containerul KeyStore al aplicației curente. Nu este necesară parola — Android utilizează contextul aplicației și UID-ul său pentru delimitarea accesului. Fiecare aplicație vede doar propriile înregistrări, cu excepția cazului în care se utilizează un UID partajat.
Metodele setEntry și getEntry lucrează cu KeyStore.PrivateKeyEntry, SecretKeyEntry sau TrustedCertificateEntry. Parametrul ProtectionParameter este întotdeauna null pentru Android Keystore (protecția este implementată la nivel de sistem).
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)
}
Cu ajutorul KeyCharacteristics se poate determina în ce mediu este stocată cheia: KeyStore software, TEE sau StrongBox. Metoda getKeyCharacteristics() returnează un set de flag-uri: FLAG_HARDWARE (keymaster), FLAG_SECURE_ELEMENT (StrongBox), FLAG_TRUSTED_USER_PRESENCE_REQUIRED (biometrie).
Android Keystore suportă un set larg de algoritmi criptografici, împărțit în trei categorii: asimetrici, simetrici și MAC. Suportul pentru algoritmi specifici depinde de versiunea Keymaster HAL.
RSA (1024–4096 biți) — pentru semnare (PKCS1, PSS) și criptare (OAEP, PKCS1). EC (P-224, P-256, P-384, P-521) — pentru semnarea ECDSA și convenirea ECDH. AES (128, 256 biți) — pentru criptarea simetrică în modurile CBC, CTR, GCM. HMAC (SHA1, SHA256, SHA512) — pentru autentificarea mesajelor.
Pentru fiecare cheie se stabilește setPurposes, care limitează operațiile posibile. O cheie RSA cu PURPOSE_SIGN nu poate fi utilizată pentru criptare, chiar dacă atacatorul are acces la API. Aceasta este impunerea utilizării cheii la nivel hardware.
Keymaster include un contor de încercări eșuate de autentificare biometrică. După un număr stabilit de încercări eșuate (configurabil prin setInvalidatedByBiometricEnrollment), cheia devine indisponibilă și necesită ștergere/regenerare. La ștergerea tuturor șabloanelor biometrice, toate cheile cu userAuthenticationRequired=true sunt automat invalidate.
De asemenea, este suportată Key Attestation (Android 8.1+): la cererea aplicației, Keymaster semnează un certificat cu informații despre caracteristicile cheii (hardware/software, algoritm, purges). Serverul poate verifica acest certificat pentru a confirma că cheia a fost creată în mediu de încredere.
Întrebări frecvente
Java KeyStore stochează cheile într-un fișier protejat prin parolă (JKS, BKS). Android Keystore utilizează izolarea hardware TEE sau Secure Element. Java KeyStore este vulnerabil la accesul root, Android Keystore — nu, deoarece cheile private nu părăsesc niciodată mediul securizat.
Da, prin KeyStore.setEntry cu KeyProtection. Totuși, cheia importată nu va avea protecție hardware — va fi stocată în Keystore software, criptată cu cheia principală. Pentru securitate maximă, generați întotdeauna cheile în Keystore.
Utilizați KeyChain.isBoundKeyAlgorithm sau verificați KeyCharacteristics după generarea cheii. Prezența FLAG_HARDWARE în caracteristici înseamnă că cheia a fost creată în TEE. De asemenea, puteți verifica android.security.keystore.isHardwareBacked().
La ștergerea aplicației, Android elimină toate cheile acesteia din Keystore. Datele se pierd ireversibil. La reinstalare, aplicația trebuie să genereze chei noi. Backup-ul cheilor prin TEE este imposibil din motive arhitecturale.
Pe un dispozitiv blocat, Keymaster nu execută nicio operație. Cheile cu userAuthenticationRequired=true necesită confirmare biometrică de fiecare dată. Chiar și cu acces root, atacatorul nu poate apela Keymaster direct — doar prin serviciul Android Keystore.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și