You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AndroidKeyStore导入密钥后遇公钥获取异常及证书添加失败求助

AndroidKeyStore导入私钥后无法获取条目的解决方案

问题原因

AndroidKeyStore要求私钥条目必须关联对应的X.509证书链,你导入Wrapped私钥时仅导入了私钥材料,未关联公钥证书,导致调用getEntry时抛出UnrecoverableKeyException;而setCertificateEntry失败是因为该别名已绑定为私钥条目,无法直接覆盖为可信证书条目。

解决步骤

导入私钥后,生成对应公钥的自签名证书,通过KeyStore.PrivateKeyEntry将私钥与证书绑定,覆盖原Keystore条目即可,无需使用setCertificateEntry。

1. 添加自签名证书生成方法

import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import java.math.BigInteger
import java.security.KeyPair
import java.security.cert.X509Certificate
import java.util.*

fun generateSelfSignedCertificate(keyPair: KeyPair): X509Certificate {
    val issuer = X500Name("CN=ImportedKeySelfSigned")
    val subject = issuer // 自签名证书签发者与主体一致
    val serial = BigInteger.valueOf(System.currentTimeMillis())
    val startDate = Date(System.currentTimeMillis() - 86400000) // 提前1天生效
    val endDate = Date(System.currentTimeMillis() + 365L * 86400000) // 有效期1年

    val certBuilder = JcaX509v3CertificateBuilder(
        issuer,
        serial,
        startDate,
        endDate,
        subject,
        keyPair.public
    )

    // 使用SHA256withRSA签名算法
    val signer = JcaContentSignerBuilder("SHA256withRSA")
        .setProvider("BC")
        .build(keyPair.private)

    return certBuilder.build(signer) as X509Certificate
}

2. 修改导入逻辑,绑定证书

在minimumWorkingExample方法中,导入WrappedKeyEntry后添加证书绑定代码:

fun minimumWorkingExample(isStrongBox: Boolean) {
    // ... 保留原有的密钥生成、导入逻辑 ...

    androidKeyStore.setEntry(importedKeyAlias, wrappedKeyEntry, null);
    System.out.println("Key available: ${androidKeyStore.containsAlias(importedKeyAlias)}")

    // 新增:绑定自签名证书到私钥条目
    val selfSignedCert = generateSelfSignedCertificate(keyPairToBeImported)
    val importedPrivateKey = androidKeyStore.getKey(importedKeyAlias, null) as PrivateKey
    val privateKeyEntry = KeyStore.PrivateKeyEntry(importedPrivateKey, arrayOf(selfSignedCert))
    androidKeyStore.setEntry(importedKeyAlias, privateKeyEntry, null)

    // 现在可正常获取条目
    val importedKey = androidKeyStore.getEntry(importedKeyAlias, null)
    System.out.println("isPrivateKey: ${importedKey is PrivateKey}")
    System.out.println("isPrivateKeyEntry: ${importedKey is KeyStore.PrivateKeyEntry}")
}

3. 额外注意事项

  • 确保BouncyCastle Provider已注册,可在代码初始化阶段添加:
import java.security.Security
import org.bouncycastle.jce.provider.BouncyCastleProvider

// 注册BC Provider
Security.addProvider(BouncyCastleProvider())
  • 你的wrappedKeyAuthorizationList中未配置签名所需的摘要算法,会导致后续签名操作失败,建议补充:
private fun wrappedKeyAuthorizationList(size: Int): DERSequence {
    // ... 原代码 ...
    val allDigests: ASN1EncodableVector = ASN1EncodableVector()
    allDigests.add(ASN1Integer(KeyProperties.DIGEST_SHA256.toLong())) // 添加SHA256摘要
    val digestSet: DERSet = DERSet(allDigests)
    // ... 原代码 ...
}

内容的提问来源于stack exchange,提问作者Gamer2015

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 06:32:34