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-сервис не имеет доступа к raw-ключам — только к хэндлам, указывающим на ключи внутри 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) для современных криптографических протоколов.
Для асимметричных ключей Always generate inside Keymaster, NEVER import private keys. Импортированные закрытые ключи не защищены аппаратно — они хранятся в программном слое и уязвимы при компрометации 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. Однако лучшая практика — создавать отдельные ключи для разных операций. Это ограничивает ущерб при компрометации одного из ключей и соответствует принципу least privilege.
Используйте 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также