KeyStore (Android) — це реалізація криптографічного провайдера Java Cryptography Architecture (JCA), інтегрована в Android для безпечного зберігання ключів з можливістю апаратної ізоляції. З Android 4.3 (API 18) KeyStore підтримує апаратні ключі через Keymaster HAL, а починаючи з Android 9 (API 28) — StrongBox Keymaster для ключів у виділеному Secure Element. Згідно з Документацією безпеки Android, провайдер «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) для сучасних криптографічних протоколів.
Для асиметричних ключів завжди генеруйте всередині 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/Ed25519 | 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 підписує сертифікат, що містить список характеристик ключа: алгоритм, розмір, призначення, hardware-backed (True/False), походження (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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також