第3章 密钥生成基础:KeyPairGeneratorSpec用法、椭圆曲线与RSA密钥对生成

Android Keystore 系统提供硬件级(TEE/StrongBox)密钥存储,所有密钥材料永不离开安全环境。本章聚焦两种最常用的非对称算法——RSA 和 椭圆曲线(EC),讲解如何使用 KeyPairGeneratorSpec 在 Keystore 内安全生成密钥对,并对比两者在安全等级、性能、兼容性上的差异。

3.1 原理:KeyPairGeneratorSpec 与 Keystore Provider

KeyPairGeneratorSpec 是 Android 4.3(API 18)引入的构造类,用于定义密钥对的属性(算法、用途、别名、有效期等),再通过 KeyPairGenerator 初始化,最终在 Keystore 内生成密钥对。其核心原理在于:

  • Provider 绑定:必须使用 "AndroidKeyStore" Provider,否则密钥将落入软件层,不受硬件保护。
  • Spec 参数:除算法外,还需指定 Context、别名、密钥用途(如 PURPOSE_ENCRYPT | PURPOSE_DECRYPT)、有效期等。
  • RSA 特点:常用 2048 或 4096 位,支持加密/签名,但加解密性能低于 EC。
  • EC 特点:常用 P-256(prime256v1),同等安全等级下密钥更短、签名更快,但 Android 6.0 以下支持不全。

3.2 实现流程

  1. 获取 Keystore 实例:KeyStore.getInstance("AndroidKeyStore"),并加载 .load(null)。
  2. 构建 KeyPairGeneratorSpec.Builder,设置上下文、别名、算法、用途、有效期。
  3. 实例化 KeyPairGenerator:KeyPairGenerator.getInstance(keyAlgorithm, "AndroidKeyStore")。
  4. 调用 generator.initialize(spec) 完成初始化。
  5. 调用 generator.generateKeyPair(),生成的密钥对自动存入 Keystore。
  6. 后续通过别名从 Keystore 读取公钥和私钥引用。

3.3 代码示例:生成 RSA 与 EC 密钥对

RSA 2048 位密钥对(API 23+)

import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import java.security.KeyPairGenerator;
import java.security.KeyStore;

Context context = ...;
String alias = "my_rsa_key";
KeyPairGenerator generator = KeyPairGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");

KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias,
        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
        .setKeySize(2048)
        .setCertificateSubject(new X500Principal("CN=MyApp"))
        .setCertificateSerialNumber(BigInteger.valueOf(1))
        .setKeyValidityStart(...)
        .setKeyValidityEnd(...)
        .build();

generator.initialize(spec);
generator.generateKeyPair();

EC P-256 密钥对(API 23+)

KeyPairGenerator generatorEC = KeyPairGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");

KeyGenParameterSpec specEC = new KeyGenParameterSpec.Builder("my_ec_key",
        KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
        .setDigests(KeyProperties.DIGEST_SHA256)
        .setAlgorithmParameterSpec(new ECGenParameterSpec("prime256v1"))
        .setCertificateSubject(new X500Principal("CN=ECKey"))
        .setCertificateSerialNumber(BigInteger.valueOf(2))
        .build();

generatorEC.initialize(specEC);
generatorEC.generateKeyPair();
提示: API 23 以下需使用已废弃的 KeyPairGeneratorSpec(非 KeyGenParameterSpec)。如果项目最低版本低于 23,请使用兼容库或条件判断分支。

3.4 RSA 与 EC 特性对比

特性 RSA EC(P-256)
密钥长度 2048 / 4096 位 256 位
安全等级 112 / 128 位等效 128 位等效
签名性能 较慢(尤其私钥签名) 快 5~10 倍
加密支持 是(OAEP/PKCS1) 否(EC仅签名/密钥交换)
Android 最低版本 API 18(基础支持) API 18(P-256 需 API 23+ 稳定)
硬件安全模块 大多数 TEE 支持 部分低端设备不支持 EC 硬件加速

3.5 调试:验证密钥已正确存储

KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
if (ks.containsAlias("my_ec_key")) {
    PublicKey pub = ks.getCertificate("my_ec_key").getPublicKey();
    PrivateKey priv = (PrivateKey) ks.getKey("my_ec_key", null);
    Log.d("Keystore", "EC key pair retrieved, pub algo: " + pub.getAlgorithm());
} else {
    Log.w("Keystore", "Key alias not found");
}

3.6 常见错误与解决

  • “KeyStoreException: KeyStore not initialized” — 忘记调用 .load(null)。
  • “InvalidAlgorithmParameterException: KeyGenParameterSpec is not supported” — 确认 API level ≥ 23,或改用旧版 KeyPairGeneratorSpec。
  • “NoSuchProviderException: Provider not available” — 确保使用字符串 "AndroidKeyStore",而非空 Provider。
  • “KeyStoreException: keypair generation failed” — 通常因设备 TEE 不支持指定算法或密钥大小,可尝试降级为 2048 RSA 或 P-256 EC。
兼容性警告: Android 6.0(API 23)之前,KeyGenParameterSpec 不可用。若需支持更低版本,必须使用 KeyPairGeneratorSpec 且无法设置用途、填充等细粒度参数。建议 minSdkVersion 设为 23 以简化代码。

3.7 性能与稳定性优化

  • 密钥大小选择:优先使用 2048 位 RSA 或 P-256 EC,避免 4096 位 RSA 在低端设备上生成时间超过 5 秒。
  • 生成过程异步:generateKeyPair() 可能涉及硬件交互,应放在后台线程(如 AsyncTask 或 Coroutine),避免阻塞 UI。
  • 缓存公钥:公钥不会泄露安全,可从 Keystore 读取后缓存到内存,减少 I/O 开销。
  • 密钥复用:同一业务角色建议复用同一个别名,不要频繁生成新密钥对,以免 Keystore 条目膨胀。

3.8 密钥生成流程图

Android Keystore 密钥生成流程(RSA / EC) 构建 KeyGenParameterSpec(算法/用途/别名) 初始化 KeyPairGenerator(AndroidKeyStore Provider) generator.generateKeyPair() 硬件 TEE 可用? 密钥材料存储于TEE/StrongBox 私钥不可导出 仅软件Keystore 私钥可被Root提取 密钥对自动存入 Keystore,返回引用 说明: 所有步骤需指定AndroidKeyStore Provider
关键要点:
  • EC P-256 在签名场景下性能优于 RSA,且同等安全等级密钥更短。
  • RSA 仍适用于需要加密/解密的场景(如传输对称密钥)。
  • 务必在 generateKeyPair() 前检查设备是否支持硬件 Keystore,可通过 KeyStore.getInstance("AndroidKeyStore") 抛异常与否判断。