第2章 KeyStore与KeyPairGenerator初始化
本章讲解如何初始化Android KeyStore实例、加载底层Provider、设置密码算法参数,最终生成非对称密钥对。这是所有密钥管理操作的起点,错误配置将直接导致后续签名/加密失败。
2.1 核心组件与初始化流程
Android KeyStore 本质是一个硬件/软件安全容器,通过 KeyStore.getInstance 获取单例。初始化涉及以下关键步骤:
- 获取KeyStore实例:指定类型为
"AndroidKeyStore"。 - 加载Provider:调用
KeyStore.load(null)绑定系统Provider。 - 配置密钥参数:通过
KeyPairGeneratorSpec.Builder设置别名、算法、有效期、签名算法等。 - 生成密钥对:调用
KeyPairGenerator.generateKeyPair()完成创建。
重要提示:Android 6.0 以上推荐使用
KeyGenParameterSpec 替代 KeyPairGeneratorSpec,后者已废弃。
2.2 初始化代码示例
// 获取 AndroidKeyStore 实例
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null); // 参数为 null 表示使用默认 Provider
// 生成密钥对的参数构建器(Android 6.0+ 方式)
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"my_key_alias", // 别名
KeyProperties.PURPOSE_SIGN |
KeyProperties.PURPOSE_VERIFY) // 用途
.setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(
KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
.setKeySize(2048) // 密钥长度
.build();
// 初始化 KeyPairGenerator
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore");
kpg.initialize(spec);
// 生成密钥对(私钥存储在硬件安全模块中)
KeyPair keyPair = kpg.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
2.3 算法参数对比表
| 参数项 | 推荐值 | 说明 |
|---|---|---|
| 算法 | RSA / EC | 非对称算法,RSA 兼容性高,EC 性能更优 |
| 密钥长度 | 2048 (RSA) / 256 (EC) | 低于此值安全风险高 |
| 摘要算法 | SHA-256 / SHA-384 | 避免使用 SHA-1 |
| 填充方式 | PKCS1 / OAEP | OAEP 更安全但兼容性稍差 |
| 有效期 | 不设置或设置合理过期 | 长期密钥建议指定 setKeyValidityStart/End |
2.4 Provider加载与异常处理
加载 Provider 时最常见错误是 KeyStoreException: KeyStore not initialized,通常由 load(null) 未调用导致。另外,Android 9 以下某些设备可能不支持特定的加密算法组合,建议在初始化时捕获 InvalidAlgorithmParameterException:
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
"aes_key",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
keyGenerator.init(spec);
} catch (NoSuchAlgorithmException | NoSuchProviderException |
InvalidAlgorithmParameterException e) {
// 回退到软件实现或提示用户
Log.e("KeyStoreInit", "硬件KeyStore不支持该配置", e);
}
调试陷阱:使用
"AndroidKeyStore" Provider 时,私钥无法直接提取为字节流,所有签名/解密操作必须在 Cipher / Signature 中通过密钥别名引用,不要尝试用 getEncoded() 获取私钥——会返回 null。
2.5 KeyStore与KeyPairGenerator初始化流程
下面的 SVG 图概括了从实例化到密钥对产出的完整逻辑流程,包括必要的异常分支:
2.6 常见错误与排错清单
- KeyStore not initialized:忘记调用
load(null),或者调用了带密码的load(inputStream, password)但未正确释放。 - Invalid algorithm parameter:低版本 Android 不支持某些组合(如 RSA+OAEP+NoPadding),建议先查询
KeyCharacteristics或降级方案。 - KeyStoreException: KeyStore is locked:某些 OEM 设备在锁屏后限制 KeyStore 访问,需在用户解锁后重新初始化。
- Private key operations fail with "Operation not supported":可能使用了
SecureRandom手动生成密钥而不是委托给 TEE,请始终使用KeyPairGenerator或KeyGenerator。
调试命令(ADB):
# 查看KeyStore别名列表及特性
adb shell dumpsys android.security.keystore
# 列出所有密钥别名
adb shell 'su 0 grep -i alias /data/misc/keystore/user_0/*'
2.7 性能与稳定性建议
- 初始化
KeyStore实例尽量在应用启动时一次性完成,避免每次签名都重新获取。 - 生成密钥对是一个耗时操作(RSA 2048 在部分设备上可达 2-3 秒),建议在后台线程执行并显示加载动画。
- 为每个功能模块创建独立别名,避免单一密钥被误删除导致全线业务失效。
- 对于高频签名场景,优先使用 EC 算法(P-256)代替 RSA,速度提升约 5 倍。