第2章 KeyStore与KeyPairGenerator初始化

本章讲解如何初始化Android KeyStore实例、加载底层Provider、设置密码算法参数,最终生成非对称密钥对。这是所有密钥管理操作的起点,错误配置将直接导致后续签名/加密失败。

2.1 核心组件与初始化流程

Android KeyStore 本质是一个硬件/软件安全容器,通过 KeyStore.getInstance 获取单例。初始化涉及以下关键步骤:

  1. 获取KeyStore实例:指定类型为 "AndroidKeyStore"。
  2. 加载Provider:调用 KeyStore.load(null) 绑定系统Provider。
  3. 配置密钥参数:通过 KeyPairGeneratorSpec.Builder 设置别名、算法、有效期、签名算法等。
  4. 生成密钥对:调用 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 / OAEPOAEP 更安全但兼容性稍差
有效期不设置或设置合理过期长期密钥建议指定 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 图概括了从实例化到密钥对产出的完整逻辑流程,包括必要的异常分支:

KeyStore 初始化 & 密钥对生成流程 KeyStore.getInstance() keyStore.load(null) KeyGenParameterSpec.Builder() 设置算法/用途/填充/大小 KeyPairGenerator.initialize() 绑定Spec generateKeyPair() 私钥写入HSM / TEE 获取PublicKey 异常捕获

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 倍。