读取PKCS12密钥库文件读取PKCS12规范的密钥库文件,可使用KeyStore类,如下:
public static void testPkcs12File() {KeyStore keyStore = KeyStore.getInstance("PKCS12");InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("cert/keystore.p12");char[] password = "123456".toCharArray();keyStore.load(is, password);//获取证书X509Certificate x509Certificate = (X509Certificate)keyStore.getCertificate("demo");System.out.println("X509Certificate: ");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());//获取私钥Key key = keyStore.getKey("demo", password);System.out.printf("PrivateKey: %s \n", key);}
如果要读取.jks
文件,只需要将KeyStore.getInstance("PKCS12")
中的PKCS12更换为JKS即可 , 其它部分保持不变,不过由于JKS是java专有格式 , 目前java也不推荐使用了,所以能不用的话,就尽量不要用了 。
常见问题证书信任问题证书的绝大多数应用场景是Https协议 , 但在访问https接口时,有时会由于证书信任问题导致https握手失败 , 主要有以下2点原因:
- 有些公司会自建CA,使用自签证书,如早期的12306,而jdk只信任它预置的根证书,所以https握手时这种证书会认证失败 。
- 新成立的根CA机构证书 , 没预置在旧的jdk里面,导致这些CA机构签发的证书不被信任 。
# 将cert.crt导入jdk预置密钥库文件 , 密钥库文件密码默认是changeitsudo keytool -importcert -file cert.crt -alias demo -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit# 查看密钥库文件,检查是否导入成功keytool -list -v -alias demo -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
2. 以编码的方式信任证书以jdk自带的https sdk为例,可在代码中手动将问题证书添加到信任列表中,如下:public String testReqHttpsTrustCert() throws Exception {// 读取jdk预置证书KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());try(InputStream ksIs = new FileInputStream(System.getProperty("java.home") + "/lib/security/cacerts")) {keyStore.load(ksIs, "changeit".toCharArray());}// 读取证书文件CertificateFactory cf = CertificateFactory.getInstance("X.509");try(InputStream certIs = this.getClass().getResourceAsStream("/cert/cert.crt")) {Certificate c = cf.generateCertificate(certIs);keyStore.setCertificateEntry("demo", c);}// 生成信任管理器TrustManagerFactory tmFact = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());tmFact.init(keyStore);// 生成SSLSocketFactorySSLContext sslContext = SSLContext.getInstance("TLSv1.2");sslContext.init(null, tmFact.getTrustManagers(), new SecureRandom());SSLSocketFactory ssf = sslContext.getSocketFactory();// 发送https请求URL url = new URL("https://www.demo.com/user/list");HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();connection.setHostnameVerifier((hostname, session) -> hostname.endsWith("demo.com"));connection.setSSLSocketFactory(ssf);String result;try(InputStream inputStream = connection.getInputStream()){result = IOUtils.toString(inputStream, StandardCharsets.UTF_8);}connection.disconnect();return result;}
注:虽然2种方法都可以解决问题,但第1种方法使得java程序对环境形成了依赖 , 一旦部署环境发生变化,java程序可能就报错了,因此更推荐使用第2种方法 。总结到这里,JCA相关类的使用就介绍完了,如下表格中总结了JCA的常用类:

文章插图
本篇花了近一周时间整理 , 内容较多,对这块不太熟悉的同学,可以先关注收藏起来当示例手册,待需要时再参阅即可 。
【Java实现7种常见密码算法】
推荐阅读
- [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扩展插件