从 Bouncy Castle 中的文本创建 RSA 公钥的问题

Posted

技术标签:

【中文标题】从 Bouncy Castle 中的文本创建 RSA 公钥的问题【英文标题】:Problem creating RSA public key from text in Bouncy Castle 【发布时间】:2019-08-30 06:08:06 【问题描述】:

我在从公钥文本创建公钥时遇到问题。我从这个链接Creating RSA Public Key From String 找到了解决方案。他们提到将 Bouncy Castle(轻量级 API)作为一个库来解决将公钥字符串转换为 RSA 公钥时出现的 InvalidKeySpecException 错误。但是这个解决方案在我的情况下失败了。程序在这里抛出异常

线程“main”java.lang.IllegalArgumentException 中的异常:错误的序列大小:9

Creating RSA Public Key From String

   String publicKeyB64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3AQKDhhtcM5A1a8R9/VX" +
            "mrocKGaQlat2/MRFy/Y1fTabYyKkfgaRXyrHiRn+imq3ljEgx/vLRTTPtLt8H79a" +
            "iMU6WJkQwG504NCnDRVB9DZBoAYDtBkjtje7I2Xs3tzvlNwM0bcCmmj/6QE9rHEv" +
            "xhvvXO8M332hINORLNiCF6NvYHrIVSa8EU4F0bnlWpoNi0YhP45uyOOuPpVmsaxp" +
            "MWOycf3nTICKK5BDylnVO7kMcL1utJxOOb1fsotaLuge4fF84DG4cPpLZko3ksB/" +
            "voOLTDv5QRsn++8qRciK4sptlnOs8g2TrXjE/rZlP9QmpUV4a3iQ1WmsqWQVizmw" +
            "PwIDAQAB";

    byte[] decoded = Base64.getDecoder().decode(publicKeyB64);
    org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(decoded);
    BigInteger modulus = pkcs1PublicKey.getModulus();
    BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey generatedPublic = kf.generatePublic(keySpec);
    System.out.printf("Modulus: %X%n", modulus);
    System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent); // 17? OK.
    System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", generatedPublic.getClass().getName(), generatedPublic instanceof RSAPublicKey);

所以我真的很期待处理这个问题的建议。

【问题讨论】:

您的数据不是 RSA 公钥,它是 RSA 私钥,采用 PKCS1 aka CRT 形式,允许提取私钥或公钥字段。使用org.bouncycastle.asn1.pkcs.RSAPrivateKey——并且不要将该密钥用于任何事情,因为它已被泄露。 对此我很抱歉。我更新了公钥,但它抛出 Exception in thread "main" java.lang.IllegalArgumentException: invalid object in getInstance: org.bouncycastle.asn1.DLSequence 【参考方案1】:

如果您的公钥是正确的,那么您应该能够在命令行上读取它以解决问题。尝试使用这些命令:

$ openssl rsa -inform PEM -pubin -in pub.key -text -noout
$ openssl pkey -inform PEM -pubin -in pub.key -text -noout

将“pub.key”替换为您的公钥文件。

【讨论】:

这仅适用于 X.509 SubjectPublicKeyInfo 格式的(公共)密钥,OpenSSL 调用 PUBKEY,Java 调用 X509EncodedKeySpec,并且仅当您添加正确的 PEM BEGIN 和 END 行时。这不是 RSA 公钥的唯一有效表示 - 尽管此 Q 中的密钥不是 RSA 公钥的任何表示。 对此我很抱歉。我在我的代码中更新了公钥,但它抛出 Exception in thread "main" java.lang.IllegalArgumentException: invalid object in getInstance: org.bouncycastle.asn1.DLSequence【参考方案2】:

您现在编辑的数据是公钥,但不是PKCS1格式;它采用更常见(通常更有用)的 X.509 SubjectPublicKeyInfo 格式。 the Q you linked 中解释了这种差异。虽然 BouncyCastle 支持这种格式,但 Java 加密 (JCA) 也使用(技术上不精确的)名称 X509EncodedKeySpec 直接支持这种格式,所以这样做要简单得多:

byte[] decoded = Base64.getDecoder().decode(publicKeyB64);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey generatedPublic = kf.generatePublic(new X509EncodedKeySpec(decoded));

【讨论】:

以上是关于从 Bouncy Castle 中的文本创建 RSA 公钥的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Bouncy Castle 创建与 OpenSSH 兼容的 ED25519 密钥?

Bouncy Castle 从公钥加密会话数据包中提取 PGP 会话密钥

在没有 Bouncy Castle 的情况下,如何在 java 中从私有(ecdsa)生成公钥?

markdown CSS 3D Bouncy Castle

如何使用Bouncy Castle Crypto API来加密和解密数据

Bouncy Castle PGP 解密问题