第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 实现流程:密钥生成 → 指纹绑定 → 使用限制

Android KeyStore 密钥生命周期与指纹绑定流程 1. KeyGenParameterSpec 构建 算法 / 密钥用途 / 指纹绑定 / 使用限制 2. KeyPairGenerator.getInstance(“RSA”, “AndroidKeyStore”) 使用 AndroidKeyStore Provider 初始化生成器 3. KeyPairGenerator.generateKeyPair() 私钥写入 KeyStore,公钥返回应用 4. setUserAuthenticationRequired(true) 指纹 / 生物识别解锁后才能使用私钥 5. 密钥使用限制生效 有效期 / 用途 / 密码验证 / 锁定超时 6. Cipher / Signature 操作(TEE 内执行) ⚠ 关键约束 • 私钥不可导出 • 指纹认证超时默认 30s • 锁屏后密钥立即失效 • StrongBox 需硬件支持

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 部署检查清单

  1. 确认 AndroidManifest.xml 中声明 USE_BIOMETRIC 或 USE_FINGERPRINT 权限。
  2. 在 build.gradle 中设置 minSdkVersion >= 23 以支持指纹绑定。
  3. 测试设备是否支持 FEATURE_STRONGBOX_KEYSTORE,并根据结果选择密钥存储位置。
  4. 编写 Instrumentation Test 验证密钥生成、指纹认证超时、失效策略覆盖全部路径。
  5. 在 CI 流水线中增加 keystore2 日志采集(adb logcat -s keystore2),捕获异常退出码。
  6. 使用 KeyStore.getKeyCharacteristics() 验证密钥属性是否与 KeyGenParameterSpec 一致。