在Java中加载RSA私钥(algid解析错误,不是序列)

在Java中加载RSA私钥(algid解析错误,不是序列),java,encryption,openssl,rsa,Java,Encryption,Openssl,Rsa,我正在尝试将使用ssl生成的RSA私钥加载到java中,我的代码是: 生成密钥: openssl genrsa -out mykey.pem 1024 结果: -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCUibP4fY2PA/sGMKMbU6usuIGcOAqgQjD6c2ylVo05Oz7pgjnE +O0l2MFRUYUGT5KKk/W+0cAXkxaQHE3n8A8X1mHT8eMDmWnzz0PeYjDE8LQmAw8R Y2FnVKF

我正在尝试将使用ssl生成的RSA私钥加载到java中,我的代码是:

生成密钥

openssl genrsa -out mykey.pem 1024
结果:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCUibP4fY2PA/sGMKMbU6usuIGcOAqgQjD6c2ylVo05Oz7pgjnE
+O0l2MFRUYUGT5KKk/W+0cAXkxaQHE3n8A8X1mHT8eMDmWnzz0PeYjDE8LQmAw8R
Y2FnVKFAB36BIjdb5FsZmCk5QYKU5+nWLMqH/j/IR5AyX5wR2SMoslUg2QIDAQAB
AoGAeJ1s7638IhLIZtldyRXjRKi6ToFPV50IKodJxOSIXt3WE0V05ZaA84eUSxUY
IOzCgRbuqVmnUz1USAdD18AecC8qc7tXTRALLy7q8fxklPwmGPUOvTFmI7gRMUnv
cWrq1gySk3SKpj0YmWnuY9Xmd2+xoWLzUeFD1CROY5OTjIECQQDDlp1+Al7+duR0
XyMlkWLIk0nIbkQ5zlTAEipzmaeTSOJi6YG3EMMz3AGuZb7tw6HFxWqeg1hyKJ+T
cTM3WTdJAkEAwmrCDKE29n3wFOBKsZZFQbDgVOUXCBs2ubEI+ALe1DJU5BlfnrhJ
OINRCNgnwSFNbwxDTkDpR6J6Av2ElAvNEQJAV0dVvk5Wj50Ecz2lFHWdLD41taAn
B9igDxnMIcvWcK4cf+ENhmCPiwvJIEa8/aLIBNYErvmTtVWVaBkirrc8KQJABr+z
+sJB6S6X/fGHRkDkKJKeRvQo54QiUzHdENbwq0cQAVcMJbNZ/1c3oen2/1JLoNY5
I+dG8dCnEaGBT65VMQJBAIDqH1Kqs5tb51cpt6h9ot31SUVud5pSML/babwp3pRs
1s6poreym4PkAyRug0Dgcj1zVLt25TlOHvrL9r3Swq8=
-----END RSA PRIVATE KEY-----
String privKeyPEM=readFile("mykey.pem");
privKeyPEM= privKeyPEM.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("\n", "");
// Remove the first and last lines
privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");
System.out.println(privKeyPEM);

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

// PKCS8 decode the encoded RSA private key
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(keySpec);

// Display the results
System.out.println(privKey);
加载:

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCUibP4fY2PA/sGMKMbU6usuIGcOAqgQjD6c2ylVo05Oz7pgjnE
+O0l2MFRUYUGT5KKk/W+0cAXkxaQHE3n8A8X1mHT8eMDmWnzz0PeYjDE8LQmAw8R
Y2FnVKFAB36BIjdb5FsZmCk5QYKU5+nWLMqH/j/IR5AyX5wR2SMoslUg2QIDAQAB
AoGAeJ1s7638IhLIZtldyRXjRKi6ToFPV50IKodJxOSIXt3WE0V05ZaA84eUSxUY
IOzCgRbuqVmnUz1USAdD18AecC8qc7tXTRALLy7q8fxklPwmGPUOvTFmI7gRMUnv
cWrq1gySk3SKpj0YmWnuY9Xmd2+xoWLzUeFD1CROY5OTjIECQQDDlp1+Al7+duR0
XyMlkWLIk0nIbkQ5zlTAEipzmaeTSOJi6YG3EMMz3AGuZb7tw6HFxWqeg1hyKJ+T
cTM3WTdJAkEAwmrCDKE29n3wFOBKsZZFQbDgVOUXCBs2ubEI+ALe1DJU5BlfnrhJ
OINRCNgnwSFNbwxDTkDpR6J6Av2ElAvNEQJAV0dVvk5Wj50Ecz2lFHWdLD41taAn
B9igDxnMIcvWcK4cf+ENhmCPiwvJIEa8/aLIBNYErvmTtVWVaBkirrc8KQJABr+z
+sJB6S6X/fGHRkDkKJKeRvQo54QiUzHdENbwq0cQAVcMJbNZ/1c3oen2/1JLoNY5
I+dG8dCnEaGBT65VMQJBAIDqH1Kqs5tb51cpt6h9ot31SUVud5pSML/babwp3pRs
1s6poreym4PkAyRug0Dgcj1zVLt25TlOHvrL9r3Swq8=
-----END RSA PRIVATE KEY-----
String privKeyPEM=readFile("mykey.pem");
privKeyPEM= privKeyPEM.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("\n", "");
// Remove the first and last lines
privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", "");
System.out.println(privKeyPEM);

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

