使用openssl生成Java可以读取的密钥和自签名证书
密钥生成
私钥生成
shell
openssl genrsa -out rsa_private.pem 2048
- genrsa:是openssl生成RSA私钥的标准命令
- -out:t 指定输出的文件
- 2048 指rsa算法长度,可以替换为其他长度,例如1024。
PKCS#8标准转换
需要注意的是openssl默认生成的是PKCS#1标准的密钥,存储格式是PEM。Java标准库默认是不支持PKCS#1标准,因此需要转换为PKCS#8标准。
shell
openssl pkcs8 -topk8 -inform PEM -in rsa_private.pem -outform PEM -nocrypt > rsa_private_pkcs8.pem
- pkcs8:是openssl转换pcks8的标准命令
- -topk8:通常,输入时需要 PKCS#8 私钥,并且将写入传统格式的私钥。使用 -topk8 选项,情况正好相反:它读取传统格式的私钥并写入 PKCS#8 格式的密钥。
- -inform:输入key的格式,可以是PEM,也可以是DER
- -in:输入文件
- -outform:输出格式,可以是PEM,也可以是DER
- -nocrypt:对密钥不加密 PEM和DER是密钥的两种编码方式,PEM格式是以-----BEGIN PRIVATE KEY-----或-----BEGIN PUBLIC KEY-----开头,以-----END PRIVATE KEY-----或者-----END PUBLIC KEY-----结尾,中间是经过Base64编码后的内容,每64字节做一次换行。 DER格式是直接密钥的二进制编码。 如果需要从PKCS#8转换为PKCS#1格式可以使用如下命令
shell
openssl rsa -in rsa_private_pkcs8.pem -out rsa_private.pem
导出公钥
shell
-- 导出pem格式
openssl rsa -in rsa_private.pem -pubout -outform PEM -out rsa_public.pem
-- 导出DER格式
openssl rsa -in rsa_private.pem -pubout -outform DER -out rsa_public.der
标准转换方法与私钥转换一致
自签名证书生成
shell
# 使用自有私钥生成证书
openssl req -new -x509 -days 365 -key rsa_private.key -out cert.crt
- -new:是生成证书请求
- -x509: 生成证书格式
- -key:指定私钥,这里pkcs#1或者PKCS#8都是可以的
- -out:输出证书文件
Java读取密钥文件
读取PEM格式私钥
Java
public static PrivateKey readPemPrivateKey(String filename) throws Exception {
// 读取文件
String key = new String(Files.readAllBytes(Paths.get(filename)), Charset.defaultCharset());
String privateKeyPEM = key
.replace("-----BEGIN PRIVATE KEY-----", "")
.replaceAll("\n", "")
.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(pkcs8);
}
读取PEM格式公钥
Java
public static PublicKey readPemPublicKey(String filename) throws Exception {
String key = new String(Files.readAllBytes(Paths.get(filename)), Charset.defaultCharset());
String publicKeyPEM = key
.replace("-----BEGIN PUBLIC KEY-----", "")
.replaceAll(System.lineSeparator(), "")
.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
读取DER格式私钥
Java
public static PrivateKey readDerPrivateKey(String filename) throws Exception {
// 读取文件
byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(pkcs8);
// 转换编码
String data = Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println(data);
return privateKey;
}
读取DER格式公钥
Java
public static PrivateKey readDerPrivateKey(String filename) throws Exception {
// 读取文件
byte[] keyBytes = Files.readAllBytes(Paths.get(filename));
PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(pkcs8);
// 转换编码
String data = Base64.getEncoder().encodeToString(privateKey.getEncoded());
System.out.println(data);
return privateKey;
}
Java读取X509证书
Java
public static X509Certificate loadCert(String filename) throws Exception {
FileInputStream in = new FileInputStream(filename);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate validateCert = (X509Certificate) cf.generateCertificate(in);
return validateCert;
}
使用加载的密钥完成加密和解密
Java
public static void doEncryptAndDecrypt(PublicKey publicKey, PrivateKey privateKey, String msg) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
String out = Base64.getEncoder().encodeToString(cipher.doFinal(msg.getBytes(StandardCharsets.UTF_8)));
// 解密
cipher.init(Cipher.DECRYPT_MODE, privateKey);
out = new String(cipher.doFinal(Base64.getDecoder().decode(out)));
if (msg.equals(out)) {
System.out.println("加密、解密OK");
}
}
https://alvinkwok.cn/2021/06/11/security/使用openssl生成Java可以读取的密钥和自签名证书/