Java 支持多种证书和密钥存储格式。以下是几种常见的格式及其用途:
### 1. JKS (Java KeyStore)
- **描述**: JKS 是 Java 自带的一种密钥库格式,通常用于存储证书和私钥。
- **扩展名**: `.jks`
- **用途**: 存储服务器证书、客户端证书等。
- **读取方法**:
```java
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream("path/to/file.jks"), "password".toCharArray());
```
### 2. PKCS12 (Personal Information Exchange)
- **描述**: PKCS12 是一种跨平台的密钥和证书存储格式,它可以同时包含证书链和私钥。
- **扩展名**: `.p12`, `.pfx`
- **用途**: 通用密钥库格式,广泛用于各种系统。
- **读取方法**:
```java
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("path/to/file.p12"), "password".toCharArray());
```
### 3. PEM (Privacy Enhanced Mail)
- **描述**: PEM 是一种文本格式,用于存储公钥、私钥、证书等。
- **扩展名**: `.pem`, `.crt`, `.cer`, `.pub`, `.key`
- **用途**: 在互联网上传输证书和密钥的常见格式。
- **读取方法**:
```java
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new ByteArrayInputStream(pemToPkcs12("path/to/cert.pem", "path/to/private.pem")), "password".toCharArray());
```
### 4. DER (Distinguished Encoding Rules)
- **描述**: DER 是一种二进制格式,用于编码 ASN.1 数据结构,如 X.509 证书。
- **扩展名**: `.der`, `.cer`
- **用途**: 存储单个证书或公钥。
- **读取方法**:
```java
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = new FileInputStream("path/to/cert.der");
Certificate cert = cf.generateCertificate(in);
```
### 5. PKCS8 (Private Key Info)
- **描述**: PKCS8 是一种用于存储私钥的标准格式。
- **扩展名**: `.pk8`, `.p8`
- **用途**: 存储私钥。
- **读取方法**:
```java
KeyFactory kf = KeyFactory.getInstance("RSA");
InputStream in = new FileInputStream("path/to/private.pk8");
byte[] encodedKey = in.readAllBytes();
PrivateKey privKey = kf.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
```
### 6. X.509 (Certificate)
- **描述**: X.509 是一种用于数字证书的标准格式。
- **扩展名**: `.crt`, `.cer`, `.x509`
- **用途**: 存储单个证书。
- **读取方法**:
```java
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = new FileInputStream("path/to/cert.crt");
Certificate cert = cf.generateCertificate(in);
```
### 7. PKCS7 (Cryptographic Message Syntax)
- **描述**: PKCS7 是一种用于封装数字签名和加密数据的标准格式。
- **扩展名**: `.p7b`, `.p7s`
- **用途**: 存储签名或加密的数据,包括证书链。
- **读取方法**:
```java
CMSProcessable content = new CMSProcessableByteArray(new byte[0]);
CMSSignedData signedData = new CMSSignedData(content, new CMSProcessableInputStream(new FileInputStream("path/to/file.p7b")));
```
### 读取 PEM 文件为 PKCS12
对于 PEM 文件,您需要先将其转换为 PKCS12 格式,然后再加载到 Java KeyStore 中。这里有一个简单的示例,说明如何将 PEM 文件转换为 PKCS12 并读取到 Java KeyStore 中:
```java
import java.io.*;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS12KeyStore;
public class PEMToPKCS12 {
public static void main(String[] args) {
String certPemPath = "path/to/cert.pem";
String keyPemPath = "path/to/private.pem";
String outputP12Path = "path/to/output.p12";
try {
// Read certificate from PEM file
X509Certificate cert = readCertificateFromPem(certPemPath);
// Read private key from PEM file
PrivateKey privateKey = readPrivateKeyFromPem(keyPemPath);
// Create PKCS12 KeyStore
KeyStore keyStore = createPkcs12KeyStore(cert, privateKey, outputP12Path);
// Load PKCS12 KeyStore into Java KeyStore
KeyStore jksKeyStore = loadPkcs12IntoJavaKeyStore(keyStore, "path/to/javaKeyStore.jks");
System.out.println("Conversion completed successfully.");
} catch (Exception e) {
e.printStackTrace();
}
}
private static X509Certificate readCertificateFromPem(String path) throws IOException, CertificateException {
try (PEMReader reader = new PEMReader(new FileReader(path), new JcaPEMKeyConverter())) {
Object obj = reader.readObject();
if (obj instanceof X509CertificateHolder) {
return new JcaX509CertificateConverter().getCertificate((X509CertificateHolder) obj);
}
throw new IllegalArgumentException("Expected a certificate but got: " + obj.getClass().getName());
}
}
private static PrivateKey readPrivateKeyFromPem(String path) throws IOException, NoSuchAlgorithmException {
try (PEMReader reader = new PEMReader(new FileReader(path), new JcaPEMKeyConverter())) {
Object obj = reader.readObject();
if (obj instanceof PrivateKey) {
return (PrivateKey) obj;
}
throw new IllegalArgumentException("Expected a private key but got: " + obj.getClass().getName());
}
}
private static KeyStore createPkcs12KeyStore(X509Certificate cert, PrivateKey privateKey, String outputP12Path) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore keyStore = new JceOpenSSLPKCS12KeyStore();
keyStore.load(null, "password".toCharArray());
keyStore.setKeyEntry("alias", privateKey, "password".toCharArray(), new Certificate[]{cert});
try (FileOutputStream fos = new FileOutputStream(outputP12Path)) {
keyStore.store(fos, "password".toCharArray());
}
return keyStore;
}
private static KeyStore loadPkcs12IntoJavaKeyStore(KeyStore p12KeyStore, String jksPath) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore jksKeyStore = KeyStore.getInstance("JKS");
jksKeyStore.load(null); // Initialize empty JKS KeyStore
Enumeration<String> aliases = p12KeyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (p12KeyStore.isKeyEntry(alias)) {
PrivateKey privateKey = (PrivateKey) p12KeyStore.getKey(alias, "password".toCharArray());
Certificate[] chain = p12KeyStore.getCertificateChain(alias);
jksKeyStore.setKeyEntry(alias, privateKey, "password".toCharArray(), chain);
}
}
try (FileOutputStream fos = new FileOutputStream(jksPath)) {
jksKeyStore.store(fos, "password".toCharArray());
}
return jksKeyStore;
}
}
```
这个示例展示了如何读取 PEM 文件中的证书和私钥,然后将它们转换为 PKCS12 格式并最终存储到 JKS 文件中。请确保您已经添加了 BouncyCastle 库到您的项目中。如果使用 Maven,可以添加以下依赖:
```xml
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
```
请注意,此示例代码假设 PEM 文件中只包含一个证书和一个私钥。在实际应用中,您可能需要添加额外的错误检查和异常处理来确保程序的健壮性和安全性。