在Java中为OpenSSL格式化RSA密钥

16

背景

在Linux上使用以下命令,在OpenSSL中生成RSA密钥:

openssl genrsa -out mykey.pem 1024

此命令创建了以下内容:

"-----BEGIN RSA PRIVATE KEY-----
 MIICXQIBAAKBgQChs9Fepy5FgeL0gNJ8GHcKRHsYnM2Kkw19zwydDQNyh2hrHWV2
 B11wpLFp8d0imcl2Wjb0oV/AxOhb3unQgNzs66LVuXJwS8icp3oIJZtExs6tkxzE
 s5mnU68wMeCYtJqHIZOmNblVWvpJMLNAwAVi3oLfnzDDbzjnDapm8M21nQIDAQAB
 AoGAZ11P1+acUHgvwMXcRtFIvvp5iYkqZouL00EYOghIjNx75gTbh7A7jbbpZeTi
 y6xsuMgAWy4QzGPSeG+tHMhS7+dYQNPuKSv5KtK3V7ubXz/I3ZN1etRVecA56QNw
 7HKv6b7srolt08kogGIwpbbfl/mhfJHnv4Jeqd5lNMnK4e0CQQDWFZo4h22OlSaH
 ZGd3i4rwLrA0Ux5bkdh7YH0uEeE/nGzpVs1DPhsN8UCyq9LAiKYLlXeeCvwurKwo
 OgKlUCkzAkEAwVy2KignoRInFTAaYH8PQRfD835q+oC0Iu21BF68ne06U6wu+wWk
 bWiYxTOOb+TGZfA1vA6OAvGVGoXs1bHF7wJBAItGiop0MKYuCl7Sxy1SrxUKir+/
 w2Q3QesiHs41+6Byl7hGLEuuv9MWPM0AU5/GRqAKoUNESkPjOi0BcG8z81kCQGGn
 OvCreugjzM0skAWv5bpQEExGyixdF5yURFlCpytzBYQAb3Gi9dmze4QMd6EW/wO4
 fsrM5vehnlXY0TVTJM0CQQCMPVhub8LSo7T/lCzypvb/cgxJfyITRKcM2asrXud5
 r27kbzsXqYum4huHqyFkb3pZammsYA/z89HchylfrD4U
 -----END RSA PRIVATE KEY-----"
