4. Android Keystore系统概述
Android Keystore 并不是一个简单的“密钥文件仓库”,而是一套从应用 API 到系统服务、再到硬件安全模块的完整密钥管理链路。理解它的历史演进、架构分层以及 Keymaster/KeyMint 的角色,是后续进行密钥生成、加解密、签名验签和身份认证开发的基础。很多开发者只记住 KeyStore.getInstance("AndroidKeyStore") 这一行代码,却忽略了密钥真正存放在哪里、由谁保护、如何被硬件绑定,导致在设备迁移、指纹变更、系统升级时出现难以排查的问题。
一、历史演进:从文件密钥库到硬件密钥库
Android 的密钥管理经历了明显的三个阶段。早期 Android 2.x 到 4.x 时代,开发者通常使用 BKS 或 PKCS#12 文件型密钥库,密钥以软件形式保存在应用私有目录中。这类方案的问题很直接:只要设备被 root,攻击者就能复制密钥文件,密钥与设备之间没有强绑定关系。
Android 4.3(API 18)引入了 Android Keystore Provider,密钥开始由系统服务统一管理,应用只能通过句柄引用密钥,无法直接导出私钥。这是“密钥不离开安全边界”理念的起点。Android 6.0(API 23)进一步引入 Keymaster 2,支持 AES 对称密钥、指纹绑定和密钥认证。Android 7.0 引入 Keymaster 3,使用 HIDL 接口,并支持 ECDSA、RSA 的硬件密钥。Android 8.0 引入 Keymaster 4,支持 StrongBox 独立安全芯片。Android 12 开始,Google 推出 KeyMint 替代 Keymaster,使用 AIDL 接口,成为新设备的主流实现。
二、架构组成:四层协作模型
Android Keystore 的架构可以划分为四个层次。最上层是应用层,开发者通过 KeyStore、KeyGenerator、KeyPairGenerator、Cipher、Signature 等标准 JCA/JCE API 访问密钥。第二层是框架层,由 keystore2 系统服务负责密钥生命周期管理、访问控制和权限校验。第三层是 HAL 层,即 Keymaster 或 KeyMint,负责把上层请求转换为具体安全环境可执行的密码学操作。最底层是安全环境,可能是 TEE(可信执行环境)、StrongBox 独立芯片,或在无硬件支持时退化为软件实现。
这种分层带来的关键特性是:应用拿到的不是密钥本身,而是密钥的别名和操作句柄。真正的私钥或对称密钥始终留在 TEE 或 StrongBox 中,加解密和签名操作在安全环境内部完成,应用只能获得结果。这就是 Android Keystore 与普通文件密钥库最本质的区别。
三、Keymaster 与 KeyMint 的作用
Keymaster 和 KeyMint 是 Android Keystore 与安全硬件之间的“翻译官”和“执行器”。它们定义了一组标准接口,把上层“生成一个 RSA 2048 密钥”“用别名 myKey 做 SHA256withRSA 签名”这样的请求,转换为 TEE 或 StrongBox 能理解的命令。同时,它们还负责密钥的导入、导出(仅限公钥)、删除、认证、随机数生成和密钥证明。
Keymaster 早期使用 C++ 接口,Android 8 之后使用 HIDL。Android 12 引入的 KeyMint 改用 AIDL,接口更清晰,并强化了对 StrongBox、密钥认证和远程证明的支持。对于开发者而言,Keymaster 与 KeyMint 的差异通常被系统服务屏蔽,但在排查设备兼容性、密钥认证失败或 StrongBox 不可用时,必须知道当前设备到底走的是哪条 HAL 路径。
| 对比项 | Keymaster | KeyMint |
|---|---|---|
| 引入版本 | Android 6.0 起逐步完善 | Android 12 起成为主流 |
| 接口方式 | HIDL(Android 8+) | AIDL |
| 典型版本 | Keymaster 2 / 3 / 4 | KeyMint 1 / 2 / 3 |
| StrongBox 支持 | Keymaster 4 开始支持 | 原生强化支持 |
| 开发者感知 | 通常透明 | 通常透明,但影响设备能力 |
四、典型场景:密钥生成与签名调用链
下面以生成一个硬件支持的 EC 密钥并签名一段数据为例,展示从应用到安全环境的调用链。注意代码中并没有出现私钥,私钥始终由 KeyMint/Keymaster 在安全环境中持有。
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
"mySignKey",
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setDigests(KeyProperties.DIGEST_SHA256)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setUserAuthenticationRequired(true)
.build());
KeyPair kp = kpg.generateKeyPair();
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initSign(kp.getPrivate());
sig.update("hello keystore".getBytes());
byte[] signature = sig.sign();
调用链为:应用调用 generateKeyPair() → keystore2 校验参数与权限 → KeyMint/Keymaster 在 TEE 或 StrongBox 中生成密钥 → 返回公钥和密钥别名。签名时,应用把数据交给 Signature,系统把数据送入安全环境,由安全环境用私钥完成签名,再把签名结果返回应用。
KeyInfo 中的 isInsideSecureHardware(),或使用密钥认证(Key Attestation)解析证书扩展中的安全级别。不要仅凭“用了 AndroidKeyStore”就认为密钥一定在硬件中。
五、常见误区与复盘
- 误区一:AndroidKeyStore 等于硬件密钥库。实际上它可能回退到软件实现,是否硬件保护取决于设备能力和密钥生成参数。
- 误区二:密钥可以随意导出。私钥和对称密钥不可导出,只能导出公钥;试图导出私钥会抛出异常。
- 误区三:忽略用户认证绑定。设置
setUserAuthenticationRequired(true)后,密钥使用会受锁屏和生物识别状态影响,设备重置或指纹变更可能导致密钥失效。 - 误区四:不处理 StrongBox 不可用。调用
setIsStrongBoxBacked(true)时,若设备不支持会抛出StrongBoxUnavailableException,应做好降级。