Java 如何从密钥库中列出/导出私钥?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/150167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:57:09  来源:igfitidea点击:

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

javasslkeystore

提问by ScArcher2

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

如何从密钥库中列出和导出私钥?

采纳答案by ConroyP

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

最初来自 Example Depot 的一部分代码,用于列出密钥存储中的所有别名:

    // 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 forumsa couple of months ago, and u:turingcompletercame up with a DumpPrivateKey class to stitch into your app.

几个月前,Sun 论坛上出现了私钥的导出,而u:turingcompleter提出了一个 DumpPrivateKey 类来拼接到您的应用程序中。

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:

注意:这使用了 Sun 包,这是一件“坏事”
如果您可以下载apache commons 代码,这里是一个编译时不会发出警告的版本:

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

回答by erickson

First of all, be careful! All of your security depends on the… er… privacyof 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.

首先,要小心!您所有的安全都取决于……呃……您的私钥的隐私Keytool 没有内置密钥导出功能,以避免意外泄露此敏感材料,因此您可能需要考虑一些额外的安全措施来保护您导出的密钥。

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

这是一些简单的代码,它为您提供 OpenSSL 可以使用的未加密的 PKCS #8 PrivateKeyInfo(请参阅-nocryptpkcs8 实用程序的选项):

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.

如果需要其他格式,可以使用 KeyFactory 获取不同类型密钥的透明密钥规范。然后您可以获取例如 RSA 私钥的私有指数并以您想要的格式输出它。这将成为后续问题的好话题。

回答by DustinB

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).

如果您不需要以编程方式执行此操作,而只想管理您的密钥,那么我已经使用 IBM 的免费 KeyMan 工具已有很长时间了。非常适合将私钥导出到 PFX 文件(然后您可以轻松使用 OpenSSL 对其进行操作、提取、更改密码等)。

https://www.ibm.com/developerworks/mydeveloperworks/groups/service/html/communityview?communityUuid=6fb00498-f6ea-4f65-bf0c-adc5bd0c5fcc

https://www.ibm.com/developerworks/mydeveloperworks/groups/service/html/communityview?communityUuid=6fb00498-f6ea-4f65-bf0c-adc5bd0c5fcc

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

选择您的密钥库,选择私钥条目,然后文件->保存到 pkcs12 文件(通常为 *.pfx)。然后,您可以使用以下命令查看内容:

$ openssl pkcs12 -in mykeyfile.pfx -info

$ openssl pkcs12 -in mykeyfile.pfx -info

回答by Donal Fellows

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 keytoolto 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.

您可以使用 Java6 和 OpenSSL 从密钥库中提取私钥。这一切都取决于 Java 和 OpenSSL 都支持 PKCS#12 格式的密钥库这一事实。要进行提取,您首先使用keytool转换为标准格式。确保您对两个文件使用相同的密码(私钥密码,而不是密钥库密码),否则您将在稍后的第二步中遇到奇怪的失败。

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

Next, use OpenSSL to do the extraction to PEM:

接下来,使用 OpenSSL 对 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).

您应该能够轻松处理该 PEM 文件;它是纯文本,其中包含编码的未加密私钥和证书(以非常明显的格式)。

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.

执行此操作时,请注意确保创建的文件安全。它们包含秘密凭证。如果您未能正确保护它们,则不会警告您。保护它们的最简单方法是在一个目录中执行所有这些操作,该目录对用户以外的任何人都没有任何访问权限。永远不要把你的密码放在命令行或环境变量中;其他用户太容易抢了。

回答by diyism

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

对于android开发,将eclipse ADT中创建的keystore转换为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:

编辑 private.rsa.pem 并将“-----BEGIN PRIVATE KEY-----”保留为“-----END PRIVATE KEY-----”段落,然后:

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:

签署apk:

java -jar SignApk.jar public.x509.der private.rsa.der input.apk output.apk

回答by jrk

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

这是上述代码的较短版本,在 Groovy 中。还内置了 base64 编码:

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-----"

回答by Kkkev

Another less-conventional but arguably easier way of doing this is with JXplorer. Although this tool is designed to browse LDAP directories, it has an easy-to-use GUI for manipulating keystores. One such function on the GUI can export private keys from a JKS keystore.

另一种不太传统但可以说更简单的方法是使用JXplorer。尽管此工具旨在浏览 LDAP 目录,但它具有用于操作密钥库的易于使用的 GUI。GUI 上的一个这样的功能可以从 JKS 密钥库导出私钥。

回答by PhilDin

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

这个问题是关于 stackexchange 安全性的,建议之一是使用Keystore explorer

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

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.

刚刚尝试过,效果非常好,我强烈推荐它。

回答by Davio

Another great tool is KeyStore Explorer: http://keystore-explorer.sourceforge.net/

另一个很棒的工具是 KeyStore Explorer:http: //keystore-explorer.sourceforge.net/