KeyStore (Android) — a Java Cryptography Architecture (JCA) kriptográfiai szolgáltató megvalósítása, amely integrálva van az Androidba a kulcsok biztonságos tárolására hardveres elkülönítési lehetőséggel. Android 4.3 (API 18) óta a KeyStore támogatja a hardveres kulcsokat a Keymaster HAL-on keresztül, Android 9-től (API 28) pedig a StrongBox Keymaster-t a dedikált Secure Element-ben lévő kulcsokhoz. A Android Security Documentation szerint a „AndroidKeyStore” szolgáltató helyettesíti a szabványos Bouncy Castle vagy OpenSSL KeyStore-okat, rendszerszintű védelmet nyújtva a kulcsok jogosulatlan kinyerése ellen.
Főbb pontok
KeyStore Androidban — nem külön alkalmazás vagy fájl, hanem egy kriptográfiai szolgáltató, amely a java.security.KeyStore interfészt implementálja. Egységes API-t biztosít magánkulcsok, szimmetrikus kulcsok és megbízható hitelesítésszolgáltatók (CA) tanúsítványainak tárolására és használatára. A szolgáltató „AndroidKeyStore” néven van regisztrálva és a szabványos KeyStore.getInstance()-en keresztül érhető el.
Android 4.3 előtt a kriptográfiai műveleteket szoftveresen végezték a Bouncy Castle segítségével. Az Android 4.3-mal megjelent a Keymaster HAL 1.0, amely lehetővé tette a TEE használatát ARM TrustZone-on. Android 6.0 (API 23) hozzáadta a Keymaster 2.0-t ujjlenyomatos hardveres hitelesítés támogatásával. Android 9 (API 28) bevezette a Keymaster 4.0-t és a StrongBox Keymaster-t a dedikált Secure Element számára.
A Keymaster minden verziója új képességeket ad hozzá és javítja a kulcsok elkülönítését. A modern eszközöknek (2022+) támogatniuk kell a Keymaster 4.0-t a Google Mobile Services tanúsítványozásához, ami garantálja a TEE jelenlétét minden Android-alkalmazás számára.
Az Android KeyStore három szintből áll: Java API (KeyStore, KeyPairGenerator), rendszerfolyamat keystore (C++, system service-ként működik) és Keymaster HAL (könyvtár TEE-ben vagy Secure Element-ben). Az alkalmazás meghívja az API-t, a keystore szolgáltatás továbbítja a kérést a Keymaster-hoz, a művelet a védett környezetben történik.
Minden magánkulcs a TEE-ben tárolódik, és nem olvasható ki a felhasználói térből. Még a rendszer keystore szolgáltatása sem fér hozzá a nyers kulcsokhoz — csak a Keymaster-en belüli kulcsokra mutató kezelőkhöz.
Az Android KeyStore a JCA szolgáltató szabványos interfészét implementálja. Amikor az alkalmazás meghívja a Cipher.getInstance(„RSA/ECB/PKCS1Padding”, „AndroidKeyStore”) függvényt, az Android Security Provider a láncon keresztül továbbítja a műveletet a Keymaster-hoz: Java → JNI → keystore service → Keymaster HAL.
Az AndroidKeyStore szolgáltató automatikusan regisztrálódik a folyamat indulásakor. Prioritása magasabb, mint a Bouncy Castle-é vagy a Conscrypt-é. Ezért a KeyStore.getInstance() szolgáltató megadása nélküli meghívásakor a legtöbb esetben AndroidKeyStore kerül visszaadásra. Explicit híváshoz használja a KeyStore.getInstance(„AndroidKeyStore”) függvényt.
Minden Android-alkalmazásnak van egy elkülönített tárolója a KeyStore-ban. Az azonos UID-val (shared userId) rendelkező alkalmazásoknak közös hozzáférésük lehet bizonyos kulcsokhoz, de a szabványos konfiguráció garantálja, hogy az A alkalmazás nem olvashatja a B alkalmazás kulcsait.
load(null) — a KeyStore inicializálása. A paraméter AndroidKeyStore esetén mindig null. setEntry — kulcs mentése KeyProtection megadásával (purposes, digest, padding). getEntry — KeyStore.PrivateKeyEntry, SecretKeyEntry vagy TrustedCertificateEntry lekérése. containsAlias — kulcs létezésének ellenőrzése. deleteEntry — kulcs törlése (visszavonhatatlan).
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()
}
}
Az Android KeyStore a kriptográfiai algoritmusok széles körét támogatja, amely az eszközön lévő Keymaster HAL verziótól függően változik. A fejlesztő a támogatott algoritmusok listáját a KeyGenParameterSpec.Builder segítségével kérdezheti le generálási kísérlet során — az inkompatibilis paraméterek InvalidAlgorithmParameterException-t okoznak.
RSA (1024–4096 bit) — aláíráshoz (PKCS1, PSS SHA-1/SHA-256/SHA-384/SHA-512) és titkosításhoz (OAEP SHA-1/SHA-256). EC (P-224, P-256, P-384, P-521) — ECDSA aláíráshoz és ECDH kulcsegyeztetéshez. X25519 és Ed25519 — Android 12-től (API 31) modern kriptográfiai protokollokhoz.
Aszimmetrikus kulcsok esetén Mindig a Keymaster-en belül generáljon, SOHA ne importáljon magánkulcsokat. Az importált magánkulcsok nincsenek hardveresen védve — a szoftveres rétegben tárolódnak és sérülékenyek az AP kompromittálásakor.
AES (128, 256 bit) — szimmetrikus titkosításhoz CBC, CTR, GCM módokban. HMAC (SHA-1, SHA-256, SHA-512) — üzenetek hitelesítéséhez. ChaCha20 (Android 12+) — nagy teljesítményű folyamatos titkosításhoz Poly1305 hitelesítéssel.
| Algoritmus | Keymaster | Cél | API |
|---|---|---|---|
| RSA | KM 1.0+ | Aláírás, titkosítás | 18+ |
| EC | KM 1.0+ | ECDSA, ECDH | 18+ |
| AES | KM 2.0+ | Szimmetrikus titkosítás | 23+ |
| HMAC | KM 2.0+ | Hitelesítési kód | 23+ |
| ChaCha20 | KM 3.0+ | Folyamatos titkosítás | 31+ |
| X25519/E25519 | KM 3.0+ | Kulcscsere | 31+ |
KeyStore.PrivateKeyEntry — tartalmazza a magánkulcsot (nem exportálható) és a tanúsítványláncot. KeyStore.SecretKeyEntry — szimmetrikus kulcsokhoz. KeyStore.TrustedCertificateEntry — megbízható CA tanúsítványokhoz. Nyilvános kulcsok exportálhatók a keyStore.getCertificate(alias).publicKey segítségével.
Tekintsünk át egy teljes forgatókönyvet: AES kulcs generálása adatok titkosításához és EC kulcs generálása aláíráshoz biometrikus védelemmel. Mindkét kulcs az Android KeyStore-on belül készül hardveres támogatással.
Az AES kulcs a KeyGenerator segítségével jön létre KeyGenParameterSpec paraméterekkel. Paraméterek: PURPOSE_ENCRYPT + PURPOSE_DECRYPT, BLOCK_MODE_GCM (ajánlott mód hitelesítéssel), ENCRYPTION_PADDING_NONE (GCM-hez padding nem szükséges).
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)
}
Az EC kulcs userAuthenticationRequired=true paraméterrel felhasználói hitelesítést igényel minden aláírási művelet előtt. Ehhez BiometricPrompt használatos CryptoObject-tel, amely Signature objektumot tartalmaz. Sikeres biometria után a Keymaster engedélyezi a műveletet.
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()
}
Az Android KeyStore hardveres biztonsági garanciákat nyújt, amelyeket a szoftveres KeyStore-ok (JKS, BKS) nem tudnak nyújtani. A kulcsok SoC szinten vannak védve, és még az Android felhasználói tér feletti teljes kontroll sem teszi lehetővé a magánkulcs kinyerését.
Key Attestation — mechanizmus, amely lehetővé teszi az alkalmazás (és a szerver) számára annak ellenőrzését, hogy a kulcs milyen környezetben készült. Az Android Keystore aláír egy tanúsítványt, amely tartalmazza a kulcs jellemzőinek listáját: algoritmus, méret, purges, hardware-backed (True/False), origin (GENERATED, IMPORTED). A szerver ellenőrzi a tanúsítványláncot a Google győkértanúsítványáig.
Ez kritikus fontosságú a pénzügyi alkalmazások számára: a szerver megkövetelheti, hogy a kulcs hardveres környezetben készüljön (Hardware-Backed = True), és elutasíthatja a szoftveres Keystore-ban készült kulcsokat. A Key Attestation megakadályozza azokat a támadásokat, ahol a támadó a Keystore-t emulátorra cseréli.
setInvalidatedByBiometricEnrollment(true) azt jelenti, hogy a kulcsot a Keymaster automatikusan törli a felhasználó biometrikus sablonjainak változásakor vagy törlésekor. Ez védelem azok ellen a támadások ellen, ahol a támadó hozzáadja a saját ujjlenyomatát egy létező fiókhoz. Új ujjlenyomat hozzáadása után a régi kulcsok elérhetetlenné válnak.
A sikertelen biometrikus hitelesítési kísérletek számlálóját is a Keymaster kezeli. A maxBiometricAttempt után (a gyártó állítja be, általában 5) a Keymaster 30 másodpercre blokkolja az összes biometrikus kulcsokkal végzett műveletet. 10 sikertelen kísérlet után — az eszközjelszó (titkos PIN) megadásáig.
Gyakori kérdések
Bouncy Castle (BKS) — egy szoftveres KeyStore, amely a kulcsokat jelszóval védett fájlban tárolja. Az Android KeyStore hardveres elkülönítést (TEE/StrongBox) használ. A BKS kulcsok root hozzáféréssel kinyerhetők, az Android KeyStore kulcsok nem. A BKS CA tanúsítványokhoz, az Android KeyStore magánkulcsokhoz alkalmas.
Igen, ha a generáláskor meg van adva a PURPOSE_ENCRYPT or PURPOSE_DECRYPT or PURPOSE_SIGN or PURPOSE_VERIFY. A legjobb gyakorlat azonban külön kulcsok létrehozása különböző műveletekhez. Ez korlátozza a kárt az egyik kulcs kompromittálódása esetén és megfelel a legkisebb jogosultság elvének.
Használja a KeyStore.getKeyCharacteristics(alias) függvényt, amely az android.security.keystore-on keresztül érhető el. A metódus flag-ek halmazát adja vissza: FLAG_HARDWARE — kulcs TEE-ben, FLAG_SECURE_ELEMENT — kulcs StrongBox-ban. Ha nincsenek flag-ek — a kulcs szoftveres.
Az összes kulcs, amely setInvalidatedByBiometricEnrollment(true) paraméterrel jött létre, automatikusan érvénytelenítődik a Keymaster által. Használati kísérletkor az alkalmazás KeyPermanentlyInvalidatedException-t kap. Az ezekkel a kulcsokkal titkosított adatok visszavonhatatlanul elvesznek.
A hardveres kulcsok (TEE/StrongBox-ban) nem támogatják a biztonsági mentést — az adott eszközhöz vannak kötve. Szoftveres kulcsok bekerülhetnek a Google Drive biztonsági mentésbe. Az eszközök közötti adatátvitelhez titkosítsa az adatokat a szerveren és fejtse vissza az új eszközön.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is