Search code examples
javasslkeystore

How do I list / export private keys from a keystore?


How do I list and export a private key from a keystore?


Solution

  • A portion of code originally from Example Depot for listing all of the aliases in a key store:

        // Load input stream into keystore
        keystore.load(is, password.toCharArray());
    
        // List the aliases
        Enumeration aliases = keystore.aliases();
        for (; aliases.hasMoreElements(); ) {
            String alias = (String)aliases.nextElement();
    
            // Does alias refer to a private key?
            boolean b = keystore.isKeyEntry(alias);
    
            // Does alias refer to a trusted certificate?
            b = keystore.isCertificateEntry(alias);
        }
    

    The exporting of private keys came up on the Sun forums a couple of months ago, and u:turingcompleter came up with a DumpPrivateKey class to stitch into your app.

    import java.io.FileInputStream;
    import java.security.Key;
    import java.security.KeyStore;
    import sun.misc.BASE64Encoder;
    
    public class DumpPrivateKey {
         /**
         * Provides the missing functionality of keytool
         * that Apache needs for SSLCertificateKeyFile.
         *
         * @param args  <ul>
         *              <li> [0] Keystore filename.
         *              <li> [1] Keystore password.
         *              <li> [2] alias
         *              </ul>
         */
        static public void main(String[] args)
        throws Exception {
            if(args.length < 3) {
              throw new IllegalArgumentException("expected args: Keystore filename, Keystore password, alias, <key password: default same tha
    n keystore");
            }
            final String keystoreName = args[0];
            final String keystorePassword = args[1];
            final String alias = args[2];
            final String keyPassword = getKeyPassword(args,keystorePassword);
            KeyStore ks = KeyStore.getInstance("jks");
            ks.load(new FileInputStream(keystoreName), keystorePassword.toCharArray());
            Key key = ks.getKey(alias, keyPassword.toCharArray());
            String b64 = new BASE64Encoder().encode(key.getEncoded());
            System.out.println("-----BEGIN PRIVATE KEY-----");
            System.out.println(b64);
            System.out.println("-----END PRIVATE KEY-----");
        }
        private static String getKeyPassword(final String[] args, final String keystorePassword)
        {
           String keyPassword = keystorePassword; // default case
           if(args.length == 4) {
             keyPassword = args[3];
           }
           return keyPassword;
        }
    }
    

    Note: this use Sun package, which is a "bad thing".
    If you can download apache commons code, here is a version which will compile without warning:

    javac -classpath .:commons-codec-1.4/commons-codec-1.4.jar DumpPrivateKey.java
    

    and will give the same result:

    import java.io.FileInputStream;
    import java.security.Key;
    import java.security.KeyStore;
    //import sun.misc.BASE64Encoder;
    import org.apache.commons.codec.binary.Base64;
    
    public class DumpPrivateKey {
         /**
         * Provides the missing functionality of keytool
         * that Apache needs for SSLCertificateKeyFile.
         *
         * @param args  <ul>
         *              <li> [0] Keystore filename.
         *              <li> [1] Keystore password.
         *              <li> [2] alias
         *              </ul>
         */
        static public void main(String[] args)
        throws Exception {
            if(args.length < 3) {
              throw new IllegalArgumentException("expected args: Keystore filename, Keystore password, alias, <key password: default same tha
    n keystore");
            }
            final String keystoreName = args[0];
            final String keystorePassword = args[1];
            final String alias = args[2];
            final String keyPassword = getKeyPassword(args,keystorePassword);
            KeyStore ks = KeyStore.getInstance("jks");
            ks.load(new FileInputStream(keystoreName), keystorePassword.toCharArray());
            Key key = ks.getKey(alias, keyPassword.toCharArray());
            //String b64 = new BASE64Encoder().encode(key.getEncoded());
            String b64 = new String(Base64.encodeBase64(key.getEncoded(),true));
            System.out.println("-----BEGIN PRIVATE KEY-----");
            System.out.println(b64);
            System.out.println("-----END PRIVATE KEY-----");
        }
        private static String getKeyPassword(final String[] args, final String keystorePassword)
        {
           String keyPassword = keystorePassword; // default case
           if(args.length == 4) {
             keyPassword = args[3];
           }
           return keyPassword;
        }
    }
    

    You can use it like so:

    java -classpath .:commons-codec-1.4/commons-codec-1.4.jar DumpPrivateKey $HOME/.keystore changeit tomcat