java - RSA - Java 的 KeyFactory 失败,而 bouncycaSTLe 的 PEM 解析器成功

标签 java rsa bouncycastle

我有一个 PEM 格式的公钥(从 iOS 设备接收):

String pemPubKey = ""+
"-----BEGIN RSA PUBLIC KEY-----\n"+
"MIIBCgKCAQEA07ACQHTTrgX7ddNtyamh58xwD+S+pSrJz/Rah4zj0HIg4V/Ok5vk\n"+
"Wx6y4UyuKLCtefeiB2ipg/n1ZZ0eRac1B4UwPhAtILGQzgIUgOp0cQ3Cb94ugq92\n"+
"wxkxeEdWmIFIlXgWOf6I8yWp9DZaigrRhA2kPbY01zKxCsX1ZxKMVu2sU/HM1hJy\n"+
"aebLLND002yLzuRDLXbacmCt5U6vDQDjBmm3uZ26fEMF+GTCnn6fJBq5RDfRKjpS\n"+
"fVM0mCePO9RHiwu3oHfqoyLA2QGlCexXcIYq7KbJjC9vcamAWRqQdHlsSj5ezDTR\n"+
"GofA6HtQ+zNdGHOvqsYtbN8MJSlUXXy39wIDAQAB\n"+
"-----END RSA PUBLIC KEY-----";

如果我尝试使用 KeyFactory 将其解析为 PublicKey ,如下所示:

KeyFactory kf = KeyFactory.getInstance("RSA");
Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");
String encoded = parse.matcher(pemPubKey).replaceFirst("$1");
byte[] pem = Base64.getMimeDecoder().decode(encoded);
PublicKey pubKey = kf.generatePublic(new X509EncodedKeySpec(pem));

我得到:java.security.InvalidKeyException:IOException:algid解析错误,不是序列

但是当我像这样使用 bouncycaSTLe 时:

SubjectPublicKeyInfo subjectPublicKeyInfo =
    (SubjectPublicKeyInfo) new PEMParser(new StringReader(pemPubKey)).readObject();

PublicKey pubKey;

if (PKCSObjectIdentifiers.rsaEncryption == subjectPublicKeyInfo.getAlgorithm().getAlgorithm()) {
    DLSequence der = (DLSequence) subjectPublicKeyInfo.parsePublicKey().toASN1Primitive();
    ASN1Object modulus, exponent;
    modulus = (ASN1Object) der.getObjectAt(0);
    exponent = (ASN1Object) der.getObjectAt(1);
    RSAPublicKeySpec spec =
            new RSAPublicKeySpec(new BigInteger(modulus.toString()), new BigInteger(exponent.toString()));
    KeyFactory factory = KeyFactory.getInstance("RSA");
    pubKey = factory.generatePublic(spec);
} else {
    // Throw some exception
}

我获得了有效的PublicKey并且算法被正确识别。

为什么java的解析器在这里失败?我是否正确地从 SubjectPublicKeyInfo 迁移到 PublicKey

更新:

我尝试使用openssl验证 key :

$ openssl rsa -inform PEM -pubin -in pub.pem -text -noout unable to load Public Key 140735659656136:error:0906D06C:PEM routines:PEM_read_bio:no start line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pem/pem_lib.c:704:Expecting: PUBLIC KEY

从页眉/页脚中删除 RSA 后:

$ openssl rsa -inform PEM -pubin -in pub.pem -text -noout unable to load Public Key 140735659656136:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:1164: 140735659656136:error:0D07803A:asn1 encoding routines:ASN1_ITEM_EX_D2I:nested asn1 error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:314:Type=X509_ALGOR 140735659656136:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/asn1/tasn_dec.c:653:Field=algor, Type=X509_PUBKEY 140735659656136:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.50.2/libressl/crypto/pem/pem_oth.c:84:

最佳答案

Java 的解析器没有失败,您的公钥不是Java 的X509EncodedKeySpec 所期望的编码的SubjectPublicKeyInfo 结构的实例。我还没有详细了解 BouncycaSTLe 例程来了解它为何成功,但 PEMParser 旨在解析许多不同类型的所谓“PEM”文件。

SubjectPublicKeyInfo 在 RFC 5280 中定义如:

SubjectPublicKeyInfo  ::=  SEQUENCE  {
     algorithm            AlgorithmIdentifier,
     subjectPublicKey     BIT STRING
}

您的公钥是一个简单的 PKCS#1 RSAPublicKey,定义于 RFC 8017如:

RSAPublicKey ::= SEQUENCE {
             modulus           INTEGER,  -- n
             publicExponent    INTEGER   -- e
         }

关于“PEM”文件的最后一句话。在将某些内容描述为“PEM”格式时需要小心,因为 PEM 并不是真正的特定格式。 “PEM”只不过是用 Base64 编码真正的格式,然后将 Base64 包装在“-----BEGIN -----”和“-----END -----”行中,其中 < em>希望能够唯一地描述什么是base64编码的数据。

关于java - RSA - Java 的 KeyFactory 失败,而 bouncycaSTLe 的 PEM 解析器成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53315499/

相关文章:

java - PKCS#7 登录并验证签名

java - Activity之间如何同步数据?

java - 如何在同一个浏览器中打开多个选项卡?

iOS:是否可以在您的应用程序文档目录中存储 RSA 私钥(用于解密文本)?

licensing - PHP 中的 RSA_sign 或 DSA_sign!

c# - 从 RSACryptoServiceProvider 获取公钥?

c# - Bouncy CaSTLe 中的 TlsSignerCredentials 和 TlsAgreementCredentials 有什么区别

java - 如何在没有数字签名的情况下添加时间戳

java - 申请Java构造函数

java - 解析数字时出现 NumberFormatException