tags:

views:

5040

answers:

4

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

+5  A: 

A nice clean example for listing all of the aliases in a key store can be found here

    // Load input stream into keystore
    keystore.load(is, password.toCharArray());

    // List the aliases
    Enumeration enum = keystore.aliases();
    for (; enum.hasMoreElements(); ) {
        String alias = (String)enum.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
ConroyP
This worked great. I had a customer that created a certificate request using the tomcat instructions, so the private key was installed in they keystore. I needed it to work with apache.
ScArcher2
A year and a bit later and you've solved someone else's problem (i.e. mine). Good job! :)
Cosmic Flame
Actually, This should be updated with an additional parameter:[3] Key password and the line `Key key = ks.getKey(args[2], args[1].toCharArray());` should read `Key key = ks.getKey(args[2], args[3].toCharArray());`. The original code assumes that the KEY password is the same as the KEYSTORE password, when they are not necessarily identical.
REW
@REW: I have edited the answer to include a more robust version of the key dumper.
VonC
+2  A: 
erickson
+2  A: 

If you don't need to do it programatically, but just want to manage your keys, then I've used IBM's free KeyMan tool for a long time now. Very nice for exporting a private key to a PFX file (then you can easily use OpenSSL to manipulate it, extract it, change pwds, etc).

http://www.alphaworks.ibm.com/tech/keyman/download

Select your keystore, select the private key entry, then File->Save to a pkcs12 file (*.pfx, typically). You can then view the contents with:

$ openssl pkcs12 -in mykeyfile.pfx -info

Dustin
A: 

Here is the answer, found on http://www.memofy.com/memofy/show/000863e71fa863e7008545a7bfe138/How_to_export_private_key_from_SUN_keystore

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.security.*;
import java.security.cert.Certificate;

public class ExportPrivateKey {
  private File keystoreFile;
  private String keyStoreType;
  private char[] password;
  private char[] keypassword;
  private String alias;
  private File exportedFile;

  public static KeyPair getPrivateKey(KeyStore keystore, String alias, char[] password) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
    Key key = keystore.getKey(alias, password);
    if (key instanceof PrivateKey) {
      Certificate cert = keystore.getCertificate(alias);
      PublicKey publicKey = cert.getPublicKey();
      return new KeyPair(publicKey, (PrivateKey) key);
    }
    return null;
  }

  public void export() throws Exception {
    KeyStore keystore = KeyStore.getInstance(keyStoreType);
    BASE64Encoder encoder = new BASE64Encoder();
    keystore.load(new FileInputStream(keystoreFile), password);
    KeyPair keyPair = getPrivateKey(keystore, alias, keypassword);
    PrivateKey privateKey = keyPair.getPrivate();
    String encoded = encoder.encode(privateKey.getEncoded());
    FileWriter fw = new FileWriter(exportedFile);
    fw.write("-----BEGIN PRIVATE KEY-----\n");
    fw.write(encoded);
    fw.write("\n");
    fw.write("-----END PRIVATE KEY-----");
    fw.close();
  }

  public static void main(String args[]) throws Exception {
    ExportPrivateKey export = new ExportPrivateKey();
    export.keystoreFile = new File(args[0]);
    export.keyStoreType = args[1];
    export.password = args[2].toCharArray();
    export.keypassword = args[3].toCharArray();
    export.alias = args[4];
    export.exportedFile = new File(args[5]);
    export.export();
  }
}

Use as follows: java ExportPrivateKey keystoreFile keyStoreType password keypassword alias

Sash