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

后端 未结 9 472
轮回少年
轮回少年 2020-11-30 19:26

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

相关标签:
9条回答
  • 2020-11-30 19:32

    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
    
    0 讨论(0)
  • 2020-11-30 19:35

    For android development, to convert keystore created in eclipse ADT into public key and private key used in SignApk.jar:

    export private key:

    keytool.exe -importkeystore -srcstoretype JKS -srckeystore my-release-key.keystore -deststoretype PKCS12 -destkeystore keys.pk12.der
    openssl.exe pkcs12 -in keys.pk12.der -nodes -out private.rsa.pem
    

    edit private.rsa.pem and leave "-----BEGIN PRIVATE KEY-----" to "-----END PRIVATE KEY-----" paragraph, then:

    openssl.exe base64 -d -in private.rsa.pem -out private.rsa.der
    

    export public key:

    keytool.exe -exportcert -keystore my-release-key.keystore -storepass <KEYSTORE_PASSWORD> -alias alias_name -file public.x509.der
    

    sign apk:

    java -jar SignApk.jar public.x509.der private.rsa.der input.apk output.apk
    
    0 讨论(0)
  • 2020-11-30 19:36

    First of all, be careful! All of your security depends on the… er… privacy of your private keys. Keytool doesn't have key export built in to avoid accidental disclosure of this sensitive material, so you might want to consider some extra safeguards that could be put in place to protect your exported keys.

    Here is some simple code that gives you unencrypted PKCS #8 PrivateKeyInfo that can be used by OpenSSL (see the -nocrypt option of its pkcs8 utility):

    KeyStore keys = ...
    char[] password = ...
    Enumeration<String> aliases = keys.aliases();
    while (aliases.hasMoreElements()) {
      String alias = aliases.nextElement();
      if (!keys.isKeyEntry(alias))
        continue;
      Key key = keys.getKey(alias, password);
      if ((key instanceof PrivateKey) && "PKCS#8".equals(key.getFormat())) {
        /* Most PrivateKeys use this format, but check for safety. */
        try (FileOutputStream os = new FileOutputStream(alias + ".key")) {
          os.write(key.getEncoded());
          os.flush();
        }
      }
    }
    

    If you need other formats, you can use a KeyFactory to get a transparent key specification for different types of keys. Then you can get, for example, the private exponent of an RSA private key and output it in your desired format. That would make a good topic for a follow-up question.

    0 讨论(0)
  • 2020-11-30 19:39

    This question came up on stackexchange security, one of the suggestions was to use Keystore explorer

    https://security.stackexchange.com/questions/3779/how-can-i-export-my-private-key-from-a-java-keytool-keystore

    Having just tried it, it works really well and I strongly recommend it.

    0 讨论(0)
  • 2020-11-30 19:46

    Here is a shorter version of the above code, in Groovy. Also has built-in base64 encoding:

    import java.security.Key
    import java.security.KeyStore
    
    if (args.length < 3)
            throw new IllegalArgumentException('Expected args: <Keystore file> <Keystore format> <Keystore password> <alias> <key password>')
    
    def keystoreName = args[0]
    def keystoreFormat = args[1]
    def keystorePassword = args[2]
    def alias = args[3]
    def keyPassword = args[4]
    
    def keystore = KeyStore.getInstance(keystoreFormat)
    keystore.load(new FileInputStream(keystoreName), keystorePassword.toCharArray())
    def key = keystore.getKey(alias, keyPassword.toCharArray())
    
    println "-----BEGIN PRIVATE KEY-----"
    println key.getEncoded().encodeBase64()
    println "-----END PRIVATE KEY-----"
    
    0 讨论(0)
  • 2020-11-30 19:51

    You can extract a private key from a keystore with Java6 and OpenSSL. This all depends on the fact that both Java and OpenSSL support PKCS#12-formatted keystores. To do the extraction, you first use keytool to convert to the standard format. Make sure you use the same password for both files (private key password, not the keystore password) or you will get odd failures later on in the second step.

    keytool -importkeystore -srckeystore keystore.jks \
        -destkeystore intermediate.p12 -deststoretype PKCS12
    

    Next, use OpenSSL to do the extraction to PEM:

    openssl pkcs12 -in intermediate.p12 -out extracted.pem -nodes
    

    You should be able to handle that PEM file easily enough; it's plain text with an encoded unencrypted private key and certificate(s) inside it (in a pretty obvious format).

    When you do this, take care to keep the files created secure. They contain secret credentials. Nothing will warn you if you fail to secure them correctly. The easiest method for securing them is to do all of this in a directory which doesn't have any access rights for anyone other than the user. And never put your password on the command line or in environment variables; it's too easy for other users to grab.

    0 讨论(0)
提交回复
热议问题