Java密钥库的不同类型 -- JKS

原文:https://www.pixelstech.net/article/1409966488-Different-types-of-keystore-in-Java----JKS

转载:https://www.cnblogs.com/yangchongxing/p/13834467.html

机器翻译

Different types of keystore in Java -- JKS

Java密钥库的不同类型 -- JKS

JKS is Java Keystore, a proprietary keystore type designed for Java. It can be used to store private keys and certificates used for SSL communication, it cannot store secret keys however. The keytool shipped with JDKs cannot extract private keys stored on JKS. This type of keystore usually has an extension of jks.

JKS是Java密钥库,一种专为Java设计的密钥库类型。它可以用来存储用于SSL通信的私钥和证书,但是它不能存储密钥。JDKs附带的keytool无法提取JKS上存储的私钥。这种类型的密钥库通常有jks的扩展。

Next we will show how to operate the JKS keystore with pure Java code.

接下来,我们将展示如何使用纯Java代码操作JKS密钥库。

Create JKS keystore

创建JKS密钥库

The simplest method to create a JKS keystore to create an empty keystore. We can first get an instance of KeyStore and then load a null keystore. After loading the null keystore, we just need to call KeyStore.store() with the keystore name and password of the keystore.
Below is a simple demo:

创建JKS密钥库的最简单方法是创建空密钥库。我们可以首先获得KeyStore的一个实例,然后加载一个空KeyStore。加载空密钥库后,我们只需要调用KeyStore.store()方法并传递密钥库名称和密钥库的密码。

下面是一个简单的演示:

try{
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(null,null);
     
    keyStore.store(new FileOutputStream("mytestkey.jks"), "password".toCharArray());
}catch(Exception ex){
    ex.printStackTrace();
}

Post execution of above call, you will see a keystore named mytestkey.jks in current working directory. Now the keystore is empty without any entries.

在执行上述调用后,您将看到一个名为mytestkey.jks在当前工作目录中。现在密钥库是空的,没有任何条目

Store private key

存储私钥

Now let's store one private key and its associated certificate chain into the keystore. Note we can not store a private key without an associated certificate chain into a keystore using JDK. With some other library or native libraries, you may be able to store a private key without associated certificate chain.

现在让我们将一个私钥及其关联的证书链存储到密钥库中。注意:我们不能使用JDK将没有相关证书链的私钥存储到密钥库中。对于其他一些库或本机库,您可能能够存储私钥,而无需关联的证书链。

try{
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream("mytestkey.jks"),"password".toCharArray());
     
    CertAndKeyGen gen = new CertAndKeyGen("RSA","SHA1WithRSA");
    gen.generate(1024);
     
    Key key=gen.getPrivateKey();
    X509Certificate cert=gen.getSelfCertificate(new X500Name("CN=ROOT"), (long)365*24*3600);
     
    X509Certificate[] chain = new X509Certificate[1];
    chain[0]=cert;
     
    keyStore.setKeyEntry("mykey", key, "password".toCharArray(), chain);
     
    keyStore.store(new FileOutputStream("mytestkey.jks"), "password".toCharArray());
}catch(Exception ex){
    ex.printStackTrace();
}

First, we will create a private key and a self signed certificate and then call KeyStore.setKeyEntry() with the specified alias, key, the password for the key and its associated certificate chain. Remember we need to call KeyStore.store() to store the key into the keystore.

首先,我们将创建一个私钥和一个自签名证书,然后调用KeyStore.setKeyEntry()方法(参数:别名、私钥、密码),私钥的密码和证书关联。记住我们需要调用KeyStore.store()方法把私钥保存如密钥库。

The alias is the label of the entry so that it can be found easily later.

别名是条目的标签,以便以后很容易找到它。

Store certificate

存储证书

We can store certificate on JKS keystore. The certificate to be store should be a X509Certificate. It can be stored on the keystore without associated private key. This process is similar to storing private key.

