KeyStore (Android) ——是 Java Cryptography Architecture (JCA) 加密提供者在 Android 中的实现,用于安全存储密钥并支持硬件隔离能力。从 Android 4.3 (API 18) 开始,KeyStore 通过 Keymaster HAL 支持硬件密钥,从 Android 9 (API 28) 开始支持用于专用 Secure Element 中密钥的 StrongBox Keymaster。根据 Android Security Documentation,“AndroidKeyStore” 提供者取代了标准的 Bouncy Castle 或 OpenSSL KeyStore,为密钥提供系统级保护,防止未经授权的提取。
主要要点
Android 中的 KeyStore ——不是独立的应用程序或文件,而是实现 java.security.KeyStore 接口的加密提供者。它提供统一的 API来存储和使用私钥、对称密钥以及受信任的证书颁发机构 (CA) 的证书。该提供者以 “AndroidKeyStore” 名义注册,可通过标准的 KeyStore.getInstance() 访问。
在 Android 4.3 之前,加密操作通过 Bouncy Castle 以软件方式执行。Android 4.3 引入了 Keymaster HAL 1.0,允许在 ARM TrustZone 上使用 TEE。Android 6.0 (API 23) 添加了 Keymaster 2.0,支持通过指纹进行硬件认证。Android 9 (API 28) 引入了 Keymaster 4.0 和用于专用 Secure Element 的 StrongBox Keymaster。
Keymaster 的每个版本都增加了新功能,并提高了密钥隔离能力。现代设备 (2022+) 必须支持 Keymaster 4.0 才能获得 Google Mobile Services 认证,这保证了所有 Android 应用程序都能使用 TEE。
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。对于 AndroidKeyStore,参数始终为 null。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 无需填充)。
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 提供了硬件安全保证,软件密钥库 (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自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。