在Java 6下,以下代码为:
KeyPairGenerator keyGen = null;
try {
  keyGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
  throw new RuntimeException(e);
}
KeyPair pair = keyGen.generateKeyPair();
privateKey = new Base64Encoder().encode(pair.getPrivate().getEncoded());
publicKey = new Base64Encoder().encode(pair.getPublic().getEncoded());`
输出以下内容:
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIsJlqFOP+jPyYvrGwh+dff30a3p
 uHysMfHYi1MyNSFCsT/2QbOc/k9U/X28WRCMeFwEEnReLULXA9Ywox8GycI/ApMX+DjKBrrLDbpr
 ATLiu9+NMK4VSytKFI87P07HAni3RkiO4rFNEINVQ7t38ZmHavuXHjMkLEAK4dyLQO9NAgMBAAEC
 gYBN/jv0EmwBUgYSKflJI39TcT263B+0N/fwXXOSYNiy5rF9WstyUP/LSrbEAJLJmLKvk00y391t
 4CVz0ma+sdUdAPlS7Nmx9f3BThGOGcDmpjVo1y4e1afWtyu66ba/XDeuf7q5Y/h/pr20/gXl9Gz2
 yefQrzU9xXGKZhE/lxJ2IQJBAMELpeAal+Fa+u0InGrowVmV+lge8RZqKRfCDzPPna465E5Qcekb
 J0ShsarP5lnUfrNH5g8GLaDGQwYE/UoIpPkCQQC4YRfck5uMlI1K3F9YC3XvmFAJnf9YexoPfNSu
 dznOD4rxlwzW/5daPOR0jjlyIRDH/QuUoPIIEn1mt3dnz7X1AkBZciozgl7pPhySA7FmH96mwcUz
 W3LdrebIaVRd707iUctDNibxmXFCbaFCwf27laf3LdM9FuHBYtvfSCSMTyERAkEAlNAQsUAVmKZB
 T72D2o0Nd/7oAosaD7DzvLJU+idSaWUUEJ+IhnKuFu/0t7oe1WWopLEwypoIHsnFmsTTQ99ajQJA
 Scwh3P3RTN4F6Jz1SxRSe6L729xI8xkbco5EsMq5v5BZeoGynqdPUUZdAPcaO2k5UagaSejvzgna
 8xIqR7elVQ=="

"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItT
 MjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCu
 FUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB"

问题

  1. 如何在Java代码中生成的私钥和公钥周围包含"armor"?

  2. 为什么通过Java代码生成的密钥每行都比OpenSSL输出的密钥长?

  3. 这有任何区别吗?其他小组正在使用的工具之一在使用上述Java代码生成的私钥签署消息时失败。然而,如果该工具使用由OpenSSL生成的私钥,则可以正常工作。

  4. 是否有办法导出与Java兼容的密钥?

1个回答

15

OpenSSL的私钥格式不标准,而Java代码创建的是标准的PKCS-#8编码的私钥。

OpenSSL可以将标准的密钥格式转换为非标准形式。您可以编写Java代码来完成相同的工作,但需要使用一些第三方库,并且熟悉ASN.1也有所帮助。

要将PKCS#8密钥转换为OpenSSL格式,请使用OpenSSL的pkcs8实用程序。

openssl pkcs8 -nocrypt -inform der < pvt.der > pvt.pem

要将存储为DER编码的SubjectPublicKeyInfo格式的RSA密钥转换为PEM格式,请使用OpenSSL的rsa实用程序。

openssl rsa -pubin -inform der < pub.der > pub.pem

假设私钥以“二进制”(DER)格式存储,而不是Base-64编码。创建和存储这样的密钥的Java代码将如下所示:

KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
KeyPair pair = gen.generateKeyPair();
FileOutputStream ospvt = new FileOutputStream("pvt.der");
try {
  ospvt.write(pair.getPrivate().getEncoded());
  ospvt.flush();
} finally {
  ospvt.close();
}
FileOutputStream ospub = new FileOutputStream("pub.der");
try {
  ospub.write(pair.getPublic().getEncoded());
  ospub.flush();
} finally {
  ospub.close();
}

谢谢回复。 :)其他团队正在使用的工具期望私钥的文档化形式为 PEM编码私钥或base64编码DER格式私钥。我一直在尝试第二个选项。
  • .getEncoded()返回ASN.1的DER格式(http://download.oracle.com/javase/6/docs/api/java/security/spec/PKCS8EncodedKeySpec.html)
  • 然后我进一步将其编码为base64。
但仍然不起作用。您能看到有什么问题吗?是否有一种方法可以直接创建PEM格式的私钥?限制是我必须仅使用Java代码创建其中一种格式...
- MiKu
@MiKu - PEM使用base-64编码。问题中的“mykey.pem”当然是PEM密钥。 "DER"用于指示二进制形式。但即使您区分了二进制和base-64,仍然需要知道密钥的预期结构:PKCS#8或本机OpenSSL。 DER或PEM只是最终的编码层。 “base64编码的DER”真的没有任何意义。那会与PEM有什么不同呢?你试过我的代码吗? - erickson
我同意你所说的Erikson。 我想做的是使用Java代码创建密钥,以便其他工具可以很好地解释它。 默认的PKCS#8结构与该工具不太兼容。 我用Bouncy Castle解决了问题。JDKKeyPairGenerator.RSA keyPairGen = new JDKKeyPairGenerator.RSA(); keyPairGen.initialize(RSA_KEY_STRENGTH); KeyPair keyPair = keyPairGen.generateKeyPair();StringWriter stringWriter = new StringWriter(); PEMWriter pemFormatWriter = new PEMWriter(stringWriter);pemFormatWriter.writeObject(keyPair.getPrivate()); pemFormatWriter.close(); - MiKu
1
另外,我不确定“base64编码的DER”是否等同于PEM。更可能的是,你说它们本质上是相同的是正确的。 需要验证(为了我的个人确认),通过使用openssl创建.dem文件并对其进行BASE64编码来检查它是否等同于密钥的.pem等效文件。根据你的建议,似乎应该是相等的。 :) 感谢你的帮助。ASN.1是一篇好文章。 :) - MiKu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接