Private Key PFX to/from JKS Conversion Using OpenSSL and Jetty

Recently I’ve been watching quite a few screencasts which seem to be a really fun way to learn something. This made me want to create something of my own. So for this blog post I’m putting up my first attempts at creating screencasts while trying to explain something useful.

When dealing with PKI based application security, one usually encounters different systems on different platforms and making sure they can interact with each other can be quite a hassle. Testing these systems usually means you create you own self-signed private/public key pairs. And of course there are times when for testing purposes you need to convert your private key to another format because you generated it on a different platform or received it from someone else who didn’t ask you about your preferred private key storage format. There are quite a few storage formats devised by the public-key cryptography standards group. Most of the time I have to deal with keys in Java’s JKS format and PFX format used on Microsoft platforms so from time to time I have a need of converting one format into another. See the screencasts bellow of how I’m converting them both ways.

Convert private key in PFX format to JKS keystore

This text will be replaced

Note: after this conversion the alias in the Java keystore for the converted key is ‘1’. Since I’m using such conversions only for test purposes I haven’t looked into changing the alias to something more meaningful. But if you know a quick way of doing this without reimporting the key, please, post your method in the comments ;)

Convert private key in JKS keystore to PFX format

This text will be replaced

Here’s the source of the Java file I used in the screencast for private key an certificate extraction from JKS keystore. Note that I’m assuming here the usage of JDK 6 because System.console().readPassword() is used to read the password without echoing.

import java.io.*;
import java.security.*;
import java.security.cert.Certificate;

public class ExportKeyAndCert {

    private static class Base64 {
        static final byte[] encodeData;
        static final String charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        static {
            encodeData = new byte[64];
            for (int i = 0; i < 64; i++) {
                byte c = (byte) charSet.charAt(i);
                encodeData[i] = c;
            }
        }

        private Base64() {}

        public static String encode(byte[] src) {
            int length = src.length;
            byte[] dst = new byte[(length + 2) / 3 * 4 + length / 57];
            int x = 0, len = 0, old = 0, state = 0, dstIndex = 0;

            for (int srcIndex = 0; srcIndex < length; srcIndex++) {
                x = src[srcIndex];
                switch (++state) {
                    case 1:
                        dst[dstIndex++] = encodeData[(x >> 2) & 0x3f];
                        break;
                    case 2:
                        dst[dstIndex++] = encodeData[((old << 4) & 0x30) | ((x >> 4) & 0xf)];
                        break;
                    case 3:
                        dst[dstIndex++] = encodeData[((old << 2) & 0x3C) | ((x >> 6) & 0x3)];
                        dst[dstIndex++] = encodeData[x & 0x3F];
                        state = 0;
                        break;
                }
                old = x;
                if (++len >= 57) {
                    dst[dstIndex++] = (byte) '\n';
                    len = 0;
                }
            }
            switch (state) {
                case 1:
                    dst[dstIndex++] = encodeData[(old << 4) & 0x30];
                    dst[dstIndex++] = (byte) '=';
                    dst[dstIndex++] = (byte) '=';
                    break;
                case 2:
                    dst[dstIndex++] = encodeData[(old << 2) & 0x3c];
                    dst[dstIndex++] = (byte) '=';
                    break;
            }
            return new String(dst);
        }
    }

    static public void main(String[] args) {
        if (args.length < 2) {
            System.out.println("Usage: java ExportKeyAndCert keyStore keyAlias");
            System.exit(0);
        }
        try {
            String keyStore = args[0];
            char[] storePass = System.console().readPassword("Enter keystore password: ");
            String keyAlias = args[1];
            char[] keyPass = System.console().readPassword("Enter key password: ");

            KeyStore ks = KeyStore.getInstance("jks");
            ks.load(new FileInputStream(keyStore), storePass);

            Certificate cert = ks.getCertificate(keyAlias);
            String b64 = Base64.encode(cert.getEncoded());

            PrintWriter fout = new PrintWriter("public.cer");
            fout.println("-----BEGIN CERTIFICATE-----");
            fout.println(b64);
            fout.println("-----END CERTIFICATE-----");
            fout.close();

            Key key = ks.getKey(keyAlias, keyPass);
            b64 = Base64.encode(key.getEncoded());

            fout = new PrintWriter("private.key");
            fout.println("-----BEGIN PRIVATE KEY-----");
            fout.println(b64);
            fout.println("-----END PRIVATE KEY-----");
            fout.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5 comments

  • Giacomo Galletto

    Hello,

    great article, my congratulation.

    Anyway, I’m experiencing a convertion from a keystore.ks (not .jks: probably generated with the 1.5 version of java) to a .pfx file.
    Your code throw an “Invalid keystore format” exception (which I have appended here), I guess because is expecting a .jks keystore generated with the 1.6 version of java.

    So, I’m wondering if there is the way to adjust your code in order to let it work with .ks keystore.

    Best regards
    Giacomo Galletto

    java.io.IOException: Invalid keystore format at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:633) at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:38) at java.security.KeyStore.load(KeyStore.java:1185)
    at ExportKeyAndCert.main(ExportKeyAndCert.java:86)

  • Shrenik

    In the last step while converting private.key to pfx format, I am getting error saying “Loading ‘screen’ into random state – done”
    “Unable to load private key”

    Please guide

  • mishomor

    I got the same “Unable to load private key” message. Any updates on this one?

  • amin

    i get Exption java.lang.NullPointerException at ExportKeyCert.Main(ExportKeyAndCert.java:77);

    how to fix it

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>