【问题标题】:How to generate RSA Private key from *pem string in Java如何从 Java 中的 *pem 字符串生成 RSA 私钥
【发布时间】:2013-08-24 12:39:51
【问题描述】:

我想从 Java 中的字符串(.pem 文件)生成私钥。

private static final String test = "-----BEGIN RSA PRIVATE KEY-----\n" +
         "MIIEpAIBAAKCAQEAvcCH8WsT1xyrZqq684VPJzOF3hN5DNbowZ96Ie//PN0BtRW2\n" +
// and so on
         "-----END RSA PRIVATE KEY-----";

try {
    String privKeyPEM = test.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
    privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");

    byte [] encoded = Base64.decode(privKeyPEM);

    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PrivateKey privKey = kf.generatePrivate(keySpec);
}
catch (Exception e) {
    e.printStackTrace();
}

最后一行(generatePrivate 函数)抛出这个异常:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
    at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(Unknown Source)
    at java.security.KeyFactory.generatePrivate(Unknown Source)
    at Test.main(Test.java:52)
Caused by: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
    at sun.security.pkcs.PKCS8Key.decode(Unknown Source)
    at sun.security.pkcs.PKCS8Key.decode(Unknown Source)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(Unknown Source)
    at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(Unknown Source)
    at sun.security.rsa.RSAKeyFactory.generatePrivate(Unknown Source)
    ... 3 more

如果我将私钥更改为 .der 文件中的值,它可以正常工作,但我需要从 .pem 文件中生成私钥文件。

我附上了打印为字符串的字节截图(一次用 \n 硬编码,一次用 \n 硬编码)和一次来自文件。

Bigger Image

奇怪的是文件的输出与字符串的输出不同。

如果我尝试使用 Base64 对 .der 文件进行编码,则结果与 .pem 文件中的字符串不同。为什么会这样?

【问题讨论】:

  • 你找到答案了吗?
  • @SankarP 不是真的。
  • 好的。我找到了解决方案。以“-----BEGIN RSA PRIVATE KEY”开头的密钥是 pkcs1 编码文件。 Java 不支持这种 pkcs1 编码,除非您使用像 BouncyCastle 这样的外部库。我昨天遇到了同样的问题,大约 8 小时后,找到了解决方案。如果您使用 pkcs8 对私钥进行编码,它将以 "--- BEGIN PRIVATE KEY---" 开头,这将由 stock java.util 处理。 HTH。

标签: java rsa private-key pem der


【解决方案1】:

你说最后一行是抛出异常,即

PrivateKey privKey = kf.generatePrivate(keySpec);

以上行适用于设置正确的密钥规范,即

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);

所以实际问题在于编码字节数组。你在byte [] encoded = Base64.decode(privKeyPEM);之后做了System.out,看看输出是什么。

我知道如果邮件是 MIME 格式,那么在某些字符之后会附加回车符和换行符的组合,因此对于电子邮件系统或您使用它的任何地方来说,字符串不会太长。

最终的字符串测试在您使用的原始文本中有一些'\n'。您确实删除了下面一行中的其他文本,

String privKeyPEM = test.replace("-----BEGIN RSA PRIVATE KEY-----\n", "");
    privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");

但是,看看字符串,

"MIIEpAIBAAKCAQEAvcCH8WsT1xyrZqq684VPJzOF3hN5DNbowZ96Ie//PN0BtRW2\n" +
// and so on
         "-----END RSA PRIVATE KEY-----";

它可能还剩下一些'\n',这可能会在您生成密钥规范时导致一些不需要的字符。尝试更多 System.out 并查看编码的字节数组是什么样的,并且在此之前检查 String privKeyPEM 并查看其中是否没有剩余的字符。

希望有帮助。

【讨论】:

  • 我上传了encoded的输出。 pastebin.com/YUsNdhgW。我还将测试更改为没有\n 的纯字符串,它也不起作用。
  • 我还上传了一个截图,输出为字符串。
  • Base64 解码会忽略换行符,通常会忽略所有空格。
猜你喜欢
  • 2017-02-07
  • 1970-01-01
  • 2019-08-15
  • 2010-09-19
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
  • 2016-02-29
相关资源
最近更新 更多