我们可以在JKS密钥库中存储证书。要存储的证书应为X509证书。它可以存储在没有相关私钥的密钥库中。这个过程类似于存储私钥。

try{
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream("mytestkey.jks"),"password".toCharArray());
     
    CertAndKeyGen gen = new CertAndKeyGen("RSA","SHA1WithRSA");
    gen.generate(1024);
     
    X509Certificate cert = gen.getSelfCertificate(new X500Name("CN=SINGLE_CERTIFICATE"), (long)365*24*3600);
     
    keyStore.setCertificateEntry("single_cert", cert);
     
    keyStore.store(new FileOutputStream("mytestkey.jks"), "password".toCharArray());
}catch(Exception ex){
    ex.printStackTrace();
}

Loading private key

加载私钥

After storing the keys, we can also load the entries inside the keystore. Here we are saying to load private key, actually it's not the case here, as we described earlier, the private key cannot be extracted from JKS using Java. Here we actually extract the certificate chain of the private key.

在存储密钥之后,我们还可以加载密钥库中的条目。这里我们说的是加载私钥,实际上这里不是这样,正如我们前面所描述的,私钥不能用Java从JKS中提取出来。这里我们实际上提取了私钥的证书链。

try{
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream("mytestkey.jks"),"password".toCharArray());
     
    Key key = keyStore.getKey("mykey", "password".toCharArray());
//          System.out.println("Private key : "+key.toString());   //You will get a NullPointerException if you uncomment this line
     
    java.security.cert.Certificate[] chain =  keyStore.getCertificateChain("mykey");
    for(java.security.cert.Certificate cert:chain){
        System.out.println(cert.toString());
    }
}catch(Exception ex){
    ex.printStackTrace();
}

Note the commented line, the key will be null as expected. We can get the certificate chain as normal though.

注意注释行,键将如预期的那样为null。我们可以正常获取证书链。