// PKCS8 decode the encoded RSA private key
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privKey = kf.generatePrivate(keySpec);

// Display the results
System.out.println(privKey);
它抛出一个
IOException:algid解析错误,而不是一个序列。错误在哪里

Exception in thread "main" 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 base54.encrypt.RSAToy.main(RSAToy.java:36)
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)
线程“main”java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:IOException:algid解析错误,不是序列 位于sun.security.rsa.RSAKeyFactory.EngineeGeneratePrivate(未知源) 位于java.security.KeyFactory.generatePrivate(未知源) 位于base54.encrypt.RSAToy.main(RSAToy.java:36) 原因:java.security.InvalidKeyException:IOException:algid解析错误,不是序列 位于sun.security.pkcs.PKCS8Key.decode(未知源) 位于sun.security.pkcs.PKCS8Key.decode(未知源) 位于sun.security.rsa.RSAPrivateCrtKeyImpl。(未知来源) 位于sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(未知源) 位于sun.security.rsa.RSAKeyFactory.generatePrivate(未知源)
如果需要,您仍然可以加载密钥

public static PublicKey bigIntegerToPublicKey(BigInteger e, BigInteger m)  {
    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PublicKey pubKey = fact.generatePublic(keySpec);
    return pubKey;
}

public static PrivateKey bigIntegerToPrivateKey(BigInteger e, BigInteger m) {
    RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
    KeyFactory fact = KeyFactory.getInstance("RSA");
    PrivateKey privKey = fact.generatePrivate(keySpec);
    return privKey;
}

您所需要的只是模数和指数。

之所以会出现此错误,是因为您正在读取PKCS#8密钥文件,但您的文件具有PKCS#1格式(PKCS#1具有
开始RSA私钥
头,而PKCS#8具有
开始私钥
头)

为了读取PKCS#1和PKCS#8 PEM文件,我使用Apache JMeter的源代码:


PrivateKey pk=(新的PrivateKeyReader(“/path/to/myfile.der”)).getPrivateKey()

继Julien Kronegg的回答之后,如果由于文件的PKCS#1格式而出现此错误,则可以使用以下步骤将其转换为PKCS#8文件

首先,将PKCS#1密钥文件保存到名为
priv1.pem的文件中

-----BEGIN RSA PRIVATE KEY-----
[...]
-----END RSA PRIVATE KEY-----
然后,执行以下命令:

openssl pkcs8 -topk8 -inform PEM -outform PEM -in priv1.pem -out priv8.pem -nocrypt
这将生成一个名为
priv8.pem
的文件,它是PKCS#8格式的关键文件:

我从Java中使用它,如下所示:

String PRIVATE_RSA_KEY_PKCS8 = 
    "-----BEGIN PRIVATE KEY-----\n" +
    "MDSTofml23d....\n" +
    [...] +
    "-----END PRIVATE KEY-----\n";
String key = PRIVATE_RSA_KEY_PKCS8
    .replace("-----BEGIN PRIVATE KEY-----\n", "")
    .replace("\n-----END PRIVATE KEY-----\n", "");
PKCS8EncodedKeySpec keySpec =
    new PKCS8EncodedKeySpec(DatatypeConverter.parseBase64Binary(key));
try {
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
    Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] bytes = parseBase64Binary(encryptedNodeIdentifier);
    byte[] decryptedData = cipher.doFinal(bytes);
    return new String(decryptedData);
} catch (GeneralSecurityException e) {
    return "";
}

或者,您可以将mykey.pem转换为DER格式并使用现有代码。下面是执行此操作的openssl命令

 
openssl pkcs8 -topk8 -inform PEM -outform DER -in mykey.pem -out mykey.der -nocrypt
新的格式化文件看起来像

 

