0

I have a private key file in the .der format. I'm trying to save this private key as a PrivateKey object (with Java) like this:

PrivateKey clientPrivKey = getPrivateKeyFromKeyFile("C:\\Users\\Bob\\Desktop\\Assignments\\Project\\VPN Project\\src\\client-private.der");

This is what the getPrivateKeyFromKeyFile method looks like:

private static PrivateKey getPrivateKeyFromKeyFile(String keyfile) throws Exception
    {
        Path path = Paths.get(keyfile);
        byte[] privKeyByteArray = Files.readAllBytes(path);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec); 
        return myPrivKey;
    }

But when I try this, I keep getting InvalidKeySpecException because of this line of code:

PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec);

I'm not sure what's the issue here. I opened up the private key file and everything looks fine. It starts with -----BEGIN RSA PRIVATE KEY----- and ends with -----END RSA PRIVATE KEY-----.

And in case it's relevant, I created this private key using this OpenSSL command:

genrsa -out client-private.der 2048
Bob K
  • 69
  • 1
  • 9

1 Answers1

2

A file generated with

openssl genrsa -out <path to output-file> 2048

is actually not a .der-file, but a .pem-file (see e.g. What are the differences between .pem, .cer and .der?) and the data are not stored in the PKCS8-format, but in the PKCS1-format (see e.g. PKCS#1 and PKCS#8 format for RSA private key). Keys in the PKCS1-format can not be processed directly using standard Java tools. For this, third-party libraries like BouncyCastle are necessary (see e.g. Read RSA private key of format PKCS1 in JAVA).

Another possibility is to convert the PKCS1-formatted key into a PKCS8-formatted key with OpenSSL first (see e.g. Load a RSA private key in Java (algid parse error, not a sequence)):

openssl pkcs8 -topk8 -inform PEM -outform PEM -in <path to the input-pkcs1-pem-file> -out <path to the output-pkcs8-pem-file> -nocrypt

And then, after (programmatic) deletion of the Beginn-/End-line and after base64-decoding the private key can be generated (see e.g. How to read .pem file to get private and public key) e.g. with

private static PrivateKey getPrivateKeyFromKeyFile(String keyfile) throws Exception
{
    Path path = Paths.get(keyfile);
    byte[] privKeyByteArray = Files.readAllBytes(path);
    // added ----------------------------------------------------------------
    String privKeyString = new String(privKeyByteArray);
    privKeyString = privKeyString.replace("-----BEGIN PRIVATE KEY-----", "");
    privKeyString = privKeyString.replace("-----END PRIVATE KEY-----", "");
    privKeyString = privKeyString.replace("\r\n", "");
    privKeyByteArray = Base64.getDecoder().decode(privKeyString);
    // ----------------------------------------------------------------------
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PrivateKey myPrivKey = keyFactory.generatePrivate(keySpec); 
    return myPrivKey;
}
Topaco
  • 40,594
  • 4
  • 35
  • 62