[
[
  Version: V3
  Subject: CN=ROOT
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
 
  Key:  Sun RSA public key, 1024 bits
  modulus: 90980299845597512779139009881469177009407272139633139241921529845092210461181243924599150259446249079941561941533303439718936138867375776965995893255358889228584415558006141961051402385279285497775776996780406808976543439543789816486513982581378223575354716191394304768315366544413052547926792470794374067383
  public exponent: 65537
  Validity: [From: Sat Sep 06 09:57:28 CST 2014,
               To: Sun Sep 06 09:57:28 CST 2015]
  Issuer: CN=ROOT
  SerialNumber: [    206b697b]
 
]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 53 6A FD FE E6 3A 5E 6E   A6 43 C4 F4 D1 56 D4 08  Sj...:^n.C...V..
0010: 7E 3B 8B 73 68 71 56 AB   96 FE 24 E7 2D DC 04 BB  .;.shqV...$.-...
0020: 14 B0 C6 71 8D F0 3E EC   FE D8 5B BB 8C 0F 55 63  ...q..>...[...Uc
0030: 2B 38 8E 45 F1 2D F0 BB   8C 6D 13 A8 11 37 E1 FA  +8.E.-...m...7..
0040: 77 AF C7 73 72 2B 40 4F   74 32 F6 3C 24 E6 AB ED  w..sr+@Ot2.<$...
0050: 2C 6F 19 2E DC 58 5F CB   75 62 40 2F 3E BE 59 99  ,o...X_.ub@/>.Y.
0060: C0 1F 7A 70 15 AF C3 66   B3 4F C9 11 C3 45 59 EF  ..zp...f.O...EY.
0070: 36 F4 1C C9 9B FA 5E 43   A0 28 DB 07 0D F2 53 6E  6.....^C.(....Sn
 
]

加载证书

Loading certificate

This is similar to loading private key, we need to pass the alias of the certificate we want to extract.

这与加载私钥类似,我们需要传递要提取的证书的别名。

try{
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream("mytestkey.jks"),"password".toCharArray());
     
    java.security.cert.Certificate cert = keyStore.getCertificate("single_cert");
     
    System.out.println(cert.toString());
}catch(Exception ex){
    ex.printStackTrace();
}

The output will be:

输出将是:

[
[
  Version: V3
  Subject: CN=SINGLE_CERTIFICATE
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5
 
  Key:  Sun RSA public key, 1024 bits
  modulus: 99756834215197288877309915243024788596281418171661241282881476656110879586349799740269767889529808199104172091786860877280382867461569439907754755558759387462421169749111354565793974372777424046360810758009149155148290676527032833774084635148674232352006810533640038723102562578516643345287042787777951043863
  public exponent: 65537
  Validity: [From: Sat Sep 06 10:14:33 CST 2014,
               To: Sun Sep 06 10:14:33 CST 2015]
  Issuer: CN=SINGLE_CERTIFICATE
  SerialNumber: [    6943e549]
 
]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 35 58 70 96 F4 35 82 2A   95 9F BB 31 02 6E 7C 29  5Xp..5.*...1.n.)
0010: 4A FE AF EB 2D B5 3A A7   C7 9D 4C 9A 34 2C 5C 46  J...-.:...L.4,F
0020: C2 82 A8 AC 1A C0 98 A5   67 21 74 7B 1E E2 E5 AC  ........g!t.....
0030: DE B2 1D 87 BE 16 45 9B   D0 2A D3 2B F6 E1 4B 35  ......E..*.+..K5
0040: 27 8B A7 0A EF F2 07 41   90 A6 69 07 BE 87 C5 B1  '......A..i.....
0050: 54 DE DB A2 5A 41 47 3B   3F A7 74 6F 5C C8 8D B4  T...ZAG;?.to...
0060: C8 65 2B 0F 8E 94 A8 80   C7 8B B5 78 FA C2 9C ED  .e+........x....
0070: 8E EC 28 E4 8E 62 A1 59   6A BC 37 7B 0D FC C7 AF  ..(..b.Yj.7.....
 
]

Import keys and certificates

导入密钥和证书

This process is actually very simple, we first need to load the keystore where the certificate to be imported. Then we also need to load another keystore where we need to import certificate to. Next, we need to get the certificate from source keystore and put it into the destination keystore.

这个过程实际上非常简单,我们首先需要加载密钥库,在那里导入证书。然后我们还需要加载另一个密钥库,我们需要将证书导入到其中。接下来,我们需要从源密钥库获取证书并将其放入目标密钥库中。

Since we cannot extract private key from JKS, so we can only import certificate to JKS. However, we can extract private keys from other types of keystore(PKCS12) and then store them in JKS keystore.

由于无法从JKS中提取私钥,所以只能将证书导入JKS。但是,我们可以从其他类型的密钥库(PKCS12)中提取私钥,然后将它们存储在JKS密钥库中。

One final piece of information. Oracle provides two versions of JKS keystore : case sensitive and case insensitive. When calling KeyStore.getInstance("JKS"), a case insensitive version of JKS instance is created, when KeyStore.getInstance("CaseExactJKS") is called, a case sensitive version of JKS instance will be created. Usually case insensitive is recommended as an user should distinguish different entries with different alias names instead of different alias name cases. For more information about case sensitivity, please refer to this post.

最后一条信息。Oracle提供了两个版本的JKS密钥库:区分大小写和不区分大小写。当调用KeyStore.getInstance("JKS")时将创建一个不区分大小写版本的JKS实例。当调用KeyStore.getInstance("CaseExactJKS")时将创建区分大小写版本的JKS实例。通常建议不区分大小写,因为用户应该区分具有不同别名的不同条目,而不是不同的别名大小写。有关区分大小写的更多信息,请参阅这篇文章。

原文地址:https://www.cnblogs.com/yangchongxing/p/13834467.html