how to generate public and private key in PEM format

11.5k views Asked by At

I need to generating a RSA and DSA key pair (public and private key) in PEM format using java. I want the public and private key files to be opened with this format:

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAryQICCl6NZ5gDKrnSztO 3Hy8PEUcuyvg/ikC+VcIo2SFFSf18a3IMYldIugqqqZCs4/4uVW3sbdLs/6PfgdX 7O9D22ZiFWHPYA2k2N744MNiCD1UE+tJyllUhSblK48bn+v1oZHCM0nYQ2NqUkvS j+hwUU3RiWl7x3D2s9wSdNt7XUtW05a/FXehsPSiJfKvHJJnGOX0BgTvkLnkAOTd OrUZ/wK69Dzu4IvrN4vs9Nes8vbwPa/ddZEzGR0cQMt0JBkhk9kU/qwqUseP1QRJ 5I1jR4g8aYPL/ke9K35PxZWuDp3U0UPAZ3PjFAh+5T+fc7gzCs9dPzSHloruU+gl FQIDAQAB -----END PUBLIC KEY-----

My public key is already generated before with this format that i do not want it:

0Ÿ0 *†H†÷ 0Ÿ0 *†H†÷

ok, this is my code of key generation:

private static void createKey()
        throws Exception {

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("Password to encrypt the private key: ");
            String password = in.readLine();
            System.out.println("Generating an RSA keypair...");

            // Create an RSA key
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(1024);
            KeyPair keyPair = keyPairGenerator.genKeyPair();

            System.out.println("Done generating the keypair.\n");

            // Now we need to write the public key out to a file
            System.out.print("Public key filename: ");
            String publicKeyFilename = "C:/Users/Joe/Desktop/" + in.readLine();

            // Get the encoded form of the public key so we can
            // use it again in the future. This is X.509 by default.
            byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

            // Write the encoded public key out to the filesystem
            FileOutputStream fos = new FileOutputStream(publicKeyFilename);
            fos.write(publicKeyBytes);
            fos.close();

            // Now we need to do the same thing with the private key,
            // but we need to password encrypt it as well.
            System.out.print("Private key filename: ");
            String privateKeyFilename = "C:/Users/Joe/Desktop/" + in.readLine();

            // Get the encoded form. This is PKCS#8 by default.
            byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();

            // Here we actually encrypt the private key
            byte[] encryptedPrivateKeyBytes =
            passwordEncrypt(password.toCharArray(),privateKeyBytes);

            fos = new FileOutputStream(privateKeyFilename);
            fos.write(encryptedPrivateKeyBytes);
            fos.close();
        }

thank you for your help..

3

There are 3 answers

0
Katherine Rose On

I've written a library that includes methods which can do this. It's called Reasonably Easy Cryptography and you can use the PEMHandler methods for this. Here's how you could do it, assuming you've imported PEMHandler from my library, and that key's class is an implementation of java.security.Key such as a PrivateKey:

String pem = PEMHandler.keyToPem(key);

This works with any kind of Key, it'll figure out whether it's a public or private key and what algorithm it uses on its own (it isn't perfect and I'm still working on finding the best way to do that, but it does work fine with PrivateKey and PublicKey). There's also a method to do this for both keys in a KeyPair in one call, and methods to convert the PEM string back to a Key.

1
BitLord On

Maybe a bit late but there is my solution. Hope it helps others.

byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

Here you're taking bytes of key and writing directly to file. So you get the appropriate result - DER-encoded file. However PEM is Base64 encoded format with line breaks each 64 symbols and header/footer.

There is code implementing this logic:

String publicKeyContent = Base64.getEncoder().encodeToString(publicKeyBytes);
String publicKeyFormatted = "-----BEGIN PUBLIC KEY-----" + System.lineSeparator();
for (final String row: 
        Splitter
            .fixedLength(64)
            .split(publicKeyContent)
    ) 
{
    publicKeyFormatted += row + System.lineSeparator();
}
publicKeyFormatted += "-----END PUBLIC KEY-----";

So publicKeyFormatted will contain PEM-encoded string of public key.

P.S. Splitter is a class provided in Guava lib, but you can split the string with a simple cycle or somehow.

0
Syd Gillani On

Instead of manually generating the PEM String, you can use the bouncy castle to do it for you: since it's a tested library you can be sure about the output. The following code is in Kotlin but can easily be used with Java syntax:

        val gen = KeyPairGenerator.getInstance("RSA")
        gen.initialize(2048)
        val pair = gen.generateKeyPair()
        val privateKey: PrivateKey = pair.private
       
  
        val pemObject = PemObject("RSA PRIVATE KEY", privateKey.encoded)
        
        val byteStream = ByteArrayOutputStream()
        val pemWriter = PemWriter(OutputStreamWriter(byteStream))
        pemWriter.writeObject(pemObject)
        pemWriter.close();
        println(String(byteStream.toByteArray()))