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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също