BKS 是流行的第三方 Java 加密库提供商——BouncyCastle 提供的一种密钥库格式。它类似于 Oracle JDK 提供的 JKS 密钥库。
在开始使用 BKS 之前,必须下载并安装 BouncyCastle 提供商。要下载提供商,请访问 BouncyCastle 下载页面。可以通过在 java.security 文件中添加条目来安装提供商。
security.provider.N=org.bouncycastle.jce.provider.BouncyCastleProvider
N 表示提供商列表中的提供商索引。
创建 BKS 密钥库
要创建 BKS 密钥库,只需创建一个“BKS”类型的 KeyStore 实例,并加载 null 输入流和 null 密码。
KeyStore keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(null, null); keyStore.store(new FileOutputStream("mytestkeys.bks"), "password".toCharArray());
存储密钥
与 JKS 不同,密钥可以存储在 BKS 密钥库中。在存储密钥之前,可能需要 不受限制的策略文件。
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(256); Key key = keyGenerator.generateKey(); KeyStore keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(new FileInputStream("mytestkeys.bks"), "password".toCharArray()); keyStore.setKeyEntry("aeskey", key, "password".toCharArray(), null); keyStore.store(new FileOutputStream("mytestkeys.bks"), "password".toCharArray());
存储私钥
除了密钥,私钥也可以存储在 BKS 中。这需要同时存储相应的证书链。否则,将抛出异常。
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 keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(new FileInputStream("mytestkeys.bks"), "password".toCharArray()); keyStore.setKeyEntry("rsakey", key, "password".toCharArray(), chain); keyStore.store(new FileOutputStream("mytestkeys.bks"), "password".toCharArray());
存储证书
有时需要信任库时,不需要在密钥库中存储密钥,只需要存储证书。BKS 支持存储没有相应私钥的证书。
CertAndKeyGen gen = new CertAndKeyGen("RSA","SHA1WithRSA"); gen.generate(1024); X509Certificate cert=gen.getSelfCertificate(new X500Name("CN=SINGLE_CERTIFICATE"), (long)365*24*3600); KeyStore keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(new FileInputStream("mytestkeys.bks"), "password".toCharArray()); keyStore.setCertificateEntry("rsacert", cert); keyStore.store(new FileOutputStream("mytestkeys.bks"), "password".toCharArray());
注意,要存储证书,不需要密码,因为证书通常不需要保护。
加载密钥
从密钥库加载密钥时,只需要指定密钥条目的别名。如果是私钥,则可能需要使用相同的别名来加载证书链。
KeyStore keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(new FileInputStream("mytestkeys.bks"), "password".toCharArray()); Key key = keyStore.getKey("rsakey", "password".toCharArray()); Certificate[] chain = (Certificate[]) keyStore.getCertificateChain("rsakey"); for(java.security.cert.Certificate cert:chain){ System.out.println(cert.toString()); }
输出可能如下所示
[0] Version: 3 SerialNumber: 1676692330 IssuerDN: CN=ROOT Start Date: Sun Jul 03 15:29:46 CST 2016 Final Date: Mon Jul 03 15:29:46 CST 2017 SubjectDN: CN=ROOT Public Key: RSA Public Key modulus: 813dd8db5d26940347116b4986eb7bc89fa423c9d9374a422f2951c9a258458175d97ac586a94da851885453e368e249e1c3b14751a80e8d3ec4dc6be19bfd968fa59209f7d032215946e4ad9b0e261d488a35af250e8dbcb9d0fa5c0c309a2be8fe9535950b9b4c6cdca25f9c2e50ed2786bcbce6b2971c80edef9691ae5d63 public exponent: 10001 Signature Algorithm: SHA1WITHRSA Signature: 00362e9e84c5dd02ed6cf589625257abe55d3c5c fdde5cee362222147b5870b89909e3008567e29b 9b4b5c72342219d167dd058b7d1c59ca4696db4e 28ee791989e731fba86ebb1b2caedce98af2a5e7 44a026cc01d9b4b65e0a65b19a684b1b99b71afe 4d27412e852d977a2855e9f011918ac528555469 aeb8406756185b44
加载证书
这类似于加载密钥,需要证书的别名才能加载。
KeyStore keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(new FileInputStream("mytestkeys.bks"), "password".toCharArray()); Certificate cert = (Certificate) keyStore.getCertificate("rsakey"); System.out.println(cert.toString());
输出可能如下所示
[0] Version: 3 SerialNumber: 1676692330 IssuerDN: CN=ROOT Start Date: Sun Jul 03 15:29:46 CST 2016 Final Date: Mon Jul 03 15:29:46 CST 2017 SubjectDN: CN=ROOT Public Key: RSA Public Key modulus: 813dd8db5d26940347116b4986eb7bc89fa423c9d9374a422f2951c9a258458175d97ac586a94da851885453e368e249e1c3b14751a80e8d3ec4dc6be19bfd968fa59209f7d032215946e4ad9b0e261d488a35af250e8dbcb9d0fa5c0c309a2be8fe9535950b9b4c6cdca25f9c2e50ed2786bcbce6b2971c80edef9691ae5d63 public exponent: 10001 Signature Algorithm: SHA1WITHRSA Signature: 00362e9e84c5dd02ed6cf589625257abe55d3c5c fdde5cee362222147b5870b89909e3008567e29b 9b4b5c72342219d167dd058b7d1c59ca4696db4e 28ee791989e731fba86ebb1b2caedce98af2a5e7 44a026cc01d9b4b65e0a65b19a684b1b99b71afe 4d27412e852d977a2855e9f011918ac528555469 aeb8406756185b44
删除条目
在密钥库中删除条目是一项简单的任务。条目可以是密钥、私钥和证书。只需要指定别名。
KeyStore keyStore = KeyStore.getInstance("BKS", "BC"); keyStore.load(new FileInputStream("mytestkeys.bks"), "password".toCharArray()); keyStore.deleteEntry("aeskey"); keyStore.store(new FileOutputStream("mytestkeys.bks"), "password".toCharArray());
为了使删除生效,需要再次存储密钥库,否则条目不会真正存储。
除了 BKS,BouncyCastle 还提供了另外两种密钥库实现:BouncyCastle 和 PKCS12。
Keystore.BouncyCastle 或 Keystore.UBER 只有在命令行提供密码时才能与 keytool 一起使用,因为整个密钥库都使用基于 SHA1 和 Twofish 的 PBE 进行加密。PBEWithSHAAndTwofish-CBC。这使得整个密钥库能够抵抗篡改和检查,并强制进行验证。Sun JDK 提供的 keytool 即使没有给出密码也会尝试加载密钥库,但这对于此版本来说是不可能的。
PKCS12 提供了与常规密钥库略有不同的情况,密钥库密码当前是用于存储密钥的唯一密码。否则,它支持所有使其能够与 keytool 一起使用的功能。在某些情况下,其他库始终期望处理 Sun 证书,如果是这种情况,请使用 PKCS12-DEF,并且密钥库生成的证书将使用默认提供商。