2

In one of our applications private keys are stored using BouncyCastle's PEMWriter. At the moment I am investigating if we can get rid of the BouncyCastle dependency since Java 7 seems to have everything we need. The only issue is that I can not read the private keys stored in the database as PEM-encoded strings (the certificates/public keys are fine).

If I save the PEM-encoded string of the private key from the database to a file I can run OpenSSL to convert the key to PKCS#8 format like this:

openssl pkcs8 -topk8 -inform PEM -outform DER \
              -in private_key.pem -out private_key.der -nocrypt

The resulting output I can base64 encode and then read using this bit of Java/JCA code:

byte[] privateKeyBytes = 
           DatatypeConverter.parseBase64Binary(privateKeyDERcontents);
PrivateKey prKey = 
           KeyFactory.getInstance("RSA").
               generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

This private key matches the public key stored as expected, i.e. I can round-trip from plaintext to ciphertext and back.

The question I have is: can I directly read the original PEM encoding somehow?

EDIT

Here is a bit of code that reads the strings in question using BouncyCastle:

if (Security.getProvider("BC") == null) {
    Security.addProvider(new BouncyCastleProvider());
}
PEMReader pemReader = new PEMReader(new StringReader(privateKeyPEM));
KeyPair keyPair = (KeyPair) pemReader.readObject();
PrivateKey key = keyPair.getPrivate();

The "privateKeyPEM" is the PEM encoded string in the database, otherwise this example is self-contained. Interestingly it already uses the JCA KeyPair object as output. To rephrase my original question: can I do the equivalent of the code above without depending on PEMReader (and in turn quite a few other BouncyCastle classes)?

Peter Becker
  • 8,795
  • 7
  • 41
  • 64
  • Your first bit of code does not go with your openssl command. Your openssl command produces DER output, but your java code base64 decoded that. That won't work because it isn't base64 encoded to start with. – President James K. Polk Jan 11 '13 at 01:23
  • @GregS: you are right, I must have combined the wrong bits from my experiments. Let me check what works: I would have either used "-outform PEM" and stripped the header/footer (likely) or base64 encoded the DER output (less likely). I'll edit the post soon. – Peter Becker Jan 13 '13 at 23:47
  • @GregS: simply base64 encoding the DER works, so let's assume I did that. If wrapped at 64 characters it's the same as the PEM anyway. – Peter Becker Jan 13 '13 at 23:56

1 Answers1

-2

Key inside of PEM file is already stored in PKCS#8 format, so if it is not encrypted with password you can just remove headers (-----BEGIN RSA PRIVATE KEY-----), Base64-decode input, and get the needed bytes.

Nickolay Olshevsky
  • 13,706
  • 1
  • 34
  • 48
  • 2
    I'm pretty sure that is not correct. A PEM file may contain a PKCS#8 encoded key, but it can contain other binary data. An example is X.509 certificates (commonly used for public keys) and whatever the default for OpenSSL is (some kind of proprietary format). You can convert openssl to get from one to another while maintaining PEM as the outer encoding -- use the command I gave with both -inform and -outform set to PEM. – Peter Becker Jan 09 '13 at 23:43
  • 2
    Sure, PEM is just the text encoding for binary data. I'm speaking about this particular situation. Here you have Base64-encoded PKCS#8 private key. – Nickolay Olshevsky Jan 10 '13 at 08:01
  • 1
    The openssl command to convert to PKCS#8 is necessary. See e.g. http://www.openssl.org/docs/apps/pkcs8.html -- the keys I have seem to be in the format called "traditional" in that document. – Peter Becker Jan 11 '13 at 00:23
  • 1
    @PeterBecker: You seem to be missing the point. You don't want to use Bouncycastle. You been told how you don't have to. Now you are wandering away on to other topics. – President James K. Polk Jan 11 '13 at 01:25
  • 2
    @GregS: how am I missing the point? I don't want to use BC, but I still have not been able to read the private keys in the database using just the JDK. Nickolay claims the keys should be PKCS#8, but they are not. They are in a format that makes the OpenSSL conversion necessary until I find out how else to do it. – Peter Becker Jan 13 '13 at 23:45
  • Did you try the method I suggested? – Nickolay Olshevsky Jan 14 '13 at 08:50
  • I found this answer to another question to be relevant, and good source of sample code to this end: http://stackoverflow.com/a/27621696/1720448 – Paul Cunningham Jun 19 '15 at 21:00