Search code examples
javarsabouncycastleprivate-key

Get a PrivateKey from a RSA .pem file


Given this .pem file (generated with openssl and encrypted with a password):

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,AC009672952033EB

2wegzxf3MtncXS1CY3c.....
....
....
-----END RSA PRIVATE KEY-----

How do I get a PrivateKey object in Java? I wrote the following code but I cannot find the right way to get a KeySpec:

PrivateKey readFromPem(File keyFile, String password){
    PemReader r = new PemReader(new InputStreamReader(new FileInputStream(keyFile)));
    PemObject pemObject = r.readPemObject();
    byte[] encodedKey = pemObject.getContent();

    KeySpec keySpec = ???? // how to get this?

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey key = keyFactory.generatePrivate(keySpec);
    return key;
}

I guess I should build a RSAPrivateKeySpec, but I don't know how. I tried the method from this answer and this other answer, but they both result in errors when parsing the byte array.


Solution

  • I'm using BouncyCastle 1.57 (bcprov-jdk15on, bcmail-jdk15on and bcpkix-jdk15on) and Java 7.

    You can read the private key using the JcaPEMKeyConverter class. The code below works for keys with and without a password:

    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.openssl.PEMDecryptorProvider;
    import org.bouncycastle.openssl.PEMEncryptedKeyPair;
    import org.bouncycastle.openssl.PEMKeyPair;
    import org.bouncycastle.openssl.PEMParser;
    import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
    import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
    
    // don't forget to add the provider
    Security.addProvider(new BouncyCastleProvider());
    String password = "your password";
    
    // reads your key file
    PEMParser pemParser = new PEMParser(new FileReader(keyFile));
    Object object = pemParser.readObject();
    JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
    
    KeyPair kp;
    if (object instanceof PEMEncryptedKeyPair) {
        // Encrypted key - we will use provided password
        PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) object;
        // uses the password to decrypt the key
        PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
        kp = converter.getKeyPair(ckp.decryptKeyPair(decProv));
    } else {
        // Unencrypted key - no password needed
        PEMKeyPair ukp = (PEMKeyPair) object;
        kp = converter.getKeyPair(ukp);
    }
    
    // RSA
    KeyFactory keyFac = KeyFactory.getInstance("RSA");
    RSAPrivateCrtKeySpec privateKey = keyFac.getKeySpec(kp.getPrivate(), RSAPrivateCrtKeySpec.class);
    
    System.out.println(privateKey.getClass());
    

    The privateKey's class will be java.security.spec.RSAPrivateCrtKeySpec (which extends RSAPrivateKeySpec).