第1章 Android Keystore架构概览
1.1 架构全景图
Android Keystore 并非单一组件,而是一套自底向上、多层协作的密钥管理体系。理解其整体架构,是后续章节所有实现的基础。最上层是应用开发者直接调用的 Keystore Provider(通过 java.security.KeyStore 或 android.security.keystore 包访问),向下经过系统服务层、硬件抽象层,最终抵达硬件安全模块。
1.2 Keystore 系统服务
系统服务运行在 system_server 进程中,是应用与硬件安全模块之间的桥梁。它负责统一管理密钥生命周期、强制执行访问控制策略,并维护全局锁定状态。
1.2.1 核心职责
- 密钥生成与导入:调用 Keymaster HAL 在安全硬件中生成或导入密钥。
- 密钥删除:根据 UID 和别名删除密钥,同时清除安全硬件中的对应密钥槽。
- 访问审计:记录每次密钥操作的发起方 UID、操作类型和时间戳。
- 锁定状态管理:监听设备锁屏/解锁广播,切换密钥的可用状态。
1.2.2 注册与绑定流程
应用通过 Context.getSystemService 获取 KeyStore 实例,内部通过 Binder IPC 与系统服务通信。服务端会校验调用方的 UID 和权限。
KeyStore.getInstance() 返回 null,通常是因为系统服务未运行或 SELinux 策略拒绝访问。可以通过 adb shell dumpsys keystore 查看服务状态。
1.3 硬件安全模块(HSM)
Android Keystore 的安全根基在于将密钥材料与常规操作系统隔离开。根据设备硬件能力,HSM 有三种实现形态:
| 实现形态 | 安全等级 | 典型硬件 | 支持算法 | 可用性 |
|---|---|---|---|---|
| 软件安全模块 | 低(依赖文件系统加密) | 无专用硬件 | AES, RSA, EC | 所有设备(兜底) |
| TEE(TrustZone) | 中 | ARM TrustZone | AES, RSA, EC, HMAC | Android 7.0+ 主流设备 |
| StrongBox / SE | 高(独立安全芯片) | eSE, Titan M, S3K | 有限集(通常不含非对称) | Android 9.0+ Pixel / 企业设备 |
1.3.1 查询设备 HSM 能力
开发前应检查当前设备支持的硬件安全模块等级:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
// 生成一个测试密钥用于查询
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"_test_key_", KeyProperties.PURPOSE_SIGN)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setIsStrongBoxBacked(true) // 尝试请求 StrongBox
.build();
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
try {
kpg.initialize(spec);
kpg.generateKeyPair();
// 成功表示设备支持 StrongBox
} catch (ProviderException e) {
// 回退到 TEE 或软件实现
}
setIsStrongBoxBacked(true) 会抛出 java.security.ProviderException: StrongBox not available。生产代码必须捕获此异常并提供回退逻辑。
1.4 密钥存储分区
Android Keystore 采用 多租户隔离 的存储模型。每个应用(以 UID 标识)拥有独立的密钥存储空间,彼此不可见。密钥数据在文件系统中以加密形式存储于:
/data/misc/keystore/user_0/
分区路径包含 user_id,因此同一设备上的不同用户(如工作资料、多用户模式)拥有完全隔离的密钥仓库。密钥文件名以加密哈希形式存储,避免别名泄露。
1.4.1 密钥属性分区
每个密钥除了存储在安全硬件中的密钥材料外,系统中还维护一份元数据记录,包含:
- UID:创建该密钥的应用标识。
- 别名:应用指定的引用名(加密存储)。
- 用途标志:加密/解密/签名/验证。
- 访问条件:是否需要用户认证、超时策略。
# 密钥别名与 UID 映射示例(内部格式,仅供理解)
key_0xabc123:
uid: 10123
alias_hash: e3b0c44298fc1c149afbf4c8996fb924
purpose: encrypt|decrypt
auth_required: true
auth_timeout_seconds: 300
1.5 访问控制模型
访问控制是 Keystore 安全性的最后一道防线。即使攻击者获得 root 权限,也无法直接获取密钥材料,但可以通过伪装 UID 发起操作请求。访问控制模型从三个维度进行防御:
| 控制维度 | 机制 | 配置方式 |
|---|---|---|
| UID 绑定 | 系统服务强制校验调用方 UID 是否匹配密钥创建者 | 自动,开发者无需配置 |
| 用户认证 | 需要解锁设备 / 生物识别 / 锁屏密码 | setUserAuthenticationRequired(true) |
| 密钥用途授权 | 密钥生成时声明合法操作,后续不可变更 | setPurpose(key_purpose) |
| 锁定状态 | 设备锁屏后,需要认证的密钥自动失效 | 自动,依赖 DevicePolicyManager |
| 超时策略 | 用户认证后,密钥仅在指定时间内可用 | setUserAuthenticationValidityDurationSeconds(n) |
1.5.1 锁定状态与密钥可用性
设备锁屏后,所有标记为 setUserAuthenticationRequired(true) 的密钥将立即变为不可用状态,直到用户再次解锁。此行为不可绕过。
setUserAuthenticationValidityDurationSeconds(30),让一次解锁在 30 秒内免除重复认证。这能显著减少对生物识别硬件的反复唤醒。
1.6 调试与验证
使用以下命令快速验证当前设备 Keystore 状态:
# 查看 Keystore 系统服务运行状态
adb shell dumpsys keystore
# 查看系统密钥列表(需 root)
adb shell su -c "ls -la /data/misc/keystore/user_0/"
# 测试特定应用能否创建密钥
adb shell pm clear com.example.myapp
# 重新打开应用并检查 logcat
adb logcat -s "KeyStore"
dumpsys keystore 返回 Can't find service: keystore,说明系统服务崩溃或未启动。在原生 AOSP 设备上,通常需要重启 system_server 或重新烧录系统映像。
1.7 性能与稳定性考量
- 避免频繁创建密钥:密钥生成涉及安全硬件通信,每次耗时约 50-200ms。推荐在应用启动时创建,然后缓存
PrivateKey或SecretKey句柄。 - 异步操作:所有的 Keystore 操作(生成、签名、加密)不应在主线程执行。使用
AsyncTask、Coroutine或HandlerThread避免 ANR。 - 密钥别名冲突:不同模块使用共同别名时会导致密钥覆盖。建议采用包名前缀,例如
com.example.secure_chat.encryption_key。
1.8 章节小结
Android Keystore 的架构以 系统服务 + 硬件隔离 + 分区存储 + 强制访问控制 为四大支柱。开发者应当熟记:密钥材料永远不应离开安全硬件;访问策略在密钥生成时固化;调试时优先检查 dumpsys keystore 和 logcat。本章建立的架构视角,将贯穿后续所有实战章节。