Android Keystore — 是一种加密提供程序,它在孤立的执行环境(TEE)中生成和存储加密密钥,连操作系统都无法访问。据 AOSP Security Documentation (2025) 报道,Keystore被 Google Play 前100名的Android应用程序中的80%以上用于保护令牌和加密数据。理解 Android Keystore 对在Android上安全存储密钥至关重要。
主要观点
Android Keystore — Android平台的系统组件,提供API用于在受保护环境中生成、存储和使用加密密钥。与软件加密库(Bouncy Castle、Conscrypt)不同,Keystore保证私钥从不离开孤立的执行区域。
Keystore出现在Android 4.3(API 18)中,作为支持RSA的软件提供程序。从Android 6.0(API 23)开始,Keystore通过Keymaster Hardware Abstraction Layer (HAL)获得了硬件支持,将加密操作委托给兼容设备上的Trusted Execution Environment (TEE)。据 Android Compatibility Definition Document (2025),所有带有Android 9+的设备必须通过TEE或StrongBox支持硬件Keystore。
Keystore中的密钥通过别名(alias)标识 — 在创建或加载密钥时传递的字符串。Keystore不允许获取密钥的原始材料:getEncoded()方法对在Keystore中创建的密钥返回 null。这是与软件密钥的根本区别 — 攻击者即使完全控制设备也无法提取私钥。
Keystore与Android的其他安全机制集成:生物识别验证(BiometricPrompt)、文件级加密(File-Based Encryption)以及SafetyNet / Play Integrity验证功能。密钥可以配置为在特定条件下自动删除:删除密码时、添加新指纹时或到期时。
Android Keystore的架构包括三个实现层级,它们在硬件保护程度上有所不同。层级取决于设备的硬件能力。
TEE(Trusted Execution Environment) — 一个孤立的区域,与主操作系统在同一个处理器上并行工作。TEE使用ARM TrustZone技术,将物理处理器内核分为两个虚拟部分:Normal World(Android)和Secure World(TEE)。Secure World中的代码可以访问Normal World无法访问的内存和外设。
当应用程序通过Keystore调用加密操作时,请求通过Keymaster HAL发送到TEE,在该环境中由硬件执行操作。结果返回给应用程序,但私钥仍留在TEE的受保护内存中。TEE已按照GlobalPlatform TEE Protection Profile获得认证,并且对于具有支持TrustZone的处理器的设备上的Android 9+是必须的要求。
TEE支持AES/GCM(128、256位)、RSA(2048、4096位)、EC(P-256、P-384、P-521)和HMAC-SHA256算法。TEE的性能低于软件加密(低20–40%),但对于典型操作(JWT签名、会话密钥解密)延迟不超过10–50毫秒。
StrongBox — 专用安全芯片,物理上与主处理器分离。与TEE(与Android共享处理器时间)不同,StrongBox拥有自己的CPU、RAM、真随机数生成器(TRNG)和受保护存储(One-Time Programmable memory)。StrongBox已获得Common Criteria EAL 4+和Secure IC Protection Profile认证。
StrongBox在具有相应芯片(例如Google Pixel上的Titan M、Samsung Galaxy上的Knox)的Android 9+设备上可用。开发者通过KeyGenParameterSpec中的setIsStrongBoxBacked(true)标志启用StrongBox。如果没有硬件支持,该标志将被忽略,Keystore将切换到TEE。
StrongBox的局限:支持有限的算法集(AES-256、EC P-256、HMAC-SHA256),操作队列不超过同时一个,操作数量受芯片资源限制。StrongBox不适合高负载场景 — 对于频繁操作使用TEE,只对于关键密钥(主加密密钥、签名密钥)使用StrongBox。
基于软件的Keystore — 在没有TEE或StrongBox硬件支持的设备上使用的软件实现。密钥以加密形式存储在文件系统中,但私钥可以暂时在RAM中解密。软件Keystore的安全性较低 — 拥有root访问权的攻击者可以在内存中截获密钥。
从Android 12(API 31)开始,Google要求所有新设备都支持硬件Keystore。带有Android 9–11的设备在低端型号上可能具有软件Keystore。开发者可以通过KeyStore.getKeyCharacteristics()检查保护级别 — SECURITY_LEVEL_TRUSTED_ENVIRONMENT或SECURITY_LEVEL_STRONGBOX属性确认硬件保护。
Android Keystore支持广泛的加密算法,根据密钥类型分为不同类别。算法的选择会影响性能、兼容性和安全级别。
AES(Advanced Encryption Standard) — 用于保护设备上数据的对称加密。推荐模式:AES/GCM/NoPadding(256位)。GCM提供可验证加密(AEAD) — 检查加密数据的完整性。IV(初始化向量)大小:GCM为12字节。不要使用AES/ECB — 它不提供适当的保护。
RSA(Rivest–Shamir–Adleman) — 用于保护会话密钥和数字签名的非对称加密。推荐大小:2048或4096位。模式:RSA/ECB/PKCS1Padding(加密)和RSA/ECB/PKCS1Sign(签名)。RSA 1024被视为过时,不建议用于新应用(NIST SP 800-131A Rev. 2)。
EC(Elliptic Curve) — 基于椭圆曲线的非对称加密,用于签名和密钥交换。支持的曲线:secp256r1(P-256,必须)、secp384r1(P-384)和secp521r1(P-521)。EC在密钥大小明显更小的情况下提供与RSA可比的安全性。P-256被推荐用于多数场景:所有设备都支持它,并提供128位安全级别。
HMAC(Hash-based Message Authentication Code) — 消息的对称验证。支持的哈希函数:SHA-256、SHA-384、SHA-512。HMAC用于验证数据的完整性和真实性,例如验证webhook请求或检查配置完整性。
所有算法都可以通过KeyGenParameterSpec.Builder.setUserAuthenticationRequired(true)绑定到生物识别验证。在Android 11+上可使用setUserAuthenticationParameters()标志,指定超时(以秒为单位),在该时间内密钥在生物识别验证后无需再次请求即可使用。
让我们看看在Kotlin中使用Android Keystore的实践示例:生成AES密钥、加密数据以及创建用于签名的非对称密钥对。
示例创建了一个绑定到生物识别验证的256位AES/GCM密钥。该密钥无法通过getEncoded()导出。
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
fun generateAesKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_ENCRYPT or
KeyProperties.PURPOSE_DECRYPT
)
.setKeySize(256)
.setBlockModes(KeyProperties.KEY_BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(true)
.build()
val generator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore"
)
generator.init(spec)
generator.generateKey()
}
示例使用来自Android Keystore的密钥加密数据。Cipher通过别名获取密钥,初始化AES/GCM加密并返回加密数据以及IV。
fun encryptData(alias: String, plaintext: ByteArray): ByteArray {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val secretKey = keyStore.getKey(alias, null) as SecretKey
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
val iv = cipher.getIV()
val encrypted = cipher.doFinal(plaintext)
// IV + 加密数据
return iv + encrypted
}
fun decryptData(alias: String, ciphertextWithIv: ByteArray): ByteArray {
val iv = ciphertextWithIv.copyOfRange(0, 12)
val encrypted = ciphertextWithIv.copyOfRange(12, ciphertextWithIv.size)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val secretKey = keyStore.getKey(alias, null) as SecretKey
val spec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)
return cipher.doFinal(encrypted)
}
示例在Keystore中创建了一个绑定到StrongBox的RSA-2048密钥对。私钥用于签名,公钥可以通过getEncoded()导出。
fun generateRsaKeyPair(alias: String) {
val spec = KeyGenParameterSpec.Builder(
alias,
KeyProperties.PURPOSE_SIGN or
KeyProperties.PURPOSE_VERIFY
)
.setKeySize(2048)
.setSignaturePaddings(
KeyProperties.SIGNATURE_PADDING_RSA_PKCS1
)
.setDigests(KeyProperties.DIGEST_SHA256)
.setIsStrongBoxBacked(true)
.build()
val pair = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
).apply { init(spec) }
.generateKeyPair()
// 公钥可以导出
val publicKey = pair.public // X509EncodedKeySpec
}
有效使用Android Keystore需要遵循能够在保持性能的同时提供最大保护的规则。
使用具有最少必要参数的KeyGenParameterSpec:只指定实际使用的目的、块模式和填充方式。过多的参数(例如为只用于签名的密钥设置PURPOSE_ENCRYPT)会创建额外的攻击向量。Android建议明确指定签名的摘要 — SHA256是最低可接受的级别(SHA1已过时)。
将密钥绑定到生物识别以进行关键操作:setUserAuthenticationRequired(true)保证密钥只能在生物识别验证后使用。在Android 11+上,使用带有超时(建议30–60秒)的setUserAuthenticationParameters(),以免在同一会话中的每次操作都要求生物识别。setInvalidatedByBiometricEnrollment(true)在添加新指纹或脸部时自动删除密钥 — 这可防止使用旧的生物识别数据访问。
在初始化阶段检查安全级别:使用KeyStore.getKeyCharacteristics()确定SECURITY_LEVEL。如果设备只支持软件Keystore(SECURITY_LEVEL_SOFTWARE),做出决定:要么拒绝功能,要么使用附加加密(例如用用户密码包装密钥)。如果StrongBox没有保障,不要依赖它 — 始终设置 setIsStrongBoxBacked(true) 标志,并通过 getKeyCharacteristics 检查结果。
按计划更新密钥:加密密钥有建议的使用寿命。NIST SP 800-57建议每1–2年更换AES密钥,每2–3年更换RSA/EC密钥对。实现密钥轮换机制:在应用程序启动时检查密钥的创建日期(KeyGenParameterSpec.Builder.setKeyValidityStart/End),并在到期时生成新密钥。用旧密钥加密的旧数据应被解密并用新密钥重新加密。
不要将Keystore用于大量数据:Keystore用于存储密钥(几百字节),而非加密大文件。对于数据加密,使用以下方案:生成随机AES密钥(DEK — Data Encryption Key),用该密钥加密数据,然后用Keystore密钥(KEK — Key Encryption Key)加密DEK。Android EncryptedSharedPreferences正是使用这种方案:主密钥在Keystore中,数据用AES-256 GCM加密。
常见问题
不能,Android Keystore的设计使得私钥从不离开TEE或StrongBox。getEncoded()方法对在Keystore中创建的密钥返回 null。密钥只能通过Cipher、Signature或Mac API使用 — 原始材料不可用。
TEE (TrustZone) — 同一处理器上的虚拟孤立,使用时间分割。StrongBox — 拥有自己CPU和内存的独立芯片。StrongBox更安全(Common Criteria EAL 4+),但更慢并且支持的算法更少。TEE适合频繁操作,StrongBox适合关键密钥。
在使用 setIsStrongBoxBacked(true) 标志生成密钥后,使用 KeyStore.getKeyCharacteristics()。SECURITY_LEVEL_STRONGBOX属性确认硬件支持。如果设备不支持StrongBox,Keystore将无错地切换到TEE — 您需要明确检查安全级别。
Keystore中的密钥在从设备上删除应用程序时会自动删除。在Android 10+上,如果应用程序在清单中具有allowBackup=true标志,密钥可能保留,但在重新安装后将无法访问。建议在清净安装时重新生成密钥。
不能,Android Keystore绑定到特定设备的硬件。在一个设备的TEE中生成的密钥无法转移到另一个设备。对于跨平台加密,使用方案:Keystore在设备上保护密钥,会话密钥通过使用非对称加密的安全API传输。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。