KeyStore (Android) — је имплементација криптографског провајдера Java Cryptography Architecture (JCA) интегрисана у Android за безбедно чување кључева са могућношћу хардверске изолације. Од Android 4.3 (API 18) KeyStore подржава хардверске кључеве кроз Keymaster HAL, а од Android 9 (API 28) — StrongBox Keymaster за кључеве у намењенском Secure Element. Према Android Security Documentation, провајдер „AndroidKeyStore” замењује стандардне Bouncy Castle или OpenSSL KeyStore, пружајући системску заштиту од неовлашћеног извлачења кључева.
Главно
KeyStore у Android-у — није посебна апликација или датотека, већ криптографски провајдер који имплементира интерфејс java.security.KeyStore. Он пружа јединствени API за чување и коришћење приватних кључева, симетричних кључева и цертификата поверљивих центара (CA). Провајдер је регистрован под називом „AndroidKeyStore” и доступан кроз стандардни KeyStore.getInstance().
Пре Android 4.3 криптографске операције су се извршавале програмски кроз Bouncy Castle. Са Android 4.3 појавио се Keymaster HAL 1.0, омогућавши коришћење TEE на ARM TrustZone. Android 6.0 (API 23) је додао Keymaster 2.0 са подршком за хардверску аутентификацију отиском прста. Android 9 (API 28) је представио Keymaster 4.0 и StrongBox Keymaster за намењенски Secure Element.
Свака верзија Keymaster-а додаје нове могућности и побољшава изолацију кључева. Модерни уређаји (2022+) морају да подржавају Keymaster 4.0 за цертификацију Google Mobile Services, што гарантује постојање TEE за све Android апликације.
Android KeyStore се састоји од три нивоа: Java API (KeyStore, KeyPairGenerator), системски процес keystore (C++, ради као system service) и Keymaster HAL (библиотека у TEE или Secure Element). Апликација позива API, keystore сервис усмерава захтев ка Keymaster-у, операција се извршава у заштићеном окружењу.
Сви приватни кључеви чувају се у TEE и не могу бити прочитани из корисничког простора. Чак ни системски keystore сервис нема приступ сировим кључевима — само до ручки које указују на кључеве унутар Keymaster-а.
Android KeyStore имплементира стандардни интерфејс пружаоца услуга JCA. Када апликација позове Cipher.getInstance(„RSA/ECB/PKCS1Padding”, „AndroidKeyStore”), Android Security Provider делегира операцију Keymaster-у кроз ланац: Java → JNI → keystore service → Keymaster HAL.
Провајдер AndroidKeyStore се региструје аутоматски при покретању процеса. Негов приоритет је виши од Bouncy Castle или Conscrypt. Стога при позиву KeyStore.getInstance() без навођења провајдера у већини случајева враћа се AndroidKeyStore. За експлицитни позив користите KeyStore.getInstance(„AndroidKeyStore”).
Свака Android апликација има изолован контејнер у KeyStore-у. Апликације са истим UID (shared userId) могу имати заједнички приступ одређеним кључевима, али стандардна конфигурација гарантује да апликација A не може да чита кључеве апликације B.
load(null) — иницијализација KeyStore-а. Параметар је увек null за AndroidKeyStore. setEntry — чување кључа са навођеном KeyProtection (purposes, digest, padding). getEntry — добијање KeyStore.PrivateKeyEntry, SecretKeyEntry или TrustedCertificateEntry. containsAlias — провера постојања кључа. deleteEntry — брисање кључа (неопозиво).
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 подржава широк скуп криптографских алгоритама, који варирају у зависности од верзије Keymaster HAL на уређају. Развијач може добити листу подржаних алгоритама кроз KeyGenParameterSpec.Builder при покушају генерације — некомпатибилни параметри изазивају InvalidAlgorithmParameterException.
RSA (1024–4096 бита) — за потпис (PKCS1, PSS са SHA-1/SHA-256/SHA-384/SHA-512) и шифровање (OAEP са SHA-1/SHA-256). EC (P-224, P-256, P-384, P-521) — за ECDSA потпис и ECDH размену кључева. X25519 и Ed25519 — од Android 12 (API 31) за савремене криптографске протоколе.
За асиметричне кључеве Увек генеришите унутар Keymaster-а, НИКАДа не увозите приватне кључеве. Увезени приватни кључеви нису хардверски заштићени — чувају се у програмском слоју и рањиви су при компромитацији AP.
AES (128, 256 бита) — за симетрично шифровање у режимима CBC, CTR, GCM. HMAC (SHA-1, SHA-256, SHA-512) — за аутентификацију порука. ChaCha20 (Android 12+) — за високоперформансно стримовно шифровање са аутентификацијом Poly1305.
| Алгоритам | Keymaster | Намена | API |
|---|---|---|---|
| RSA | KM 1.0+ | Потпис, шифровање | 18+ |
| EC | KM 1.0+ | ECDSA, ECDH | 18+ |
| AES | KM 2.0+ | Симетрично шифровање | 23+ |
| HMAC | KM 2.0+ | Код аутентификације | 23+ |
| ChaCha20 | KM 3.0+ | Стримовно шифровање | 31+ |
| X25519/E25519 | KM 3.0+ | Размена кључева | 31+ |
KeyStore.PrivateKeyEntry — садржи приватни кључ (неизвозив) и ланац цертификата. KeyStore.SecretKeyEntry — за симетричне кључеве. KeyStore.TrustedCertificateEntry — за поверљиве CA цертификате. Јавни кључеви су доступни за извоз кроз keyStore.getCertificate(alias).publicKey.
Размотримо потпун сценарио: генерација AES кључа за шифровање података и генерација EC кључа за потпис са биометријском заштитом. Оба кључа се креирају унутар Android KeyStore-а са хардверском подршком.
AES кључ се креира кроз KeyGenerator са KeyGenParameterSpec. Параметри: PURPOSE_ENCRYPT + PURPOSE_DECRYPT, BLOCK_MODE_GCM (препоручени режим са аутентификацијом), ENCRYPTION_PADDING_NONE (за GCM padding није потребан).
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)
}
EC кључ са userAuthenticationRequired=true захтева аутентификацију корисника пре сваке операције потписа. За ово се користи BiometricPrompt са CryptoObject који садржи Signature објекат. Након успешне биометрије, Keymaster дозвољава операцију.
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 пружа хардверске гаранције безбедности које програмски KeyStore-ови (JKS, BKS) не могу да пруже. Кључеви су заштићени на нивоу SoC-а, и чак потпуна контрола над корисничким простором Android-а не омогућава извлачење приватног кључа.
Key Attestation — механизам који омогућава апликацији (и серверу) да провере у којем је окружењу креиран кључ. Android Keystore потписује цертификат који садржи списак карактеристика кључа: алгоритам, величину, purges, hardware-backed (True/False), origin (GENERATED, IMPORTED). Сервер проверава ланац цертификата до коренског цертификата Google-а.
Ово је критично за финансијске апликације: сервер може захтевати да је кључ креиран у хардверском окружењу (Hardware-Backed = True) и одбијати кључеве креиране у програмском Keystore-у. Key Attestation спречава нападе у којима нападач замењује Keystore емулатором.
setInvalidatedByBiometricEnrollment(true) значи да ће кључ бити аутоматски обрисан од стране Keymaster-а при промени или брисању биометријских шаблона корисника. Ово је заштита од напада у којима нападач додаје свој отисак прста постојећем налозу. Након додавања новог отиска, стари кључеви постају недоступни.
Бројач неуспешних покушаја биометријске аутентификације такође води Keymaster. Након maxBiometricAttempt (подешава произвођач, обично 5) Keymaster блокира све операције са биометријским кључевима на 30 секунди. Након 10 неуспешних покушаја — до уношења лозинке уређаја (тајни PIN).
Често постављана питања
Bouncy Castle (BKS) — програмски KeyStore који чува кључеве у датотеци заштићеној лозинком. Android KeyStore користи хардверску изолацију TEE/StrongBox. BKS кључеви се могу извући са root приступом, Android KeyStore кључеви не могу. BKS је погодан за CA цертификате, Android KeyStore — за приватне кључеве.
Да, ако се при генерацији наведу PURPOSE_ENCRYPT or PURPOSE_DECRYPT or PURPOSE_SIGN or PURPOSE_VERIFY. Ипак, најбоља пракса је креирати одвојене кључеве за различите операције. Ово ограничава штету при компромитацији једног од кључева и одговара принципу најмање привилегије.
Користите KeyStore.getKeyCharacteristics(alias), доступан кроз android.security.keystore. Метода враћа скуп заставица: FLAG_HARDWARE — кључ у TEE, FLAG_SECURE_ELEMENT — кључ у StrongBox-у. Ако нема заставица — кључ је програмски.
Сви кључеви креирани са setInvalidatedByBiometricEnrollment(true) биће аутоматски инвалидирани од стране Keymaster-а. При покушају коришћења, апликација ће добити KeyPermanentlyInvalidatedException. Подаци шифровани овим кључевима биће неопозиво изгубљени.
Хардверски кључеви (у TEE/StrongBox-у) не подржавају резервно копирање — везани су за одређени уређај. Програмски кључеви могу бити укључени у Google Drive резервну копију. За пренос података између уређаја, шифрујте податке на серверу и дешифрујте на новом уређају.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође