有时别人发来的密钥或证书文件无法读取 , 也可使用openssl确认一下,如果openssl能读出来 , 那大概率是自己程序有问题,如果openssl读不出来,那大概率是别人发的文件有问题,如下:
# 查看pkcs1 rsa私钥openssl rsa -in rsa_private_key_pkcs1.key -text -noout# 查看pkcs1 rsa公钥openssl rsa -RSAPublicKey_in -in rsa_public_key_pkcs1.key -text -noout# 查看x.509证书openssl x509 -in cert.crt -text -nocert# 查看pkcs12密钥库文件openssl pkcs12 -in keystore.p12keytool -v -list -storetype pkcs12 -keystore keystore.p12
由于密钥、证书、密钥库文件,其实都是使用ASN.1语法描述的,所以它们都能按ASN.1语法解析出来,如下:
openssl asn1parse -i -inform pem -in cert.crt
证书格式转换某些情况下,我们需要在不同格式的密钥或证书文件之间转换,也可使用openssl命令来完成 。密钥格式转换 , 如下:
# rsa公钥转换为X509公钥openssl rsa -RSAPublicKey_in -in rsa_public_key_pkcs1.key -pubout -out public_key_x509.key# rsa私钥转换为PKCS8格式openssl pkcs8 -topk8 -inform PEM -in rsa_private_key_pkcs1.key -outform PEM -nocrypt -out private_key_pkcs8.key# pkcs8转rsa私钥openssl pkcs8 -inform PEM -nocrypt -in private_key_pkcs8.key -traditional -out rsa_private_key_pkcs1.key
证书格式转换 , 如下:
# 证书DER转PEMopenssl x509 -inform der -in cert.der -outform pem -out cert.pem -noout# x509证书转pkcs7证书openssl crl2pkcs7 -nocrl -certfile cert.crt -out cert.p7b# 查看pkcs7证书openssl pkcs7 -print_certs -in cert.p7b -noout
由于密钥库中包含证书与私钥,故可以从密钥库文件中提取出证书与私钥,如下:
# 从pkcs12密钥库中提取证书openssl pkcs12 -in keystore.p12 -clcerts -nokeys -out cert.crt# 从pkcs12密钥库中提取私钥openssl pkcs12 -in keystore.p12 -nocerts -nodes -out private_key.key# pkcs12转jkskeytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -srcalias demo -destkeystore keystore.jks -deststoretype jks -deststorepass 123456 -destalias demo# 从jks中提取证书keytool -export -alias demo -keystore keystore.jks -file cert.crt
读取密钥或证书文件使用JCA来读取密钥或证书文件,也是非常方便的 。
PEM转DER若要将PEM格式文件转换为DER , 只需要把---BEGIN XXX---
与---END XXX---
去掉,然后使用Base64解码即可,如下:
private static byte[] pemFileToDerBytes(String pemFilePath) throws IOException {InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(pemFilePath);String pemStr = StreamUtils.copyToString(is, StandardCharsets.UTF_8);//去掉---BEGIN XXX---与---END XXX---pemStr = pemStr.replaceAll("---+[^-]+---+", "").replaceAll("\\s+", "");//base64解码为DER二进制内容return Base64.getDecoder().decode(pemStr);}
读取PKCS8私钥在JCA中,使用PKCS8EncodedKeySpec解析PKCS8私钥文件 , 如下:
public static void testPkcs8PrivateKeyFile() {byte[] derBytes = pemFileToDerBytes("cert/private_key_pkcs8.key");PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(derBytes);RSAPrivateCrtKey rsaPrivateCrtKey = (RSAPrivateCrtKey)KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);BigInteger n = rsaPrivateCrtKey.getModulus();BigInteger e = rsaPrivateCrtKey.getPublicExponent();BigInteger d = rsaPrivateCrtKey.getPrivateExponent();System.out.printf(" n: %X \n e: %X \n d: %X \n", n, e, d);BigInteger plain = BigInteger.valueOf(new Random().nextInt(1000000000));// RSA加密long t1 = System.nanoTime();BigInteger secret = plain.modPow(e, n);long t2 = System.nanoTime();// RSA解密BigInteger plain2 = secret.modPow(d, n);long t3 = System.nanoTime();System.out.printf(" plain: %d \n plain2: %d \n", plain, plain2);System.out.printf("enc time: %d \n", (t2 - t1));System.out.printf("dec time: %d \n", (t3 - t2));}
读取X.509公钥在JCA中,使用X509EncodedKeySpec解析X.509公钥文件,如下:
public static void testX509PublicKeyFile() {byte[] derBytes = pemFileToDerBytes("cert/public_key_x509.key");X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(derBytes);RSAPublicKey rsaPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec);BigInteger e = rsaPublicKey.getPublicExponent();BigInteger n = rsaPublicKey.getModulus();System.out.printf(" e: %X \n n: %X \n", e, n);}
读取X.509证书读取X.509证书文件,可使用CertificateFactory类,如下:
public static void testX509CertFile() {byte[] derBytes = pemFileToDerBytes("cert/cert.crt");Collection<? extends Certificate> certificates = CertificateFactory.getInstance("X.509").generateCertificates(new ByteArrayInputStream(derBytes));for(Certificate certificate : certificates){X509Certificate x509Certificate = (X509Certificate)certificate;System.out.printf("SubjectDN: %s \n", x509Certificate.getSubjectDN());System.out.printf("IssuerDN: %s \n", x509Certificate.getIssuerDN());System.out.printf("SigAlgName: %s \n", x509Certificate.getSigAlgName());System.out.printf("Signature: %s \n", Hex.encodeHexString(x509Certificate.getSignature()));System.out.printf("PublicKey: %s \n", x509Certificate.getPublicKey());}}
推荐阅读
- [WPF] 抄抄超强的苹果官网滚动文字特效实现
- Java函数式编程:一、函数式接口,lambda表达式和方法引用
- 不妨试试更快更小更灵活Java开发框架Solon
- 11 微服务架构学习与思考:开源 API 网关02-以 Java 为基础的 API 网关详细介绍
- java 新特性之 Stream API
- java 入土--集合详解
- 4 Java I/O:AIO和NIO中的Selector
- 通过 Github Action 实现定时推送天气预报
- 3 Java I/O:NIO中的Buffer
- 提高工作效率的神器:基于前端表格实现Chrome Excel扩展插件