2. Android KeyStore 系统架构:硬件支持、安全等级、密钥生命周期
Android KeyStore 并非单一的软件库,而是一套分层的密钥管理体系。它从底层的硬件安全模块(如 TEE、StrongBox)向上提供统一的 java.security.KeyStore 或 android.security.keystore API。理解其架构的三个维度——硬件支持、安全等级、密钥生命周期——是正确使用 KeyStore 加密蓝牙持久化数据的前提。
2.1 硬件支持层
Android 设备可能包含以下硬件安全模块,KeyStore 会根据设备能力自动选择最高可用模块:
- TEE (Trusted Execution Environment):基于 ARM TrustZone 的独立安全世界,密钥运算在 TEE 内部完成,普通系统(REE)只能通过驱动接口调用。大多数中高端设备(从 Android 7.0 起)默认支持。
- StrongBox:独立的安全芯片(如 Titan M),拥有自己的 CPU、存储和真随机数生成器。Android 9 引入,需在
KeyGenParameterSpec.Builder中显式指定setIsStrongBoxBacked(true)。 - 软件安全 (Soft Keymaster):纯软件实现,密钥加密后存储于文件系统。无硬件支持的设备或未启用 TEE 时降级使用。
最佳实践:蓝牙持久化数据通常对性能要求不苛刻,应优先使用 StrongBox 或 TEE。使用前通过
KeyStore.getInstance("AndroidKeyStore") 和 Provider.getInfo() 检查设备支持情况。
2.2 安全等级对比
| 安全等级 | 实现方式 | 密钥隔离 | 抗物理攻击 | 典型设备 |
|---|---|---|---|---|
| 软件 | /data/misc/keystore 加密文件 | 弱(受 SELinux 保护) | 无 | 低端手机、模拟器 |
| TEE | ARM TrustZone + 安全 OS | 强(非安全世界不可直接访问) | 中等(需侧信道攻击) | 大部分 Android 7+ 设备 |
| StrongBox | 独立安全芯片(eSE) | 极高(物理+逻辑隔离) | 高(防篡改、防探针) | Pixel 3+、部分三星旗舰 |
关键结论:蓝牙设备配对密钥或持久化连接令牌等敏感数据,应使用
KeyProperties.PURPOSE_ENCRYPT | PURPOSE_DECRYPT 且在 TEE/StrongBox 中生成。无法满足时至少保证密钥不出用户空间。
2.3 密钥生命周期
KeyStore 中的密钥遵循一套完整的生命周期管理,所有操作都通过 KeyStore 和 KeyGenerator/KeyPairGenerator API 触发。
常见错误:未正确设置
KeyGenParameterSpec.Builder 中的 setKeyValidityStart/setKeyValidityEnd 导致密钥过期后无法解密;或忘记设置 setUserAuthenticationRequired(true) 导致密钥被恶意应用重用。
// 生成对称密钥 (AES 256) 并在 KeyStore 中管理
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"bluetooth_enc_key_01",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setKeySize(256)
.setIsStrongBoxBacked(true) // 启用 StrongBox
.setKeyValidityStart(new Date())
.setKeyValidityEnd(new Date(System.currentTimeMillis() + 365L * 24 * 60 * 60 * 1000))
.build();
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(spec);
keyGenerator.generateKey();
2.4 密钥生命周期 API 要点
- 生成:通过
KeyGenerator(对称)或KeyPairGenerator(非对称)在指定 Provider 下创建,密钥内容不出硬件。 - 存储:KeyStore 内部将密钥句柄(引用)持久化到
/data/misc/keystore/user_0/或硬件安全存储。应用不可直接读取原始密钥材料。 - 使用:通过
Cipher、Signature、Mac等引擎初始化时引用 KeyStore 别名,加解密运算在安全世界执行。 - 销毁:调用
keyStore.deleteEntry(alias)立即删除密钥材料(硬件中也会同步擦除)。不可恢复。 - 有效期:通过
setKeyValidityStart/setKeyValidityEnd控制,过期后任何操作抛出KeyStoreException。
2.5 调试与验证
// 检查当前设备支持的 KeyStore 特性
String providerName = "AndroidKeyStore";
Provider provider = Security.getProvider(providerName);
if (provider == null) {
Log.w("KeyStoreDebug", "AndroidKeyStore not available");
} else {
Log.i("KeyStoreDebug", "Provider: " + provider.getInfo());
// 输出类似: AndroidKeyStore v1.0 (TEE based, StrongBox supported)
}
// 列出所有已有别名
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
Log.i("KeyStoreDebug", "Alias: " + alias);
if (ks.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {
Log.i("KeyStoreDebug", " -> secret key (inaccessible raw)");
}
}
调试小技巧:在 Gradle 构建中引入
com.android.support:appcompat-v7:28.0.0 仅用于读取 KeyStore 别名列表;切勿在生产直接导出密钥材料——硬件隔离的密钥根本无法导出,这是安全设计。
2.6 常见错误与稳定性优化
| 错误场景 | 原因 | 解决方法 |
|---|---|---|
生成密钥时抛 ProviderException: StrongBox not available |
设备无 StrongBox 硬件 | 改用 setIsStrongBoxBacked(false) 或捕获异常降级到 TEE |
解密时 KeyStoreException: Key user not authenticated |
设置了 setUserAuthenticationRequired(true) 但未验证用户凭证 |
在使用前调用 BiometricPrompt.authenticate() 或移除该限制 |
| 密钥过期后无法解密已有数据 | setKeyValidityEnd 设置过短 |
设计时应将有效期设为长效(如 365 天),并在业务层实现密钥轮换 |
| 蓝牙重连时 KeyStore 操作频繁导致 ANR | 每次蓝牙连接都重新创建 KeyStore 实例 | 在 Application 初始化时一次性创建 KeyStore 并缓存引用 |
2.7 性能建议
- 批量操作:若要同时使用多个密钥,优先在
Cipher.init()阶段一次性指定所有参数,避免多次加载 KeyStore。 - 缓存密钥句柄:密钥别名绑定后,
KeyStore.getKey(alias, null)返回的是句柄而非原始字节,可以复用,但注意KeyStore对象本身线程安全,无需每次加锁。 - 避免频繁生成/销毁:KeyStore 中密钥生成和销毁涉及硬件状态刷新,影响性能。蓝牙持久化场景建议生成一次密钥后长期复用,仅在被保护数据泄露风险时轮换。