繁体   English   中英

如何在 JAVA 中将 RSA 私钥从 DER 转换为 PEM?

[英]How to convert RSA private key from DER to PEM in JAVA?

我有一个 RSA private key.der 文件(里面有一堆二进制文件)。 如何将文件转换为 Java 中的 PEM 格式?

如果我在命令行中使用 openssl,我会这样做:

openssl rsa -inform der -in privateKey.der -outform pem -out privateKey.pem

privateKey.pem 结果如下所示:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAyljm4IGV2JmL8amyTQz9nCSdtdJV+OGiiyefJasKuNEIVAyV
BzSNEUrJYL1LrAMM0cbenWh3M0I+RoQYfwo3J88fi/aLW5dbdU8bi001UZIeJnEB
...
...
lykp1jNHSXD8PoBNVD+pbY3zGCqH1OgPWd0/+IbMBp3Qo+HMp5Ku9w==
-----END RSA PRIVATE KEY-----

我听说人们说 PEM 只是 DER 的 Base64 编码表示加上某些 header 和页脚。 但是,如果我只是做cat privateKey.der | base64 cat privateKey.der | base64

我从 openssl 给我的结果中得到了不同的结果: MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKWObggZXYmYvxqbJNDP2... ... GndCj4cynkq73

尽管有页眉和页脚,但 PEM 字符串也不相同。 有谁知道为什么?

Java 中是否有任何库可以将 DER 转换为 PEM,就像 openssl 一样? 一直在寻找,但不幸的是,我没有找到任何有效的方法。 任何帮助将不胜感激!

PEM 格式有很多种,OpenSSL 支持十几种 PEMDER 格式的私钥。 openssl rsa [-outform pem]编写的格式是算法特定的 PKCS1 附录 A 格式,有或没有基于 rfc1421 的加密,并标记为RSA PRIVATE KEY openssl pkeyopenssl pkcs8 -topk8编写的格式是算法通用的 PKCS8 格式,它定义了自己的加密,并相应地标记为PRIVATE KEYENCRYPTED PRIVATE KEY - 注意在任何一种情况下都没有 RSA; rfc7468 Java 加密,例如PrivateKey.getEncoded()使用未加密的 PKCS8,所以如果你从 Java 得到这个 DER 并将其转换为 Z95A1446A7120E4AF5C0C8878ABB7E6,你为什么会得到不同的结果。 另请注意,PEM 是 DER 的 base64,每 64 个字符换行一次,加上 header 和页脚; 没有换行符,它不会总是有效。 对于这两者,请参见PKCS#1 和 PKCS#8 format for RSA private key

如果您拥有或可以获得 Bouncy,那么您使用 BouncyCastle 的回答是一个很好的解决方案; bcpkix 正确处理大多数 OpenSSL 格式。 如果您想在没有 Bouncy 的情况下执行此操作,它几乎与How to encrypt RSA private key with PBE in PKCS#5 format in Java with IAIK JCE 相同? (我的)除了没有加密,所以省略中间块并稍微更改 PEM header:

    // given [RSA]PrivateKey privkey, get the PKCS1 part from the PKCS8 encoding
    byte[] pk8 = privkey.getEncoded();
    // this is wrong for RSA<=512 but those are totally insecure anyway
    if( pk8[0]!=0x30 || pk8[1]!=(byte)0x82 ) throw new Exception();
    if( 4 + (pk8[2]<<8 | (pk8[3]&0xFF)) != pk8.length ) throw new Exception();
    if( pk8[4]!=2 || pk8[5]!=1 || pk8[6]!= 0 ) throw new Exception();
    if( pk8[7] != 0x30 || pk8[8]==0 || pk8[8]>127 ) throw new Exception();
    // could also check contents of the AlgId but that's more work
    int i = 4 + 3 + 2 + pk8[8];
    if( i + 4 > pk8.length || pk8[i]!=4 || pk8[i+1]!=(byte)0x82 ) throw new Exception();
    byte[] old = Arrays.copyOfRange (pk8, i+4, pk8.length);
    
    // write to PEM format (substitute other file if desired)
    System.out.println ("-----BEGIN RSA PRIVATE KEY-----");
    String b64 = Base64.getEncoder().encodeToString(old);
    for( int off = 0; off < b64.length(); off += 64 )
        System.out.println (b64.substring(off, off+64<b64.length()?off+64:b64.length()));
    System.out.println ("-----END RSA PRIVATE KEY-----");

不过,在称其为“更好”之前,我会仔细考虑。 这也类似于Convert a X509 Public key to RSA public key for publickey (also mine) 和Read a PKCS#1 or SPKI public key in Java without libraries 的相反

经过大量挖掘......我找到了一种方法,但它看起来是多余的。 如果您有更好的主意,请告诉我。

    // My private key DER file.
    byte[] privateKeyDerBytes = Files.readAllBytes(Paths.get("tst/resource/FromSecretsManager.der"));
    
    // Convert the DER file to a Java PrivateKey
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKeyDerBytes);
    KeyFactory factory = KeyFactory.getInstance("RSA");
    PrivateKey pk = factory.generatePrivate(spec);

    // Use PemWriter to write the key to PEM format
    StringWriter sw = new StringWriter();
    try (PemWriter pw = new PemWriter(sw)) {
        PemObjectGenerator gen = new JcaMiscPEMGenerator(pk);
        pw.writeObject(gen);
    }
    String privateKeyPem = sw.toString();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM