3. KeyPairGeneratorSpec 与 KeyGenParameterSpec:构建参数对象、生成RSA密钥对

Android Keystore 系统提供两套 API 用于构建 RSA 密钥对参数:KeyPairGeneratorSpec(API 18 引入,API 28 废弃)和 KeyGenParameterSpec(API 23 引入,推荐用于 API 23+ 设备)。本章将详细对比两者的差异,并演示如何通过参数对象控制密钥属性、最终生成 RSA 密钥对。

3.1 参数对象的核心作用

在调用 KeyPairGenerator.initialize() 之前,必须通过参数对象描述密钥的以下特征:

  • 算法参数:密钥大小(如 2048 位)、算法(RSA)
  • 用途:加密/解密、签名/验证、密钥协商
  • 签名摘要:SHA-256、SHA-384、SHA-512 等
  • 填充方案:PKCS1、OAEP(含摘要与掩码函数)
  • 访问控制:指纹验证、用户认证有效期、密钥始终可用
  • 密钥别名与存储:Keystore 中的唯一标识

3.2 两代 API 对比

特性 KeyPairGeneratorSpec(废弃) KeyGenParameterSpec(推荐)
最低 API 级别 API 18(Android 4.3) API 23(Android 6.0)
是否支持用途(PURPOSE) 否(仅支持加解密或签名) 是(可组合 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
签名算法指定 setSignatureAlgorithm(“SHA256withRSA”) setSignaturePaddings 与 setDigest 分开设置
加密填充指定 setEncryptionPaddings 方法 setEncryptionPaddings 更细粒度(支持 OAEP 参数)
是否支持用户认证 否 是(指纹/生物识别 + 密钥超时)
是否支持密钥生成额外参数 能够设置 setKeySize、setCertificateSubject、setCertificateSerialNumber 通过 Builder 直接构建,参数更丰富(如 setInvalidatedByBiometricEnrollment)
公认状态 API 28 废弃,不建议在新代码中使用 官方推荐,持续更新
⚠ 兼容性警告:如果应用需要支持低于 API 23 的设备,只能使用 KeyPairGeneratorSpec;此时需注意密钥用途单一(无法同时允许加密和签名),且不能使用 OAEP 填充。建议对低版本设备回退到纯软件 RSA 方案(不存于硬件 Keystore)。

3.3 使用 KeyGenParameterSpec 生成 RSA 密钥对(示例)

✏ 推荐做法:以下代码仅适用于 API 23+。密钥别名应使用公司包名前缀,避免与其他应用冲突。
// 1. 获取 KeyPairGenerator 实例,指定算法和提供者
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_RSA,
    "AndroidKeyStore");

// 2. 构建参数对象
KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(
        "my_rsa_key_alias",                          // 密钥别名
        KeyProperties.PURPOSE_ENCRYPT |               // 用途:加密
        KeyProperties.PURPOSE_DECRYPT |               // 用途:解密
        KeyProperties.PURPOSE_SIGN |                  // 用途:签名
        KeyProperties.PURPOSE_VERIFY)                 // 用途:验证
    .setDigests(KeyProperties.DIGEST_SHA256,           // 支持的摘要算法
                KeyProperties.DIGEST_SHA512)
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
                           KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
                          KeyProperties.SIGNATURE_PADDING_RSA_PSS)
    .setKeySize(2048)                                  // 密钥长度 2048 位
    .setCertificateSubject(new X500Principal("CN=MyApp"))
    .setCertificateSerialNumber(BigInteger.ONE)
    .setCertificateNotBefore(new Date())
    .setCertificateNotAfter(new Date(System.currentTimeMillis() + 365 * 24L * 60 * 60 * 1000))
    .build();

// 3. 初始化生成器
kpg.initialize(spec);

// 4. 生成密钥对(私钥自动存入 Keystore)
KeyPair keyPair = kpg.generateKeyPair();

生成的 keyPair 仅包含公钥对象;私钥始终存储在 Keystore 中,无法直接提取其明文。如需使用私钥,通过 PrivateKey 对象引用(实际调用 Keystore 硬件模块)。

3.4 生成流程与关键节点

下图展示从参数构建到密钥生成的核心步骤,以及两个 API 的版本分界点。

RSA密钥对生成流程(KeyGenParameterSpec) API ≥ 23? KeyGenParameterSpec (推荐) KeyPairGeneratorSpec (仅 API 18-28) .Builder(alias, purpose) .setKeySize(2048) .setDigests(…) kpg.initialize(spec) kpg.generateKeyPair() KeyPair(私钥在硬件中) 是 → 否 → 💡 说明 KeyPairGeneratorSpec 不支持 组合用途和 OAEP,且已被废弃。 新项目应优先使用 KeyGenParameterSpec。

3.5 常见错误与解决方案

  • NoSuchAlgorithmException: 忘记指定提供者 "AndroidKeyStore" 或使用了错误的算法名(应为 KeyProperties.KEY_ALGORITHM_RSA)。
  • InvalidAlgorithmParameterException: 在 API 23- 设备上使用了 KeyGenParameterSpec。请检查运行时 API 级别并降级到 KeyPairGeneratorSpec。
  • KeyStoreException: KeyStore not initialized: 生成密钥前需先加载 Keystore 实例(通常只需 KeyStore.getInstance("AndroidKeyStore") 并 load(null))。
  • UnsupportedOperationException: 当使用 setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 时,硬件 Keystore 可能不支持无填充。建议始终使用 PKCS1 或 OAEP。
  • 密钥别名冲突: 如果同别名密钥已存在,generateKeyPair() 会覆盖旧密钥。设计别名时建议包含版本号或时间戳。
🔥 性能要点:RSA 密钥生成属于计算密集型操作,硬件 Keystore 在生成 2048 位密钥时通常耗时 200ms~1s。应在后台线程执行生成操作,避免阻塞 UI。对于频繁创建临时密钥的场景,建议复用同一别名或预生成密钥池。