3082 0276 0201 0030 0d06 092a 8648 86f7
0d01 0101 0500 0482 0260 3082 025c 0201
0002 8181 00a9 0689 7676 2a63 5779 e4e8
4bb5 8e53 bc44 a975 8254 cb64 5cf2 1499
ad1c 6c35 6027 e357 ac09 0421 2b4b ddb4
1be3 a688 a848 5618 bce8 25d0 2cf2 972b
3801 a023 d6ee d824 4cfb 078f dad8 4317
fc9d 9468 27cc 2f08 f755 3293 76cb 3c60
4302 1c59 a8e8 5ac9 0576 8bb0 6bbb 8f1a
092d 7884 a405 c775 a8ca 7a2c 8037 435c
557a c9f0 a702 0301 0001 0281 8100 8462
6c53 ee25 30fd 98a9 230f f939 6a78 30c7
1114 6d59 8858 0bfa fa8a 4d92 ab13 8eea
4f06 9d61 30a1 7aa0 40aa ff58 b5fc 27fb
d710 4e3b 1f9b b4bd 95ca 1deb d165 063a
da5c 383d e428 cbf6 1f62 4549 5b96 ee2d
b811 4cff c849 9637 67e4 a5d5 1c75 f13b
8ddd b212 ba2f 7118 885e bc98 cab6 5434
d1e8 2a33 c408 1186 be05 6074 7431 0241
00d8 a1e2 d382 d52a 372e 0a62 807f 8283
e615 c7a7 180b e21c b6ce cd55 940f 542b
903f 86a0 e488 74b2 d69d d5d1 27d9 4079
72a2 80f8 c105 3e19 309b dd78 4dbe 440d
0d02 4100 c7bd e5fd ccee 60b2 cbc0 7520
53c1 6442 9f11 e0d0 969f 6315 41cd 7b3c
c279 cebe 4025 a4f4 97c9 6d1b c48f 6f01
cd3b e849 33e6 5f13 7fb6 2780 22d1 f2da


下面是仅使用Java运行时修改的org.apache.jmeter.protocol.oauth.sampler.PrivateKeyReader代码。它适用于我,它可以加载PKCS#1或PKCS#8私钥文件并返回PrivateKey类。(如果我在复制/粘贴时弄错了什么,请告诉我)

像这样使用它: PrivateKey pk=(新的PrivateKeyReader(“/path/to/myfile.der”)).getPrivateKey()

*
    *
  • 类:通用、应用、上下文或私有 *
  • CF:Constructed标志。如果为1,则构造该字段。 *
  • 类型:这实际上在ASN.1中称为标记。信息技术 *指示数据类型(整数、字符串)或构造 *(顺序、选择、集合)。 *
* *@param标记或标识符 *@param-length字段的长度 *@param value编码字段的八位字节字符串。 */ 公共ASN1对象(int标记,int长度,字节[]值){ this.tag=tag; this.type=tag&0x1F; 这个长度=长度; 这个值=值; } 公共int getType(){ 返回类型; } 公共整数getLength(){ 返回长度; } 公共字节[]getValue(){ 返回值; } 公共布尔值是构造的(){ return(tag&DerParser.CONSTRUCTED)=DerParser.CONSTRUCTED; } /** *对于构造的字段,返回其内容的解析器。 * *@返回构造的解析器。 *@抛出异常 */ 公共DerParser getParser()引发IOException{ 如果(!isConstructed()) 抛出新IOException(“无效的DER:无法分析基元实体”);//$NON-NLS-1$ 返回新的DerParser(值); } /** *获取整数形式的值 * *@return biginger *@抛出异常 */ public BigInteger getInteger()引发IOException{ if(type!=DerParser.INTEGER) 抛出新IOException(“无效的DER:对象不是整数”);//$NON-NLS-1$ 返回新的BigInteger(值); } /** *以字符串形式获取值。大多数字符串都经过处理 *作为拉丁语-1。 * *@returnjava字符串 *@抛出异常 */ 公共字符串getString()引发IOException{ 字符串编码; 开关(类型){ //不是所有的都是拉丁语-1,但它是最接近的东西 case DerParser.NUMERIC_字符串: case DerParser.PRINTABLE_字符串: case DerParser.VIDEOTEX_字符串: case DerParser.IA5_字符串: case DerParser.GRAPHIC_字符串: case DerParser.ISO646_字符串: case DerParser.GENERAL_字符串: encoding=“ISO-8859-1”//$NON-NLS-1$ 打破 case DerParser.BMP_字符串: encoding=“UTF-16BE”//$NON-NLS-1$ 打破 case DerParser.UTF8_字符串: encoding=“UTF-8”//$NON-NLS-1$ 打破 case DerParser.UNIVERSAL_字符串: 抛出新IOException(“无效的DER:无法处理UCS-4字符串”);//$NON-NLS-1$ 违约: 抛出新IOException(“无效的DER:对象不是字符串”);//$NON-NLS-1$ } 返回新字符串(值、编码); } } 试试这个:


也许您可以以十六进制显示base64解码的前10个字节的输出?openssl pkcs8-topk8。。。他是你的朋友。openssl rsa生成的是裸露的rsa密钥,而不是PKCS8密钥。你能给出一个答案吗,nullix?我刚刚证实,这是一个“裸”PKCS×1格式化的私钥(仅是模数、公有和私有指数和CRT参数),请考虑在这里更改可接受的答案。谢谢。你从哪里定义e和m参数?它们是相应rsa密钥的指数和模。在PrivateKey类中,可以使用getPrivateExponent()和GetModule(),在PublicKey中也可以使用。您可以使用“KeyPairGenerator kpg=KeyPairGenerator.getInstance(“RSA”);kpg.initialize(2048);KeyPair kp=kpg.genKeyPair()?即
java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());