How to generate RSA Private key from *pem string in Java

Niklas picture Niklas · Aug 22, 2013 · Viewed 11.9k times · Source

I want to generate the private key from a string(a .pem file) in Java.

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();
}

The last line(generatePrivate function) is throwing this exception:

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

If I change the private key to the value from a .der file it works properly, but I need to generate the private key file from a .pem file.

I attached a screenshot of the bytes printed as string(once hard-coded with \n and once hard-coded without \n) and once from the file.

Bigger Image

Output

The weird thing is that the output from the file is different to the output from the strings.

If I try to encode a .der file with Base64, the result is different than the string in the .pem file. Why is that so?

Answer

H-Patel picture H-Patel · Aug 22, 2013

You say that the last line is throwing exception, i.e.

PrivateKey privKey = kf.generatePrivate(keySpec);

Above line works on keyspecs being set correct, i.e.

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);

So actual problem is with encoded bytes array. Have you done System.out after byte [] encoded = Base64.decode(privKeyPEM); and see what the output is.

I understand that if the message is in MIME format, then after certain characters it appends a combination of carriage return and newline so the strings are not too long for e-mail system or wherever you are using it.

The final String test has some '\n' in the original text which you use. You did get rid of other text in below line,

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

But, look at the string,

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

it may have some more '\n' left which may result in some unwanted characters when you generate keyspec. Try more System.out and see what the encoded byte array is like and also before that check String privKeyPEM and see if any extra character is not left in it.

Hope this hepls.