如何使用 java 代码将证书和私钥导出为单个文件?
How to export Certificate and private key as a single file using java code?
我的要求是结合证书和私钥,然后使用 PEMwriter 导出文件。
我用bouncycastle生成了私钥和csr。然后,我向CA提交了CSR并获得了证书。
以下代码用于生成密钥对
KeyPair idPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
PublicKey publicKey = idPair.getPublic();
PrivateKey privkey = idPair.getPrivate();
以下代码用于接收证书并将其导出到 .cer 文件。
CertStore store = response.getCertStore();
Collection<? extends Certificate> certs = store
.getCertificates(null);
Certificate[] chain = new Certificate[certs.size()];
int i = 0;
for (Certificate certificate : certs) {
chain[i++] = certificate;
}
FileOutputStream os = new FileOutputStream("cert.cer");
os.write("-----BEGIN CERTIFICATE-----\n".getBytes("US-ASCII"));
os.write(Base64.encodeBase64(chain[0].getEncoded(), true));
os.write("-----END CERTIFICATE-----\n".getBytes("US-ASCII"));
os.close();
现在,我的目标是当我打开导出的文件时,系统必须提示我输入 install/view 证书的密码。我对这部分真的很困惑。之前我将密码添加到密钥库,如下所示
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(null, null);
keyStore.setKeyEntry("mykey", (Key) keyPair.getPrivate(), "Password1!".toCharArray(), certz);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
keyStore.store(bout, "Password1!".toCharArray()); // this is the password to open the .p12
byte[] keystore = bout.toByteArray();
bout.close();
但是,现在,我需要用密码保护证书。这可能吗?如果是这样,文件扩展名是什么?请在编码部分 (PemWriter) 指导我。
谢谢
THe following code is for receiving the certificate and exporting it to .cer file.
CertStore store = response.getCertStore();
Collection<? extends Certificate> certs = store
.getCertificates(null);
Certificate[] chain = new Certificate[certs.size()];
int i = 0;
for (Certificate certificate : certs) {
chain[i++] = certificate;
}
旁白:您不需要那个循环来将 Collection
转换为数组,只需调用 .toArray (new T[optionally_correct_size])
即可。另一方面,由于您只使用第一个元素,所以根本不需要数组,只需 Collection<T>.iterator().next()
.
更重要的是,在第三方面,许多——但绝对不是全部——使用私钥完成的操作也需要完整的证书链,而不仅仅是 leaf/end-entity 证书,才能正常工作。例如,一些签名者可以在没有链的情况下计算签名,但在某些情况下,签名无法验证,因此会被接收者拒绝。由于您不知道导出文件的使用方式、用途和用途,因此无法就此提供任何建议。如果需要 完整链,那么您是否可以只使用一系列 individual/separate PEM 证书或需要其他东西也会有所不同。
我不知道你用的是什么 Base64
编码器;该签名与 BouncyCastle 签名不匹配。我希望它能正确生成换行符。 PEM 格式不仅仅是 BEGIN-line、base64、END-line;它是 BEGIN-line,base64 ,带有换行符 ,END-line。 有些 软件会工作,有时,即使没有换行符,但有些软件有时会失败。参见 RFC 7468 sec 2 near the end。
Now, my goal is when I open the exported file, I must be prompted to input password to install/view the certificate. ... But, now, I need to protect the certificate with password. Is this even possible?
您需要区分私钥和证书。尽管在重要方面相关,但它们是不同的东西,私钥设计为 private/secret,而证书设计为 public。特别是,PEM 格式证书未加密,因此任何人都可以查看它并将其用于 public 密钥操作(加密或验证),或者用它做任何他们喜欢的事情。
但是要执行私钥操作(解密或签名),您需要私钥——通常链接到如上所述的证书或链——以及私钥可以是password-encrypted(至少)两种不同的习惯PEM格式,因此需要密码'open'它。早在 1990 年代的 OpenSSL de-facto 就定义了一个 PEM 加密方案,它可以用于它的几种 'legacy' 或 'traditional' 私钥格式,这些格式对于每个算法,并在 BEGIN-line 中的 PEM 类型中指明,因此 -----BEGIN RSA PRIVATE KEY-----
、-----BEGIN DSA PRIVATE KEY-----
、-----BEGIN EC PRIVATE KEY-----
等 之后 PKCS8 defined a generic privatekey format for all algorithms, used by much other software including Java crypto (JCA), including an encrypted variant designated by -----BEGIN ENCRYPTED PRIVATE KEY-----
(note no algorithm name). The PKCS8 version (only) has been made official by RFC7468 sec 11。 (OpenSSH、PuTTY 和 PGP 使用的私钥还有其他完全不同的 PEM-like 格式,但其中 none 使用 X.509 类型的证书。虽然 GnuPG 现在实现了 PGP 和 S/MIME,并且确实使用 X.509/PKIX for S/MIME。SO 上有许多现有的问题,一些在 security.SX 或 crypto.SX,如果您对这些感兴趣。) bcpkix
实现 OpenSSL-legacy 形式 和 PKCS8 形式。 (Java 单独没有 BouncyCastle 实现 PKCS8 未加密。)
类似地,'legacy' Java 密钥库(JKS 和 JCEKS)password-encrypt 私钥,但不是证书。 PKCS12 标准实际上非常灵活(也很复杂),但是 通常实施的 (包括您的 BC-keystore 示例)对私钥使用强密码加密,并且非常证书的弱易破密码加密;我一直不太清楚为什么,因为在不提供任何安全优势的情况下这不太方便。
If so, what will be the file extension?
这主要取决于您,或者这些文件的所有人(如果有的话)。没有标准要求文件扩展名与文件内容相匹配,反之亦然,尽管人们通常这样做是因为这样更方便。官方 .cer
应该是 DER 证书,并且 RFC7468 sec 5.3 建议 使用 .crt
作为 PEM证书。如果您将密钥写入单独的文件,使用 .key
或 .pem
似乎很常见,但我知道没有标准(当然也没有 IANA 注册)对此进行指定。 (RFC5958 注册 .p8 实际上是 DER PKCS8 未加密,RFC8351 注册 DER PKCS8 加密但未指定 any 扩展名。)如果您编写密钥和same 文件的证书,PEM 格式支持但并非所有程序都支持,除了 .pem
.
我什至没有看到常见的做法
所以终于可以回答你的问题了:-)
假设您的提供者列表(和类路径)中有 BC 提供者,类路径中有 bcpkix,并且 kv
中有一个 PrivateKey
对象:
import org.bouncycastle.openssl.PKCS8Generator;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
import org.bouncycastle.util.io.pem.PemWriter;
// for the OpenSSL legacy form
JcaPEMWriter x = new JcaPEMWriter (new OutputStreamWriter(System.out)); // or whatever
x.writeObject(kv, new JcePEMEncryptorBuilder("DES-EDE3-CBC").build("password".toCharArray()) );
// can substitute AES-{128,192,256}-CBC if desired, for more see source
x.close(); // or flush to keep underlying writer/stream
// for the PKCS8 form
PemWriter y = new PemWriter (new OutputStreamWriter(System.out)); // or whatever
y.writeObject(new JcaPKCS8Generator (kv, new JceOpenSSLPKCS8EncryptorBuilder(
PKCS8Generator.DES3_CBC).setPasssword("password".toCharArray()).build() ) );
// or AES_{128,192,256}_CBC, others will use PBES1 which is deprecated
y.close(); // or flush to keep underlying writer/stream
如上所述,对于正常使用,您不需要使用密码来保护证书。但是,如果您想将一些证书存储在安全的地方,您可以在 password-protected 密钥库文件中进行(仅 java.security 代码,不需要 PemWriter)。
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, null);
Certificate cert = getX509Cert(); // load certificate
ks.setCertificateEntry("myCertAlias", cert);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(PATH + "newKeyStore.p12");
char[] password = PASSWORD_.toCharArray();
ks.store(fos, password);
} finally {
if (fos != null) {
fos.close();
}
}
我的要求是结合证书和私钥,然后使用 PEMwriter 导出文件。
我用bouncycastle生成了私钥和csr。然后,我向CA提交了CSR并获得了证书。 以下代码用于生成密钥对
KeyPair idPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
PublicKey publicKey = idPair.getPublic();
PrivateKey privkey = idPair.getPrivate();
以下代码用于接收证书并将其导出到 .cer 文件。
CertStore store = response.getCertStore();
Collection<? extends Certificate> certs = store
.getCertificates(null);
Certificate[] chain = new Certificate[certs.size()];
int i = 0;
for (Certificate certificate : certs) {
chain[i++] = certificate;
}
FileOutputStream os = new FileOutputStream("cert.cer");
os.write("-----BEGIN CERTIFICATE-----\n".getBytes("US-ASCII"));
os.write(Base64.encodeBase64(chain[0].getEncoded(), true));
os.write("-----END CERTIFICATE-----\n".getBytes("US-ASCII"));
os.close();
现在,我的目标是当我打开导出的文件时,系统必须提示我输入 install/view 证书的密码。我对这部分真的很困惑。之前我将密码添加到密钥库,如下所示
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(null, null);
keyStore.setKeyEntry("mykey", (Key) keyPair.getPrivate(), "Password1!".toCharArray(), certz);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
keyStore.store(bout, "Password1!".toCharArray()); // this is the password to open the .p12
byte[] keystore = bout.toByteArray();
bout.close();
但是,现在,我需要用密码保护证书。这可能吗?如果是这样,文件扩展名是什么?请在编码部分 (PemWriter) 指导我。 谢谢
THe following code is for receiving the certificate and exporting it to .cer file.
CertStore store = response.getCertStore();
Collection<? extends Certificate> certs = store
.getCertificates(null);
Certificate[] chain = new Certificate[certs.size()];
int i = 0;
for (Certificate certificate : certs) {
chain[i++] = certificate;
}
旁白:您不需要那个循环来将 Collection
转换为数组,只需调用 .toArray (new T[optionally_correct_size])
即可。另一方面,由于您只使用第一个元素,所以根本不需要数组,只需 Collection<T>.iterator().next()
.
更重要的是,在第三方面,许多——但绝对不是全部——使用私钥完成的操作也需要完整的证书链,而不仅仅是 leaf/end-entity 证书,才能正常工作。例如,一些签名者可以在没有链的情况下计算签名,但在某些情况下,签名无法验证,因此会被接收者拒绝。由于您不知道导出文件的使用方式、用途和用途,因此无法就此提供任何建议。如果需要 完整链,那么您是否可以只使用一系列 individual/separate PEM 证书或需要其他东西也会有所不同。
我不知道你用的是什么 Base64
编码器;该签名与 BouncyCastle 签名不匹配。我希望它能正确生成换行符。 PEM 格式不仅仅是 BEGIN-line、base64、END-line;它是 BEGIN-line,base64 ,带有换行符 ,END-line。 有些 软件会工作,有时,即使没有换行符,但有些软件有时会失败。参见 RFC 7468 sec 2 near the end。
Now, my goal is when I open the exported file, I must be prompted to input password to install/view the certificate. ... But, now, I need to protect the certificate with password. Is this even possible?
您需要区分私钥和证书。尽管在重要方面相关,但它们是不同的东西,私钥设计为 private/secret,而证书设计为 public。特别是,PEM 格式证书未加密,因此任何人都可以查看它并将其用于 public 密钥操作(加密或验证),或者用它做任何他们喜欢的事情。
但是要执行私钥操作(解密或签名),您需要私钥——通常链接到如上所述的证书或链——以及私钥可以是password-encrypted(至少)两种不同的习惯PEM格式,因此需要密码'open'它。早在 1990 年代的 OpenSSL de-facto 就定义了一个 PEM 加密方案,它可以用于它的几种 'legacy' 或 'traditional' 私钥格式,这些格式对于每个算法,并在 BEGIN-line 中的 PEM 类型中指明,因此 -----BEGIN RSA PRIVATE KEY-----
、-----BEGIN DSA PRIVATE KEY-----
、-----BEGIN EC PRIVATE KEY-----
等 之后 PKCS8 defined a generic privatekey format for all algorithms, used by much other software including Java crypto (JCA), including an encrypted variant designated by -----BEGIN ENCRYPTED PRIVATE KEY-----
(note no algorithm name). The PKCS8 version (only) has been made official by RFC7468 sec 11。 (OpenSSH、PuTTY 和 PGP 使用的私钥还有其他完全不同的 PEM-like 格式,但其中 none 使用 X.509 类型的证书。虽然 GnuPG 现在实现了 PGP 和 S/MIME,并且确实使用 X.509/PKIX for S/MIME。SO 上有许多现有的问题,一些在 security.SX 或 crypto.SX,如果您对这些感兴趣。) bcpkix
实现 OpenSSL-legacy 形式 和 PKCS8 形式。 (Java 单独没有 BouncyCastle 实现 PKCS8 未加密。)
类似地,'legacy' Java 密钥库(JKS 和 JCEKS)password-encrypt 私钥,但不是证书。 PKCS12 标准实际上非常灵活(也很复杂),但是 通常实施的 (包括您的 BC-keystore 示例)对私钥使用强密码加密,并且非常证书的弱易破密码加密;我一直不太清楚为什么,因为在不提供任何安全优势的情况下这不太方便。
If so, what will be the file extension?
这主要取决于您,或者这些文件的所有人(如果有的话)。没有标准要求文件扩展名与文件内容相匹配,反之亦然,尽管人们通常这样做是因为这样更方便。官方 .cer
应该是 DER 证书,并且 RFC7468 sec 5.3 建议 使用 .crt
作为 PEM证书。如果您将密钥写入单独的文件,使用 .key
或 .pem
似乎很常见,但我知道没有标准(当然也没有 IANA 注册)对此进行指定。 (RFC5958 注册 .p8 实际上是 DER PKCS8 未加密,RFC8351 注册 DER PKCS8 加密但未指定 any 扩展名。)如果您编写密钥和same 文件的证书,PEM 格式支持但并非所有程序都支持,除了 .pem
.
所以终于可以回答你的问题了:-)
假设您的提供者列表(和类路径)中有 BC 提供者,类路径中有 bcpkix,并且 kv
中有一个 PrivateKey
对象:
import org.bouncycastle.openssl.PKCS8Generator;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMEncryptorBuilder;
import org.bouncycastle.util.io.pem.PemWriter;
// for the OpenSSL legacy form
JcaPEMWriter x = new JcaPEMWriter (new OutputStreamWriter(System.out)); // or whatever
x.writeObject(kv, new JcePEMEncryptorBuilder("DES-EDE3-CBC").build("password".toCharArray()) );
// can substitute AES-{128,192,256}-CBC if desired, for more see source
x.close(); // or flush to keep underlying writer/stream
// for the PKCS8 form
PemWriter y = new PemWriter (new OutputStreamWriter(System.out)); // or whatever
y.writeObject(new JcaPKCS8Generator (kv, new JceOpenSSLPKCS8EncryptorBuilder(
PKCS8Generator.DES3_CBC).setPasssword("password".toCharArray()).build() ) );
// or AES_{128,192,256}_CBC, others will use PBES1 which is deprecated
y.close(); // or flush to keep underlying writer/stream
如上所述,对于正常使用,您不需要使用密码来保护证书。但是,如果您想将一些证书存储在安全的地方,您可以在 password-protected 密钥库文件中进行(仅 java.security 代码,不需要 PemWriter)。
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, null);
Certificate cert = getX509Cert(); // load certificate
ks.setCertificateEntry("myCertAlias", cert);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(PATH + "newKeyStore.p12");
char[] password = PASSWORD_.toCharArray();
ks.store(fos, password);
} finally {
if (fos != null) {
fos.close();
}
}