第4章 Android KeyStore 集成:AndroidKeyStore Provider、生成/导入密钥、指纹解锁绑定、密钥使用限制
4.1 原理:Android KeyStore 体系与 Provider 架构
Android KeyStore 是一个硬件/软件联合的密钥存储容器,通过 AndroidKeyStore Provider 向应用层提供标准 java.security.KeyStore 接口。密钥一旦写入 KeyStore,其私钥材料在进程空间内不可直接导出,即使应用进程被攻破也无法提取明文私钥。
| 层级 | 组件 | 安全边界 |
|---|---|---|
| 应用层 | AndroidKeyStore Provider | 沙箱 + 签名隔离 |
| 框架层 | keystore2 守护进程 | SELinux + 权限校验 |
| 硬件层 | TEE / StrongBox (SE) | 物理隔离 + 防侧信道 |
Android 从 4.3(API 18)引入 KeyStore,从 6.0(API 23)起支持硬件-backed 密钥和指纹认证绑定。AndroidKeyStore Provider 是系统内置的加密 Provider,注册于 Security.insertProviderAt(),优先级高于 BC 和 SC。所有密钥生成和导入操作均通过该 Provider 委托给 keystore2 守护进程。
核心要点:AndroidKeyStore Provider 不存储密钥数据,而是存储密钥 句柄(key blob)。实际密钥材料由底层 TEE/SE 管理,应用只能通过 KeyStore 对象间接使用密钥。
4.2 实现流程:密钥生成 → 指纹绑定 → 使用限制
4.3 核心 API 与代码实现
4.3.1 生成 RSA 密钥对并绑定指纹
以下示例在 Android 9+ 上生成 RSA-2048 密钥对,要求用户通过指纹认证后才能使用私钥进行签名或解密。
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_rsa_key_v1",
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_ENCRYPT)
.setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4))
.setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
.setUserAuthenticationRequired(true) // 指纹绑定
.setUserAuthenticationValidityDurationSeconds(30) // 认证有效期 30s
.setInvalidatedByBiometricEnrollment(true) // 新增指纹后密钥失效
.build();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
kpg.initialize(spec);
KeyPair kp = kpg.generateKeyPair();
PublicKey pubKey = kp.getPublic(); // 公钥可分发
// 私钥存储在 KeyStore 中,不可直接访问
4.3.2 导入对称密钥(AES)到 KeyStore
对称密钥通常由服务端分发或在 TEE 内生成。以下示例在 KeyStore 内生成 AES-256 密钥并绑定指纹。
KeyGenParameterSpec aesSpec = new KeyGenParameterSpec.Builder(
"my_aes_key_v1",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setKeySize(256)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.setUserAuthenticationValidityDurationSeconds(10)
.build();
KeyGenerator kg = KeyGenerator.getInstance("AES", "AndroidKeyStore");
kg.init(aesSpec);
SecretKey secretKey = kg.generateKey();
// secretKey 存储在 KeyStore 中,getEncoded() 返回 null
⚠ 注意:导入外部密钥到 KeyStore 需要使用
setIsStrongBoxBacked(true)(Android 9+)确保硬件保护,或使用 KeyStore.setEntry() 配合 KeyStore.SecretKeyEntry 包装。但直接导入外部密钥会丧失“密钥不可导出”的保证,建议仅在 TEE 内部生成密钥。
4.4 密钥使用限制清单
| 限制类型 | API 方法 | 说明 |
|---|---|---|
| 认证绑定 | setUserAuthenticationRequired(true) |
每次使用私钥前必须生物识别认证 |
| 认证有效期 | setUserAuthenticationValidityDurationSeconds(s) |
认证后 s 秒内可重复使用密钥(0 表示每次操作都需认证) |
| 密钥用途 | setKeyPurpose() |
限制密钥仅可用于签名、加密或两者 |
| 算法参数 | setAlgorithmParameterSpec() |
固定密钥长度、曲线、填充模式 |
| 失效策略 | setInvalidatedByBiometricEnrollment(true) |
用户新增指纹后原密钥自动失效 |
| 超时锁定 | setKeyValidityStart/End() |
设置密钥有效时间窗口(UTC) |
| 密码验证 | setUserAuthenticationParameters() |
Android 11+ 支持锁屏密码+生物识别双重验证 |
4.5 调试与部署验证
4.5.1 确认 KeyStore Provider 可用性
java.security.Security.getProviders();
// 输出中应包含 "AndroidKeyStore" 条目
// Provider: AndroidKeyStore version 1.0
4.5.2 验证密钥是否硬件-backed
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.Entry entry = ks.getEntry("my_rsa_key_v1", null);
if (entry instanceof KeyStore.PrivateKeyEntry) {
PrivateKey priv = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
boolean isInsideTEE = priv.toString().contains("TEE") || priv.toString().contains("strongbox");
// 或检查 KeyInfo
KeyFactory factory = KeyFactory.getInstance(priv.getAlgorithm(), "AndroidKeyStore");
KeyInfo info = factory.getKeySpec(priv, KeyInfo.class);
boolean hardwareBacked = info.isInsideSecureHardware();
}
4.5.3 常见错误与排查
| 错误码 / 异常 | 原因 | 解决方案 |
|---|---|---|
KeyPermanentlyInvalidatedException |
用户新增/删除指纹导致密钥失效 | 重新生成密钥,监听 KeyStore.onKeyInvalidated() |
UserNotAuthenticatedException |
超时后未重新认证 | 捕获异常后重新触发 BiometricPrompt |
StrongBoxUnavailableException |
设备不支持 StrongBox | 降级到 TEE 实现,或检查 PackageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE) |
KeyStoreException: Invalid key blob |
密钥 blob 损坏或被篡改 | 删除旧密钥并重新生成,确保备份/恢复策略无误 |
4.6 性能与稳定性优化
- 缓存公钥:公钥可从 KeyStore 导出并通过
KeyFactory缓存到内存中,避免每次操作都查询 TEE。 - 控制认证有效期:高频操作场景设置
setUserAuthenticationValidityDurationSeconds(30~60),避免每笔操作都弹指纹。 - 异步初始化 KeyStore:将
KeyStore.load()和密钥生成放在后台线程,防止锁屏时阻塞 UI。 - 预生成密钥池:对于高并发签名/解密场景,预先创建多把短期密钥并轮换,减少单密钥热点。
- 监听指纹变更:通过
KeyStore.OnKeyInvalidatedListener(Android 11+)或BiometricManager监听生物识别变化,提前重建密钥。
💡 稳定性建议:在
Application.onCreate() 中提前加载 KeyStore 并验证密钥是否有效。如果 KeyStore.getEntry() 抛出 KeyPermanentlyInvalidatedException,立即触发密钥轮换流程,避免业务请求失败。
4.7 部署检查清单
- 确认
AndroidManifest.xml中声明USE_BIOMETRIC或USE_FINGERPRINT权限。 - 在
build.gradle中设置minSdkVersion >= 23以支持指纹绑定。 - 测试设备是否支持
FEATURE_STRONGBOX_KEYSTORE,并根据结果选择密钥存储位置。 - 编写
Instrumentation Test验证密钥生成、指纹认证超时、失效策略覆盖全部路径。 - 在 CI 流水线中增加
keystore2日志采集(adb logcat -s keystore2),捕获异常退出码。 - 使用
KeyStore.getKeyCharacteristics()验证密钥属性是否与KeyGenParameterSpec一致。