一文詳解如何通過Java實現(xiàn)SSL交互功能
創(chuàng)建證書
因為要產(chǎn)生 key 信任庫,要求的密碼至少的 6位數(shù),所以密碼設(shè)為 123456
- 首先 生成 根密鑰和根證書
- 然后 生成 客戶端密鑰 和 客戶端證書,使用根證書對應(yīng)客戶端證書簽名,將根證書和簽名客戶端證書添加到密鑰庫中
- 最后 同上生成 服務(wù)端簽名證書,并將根證書和服務(wù)端證書添加到 密鑰庫中。
對應(yīng)的腳本如下所示:
#!/bin/bash # 加個前綴 PFX='file' # Password 這里只能使用單引號 PASS='123456' echo "---- 產(chǎn)生根相關(guān)文件 ----" echo "創(chuàng)建自簽名的根密鑰" openssl genrsa -out ${PFX}.rootkey.pem 2048 echo "生成根證書" openssl req -x509 -new -key ${PFX}.rootkey.pem -out ${PFX}.root.crt -subj "/C=CN/ST=GD/L=GZ/O=RootCA/OU=RootCA/CN=RootCA" echo "----- 產(chǎn)生客戶端相關(guān)文件 -----" echo "生成客戶端密鑰" openssl genrsa -out ${PFX}.clientkey.pem 2048 echo "生成客戶端證書請求文件,使用根證書進行簽發(fā)" openssl req -new -key ${PFX}.clientkey.pem -out ${PFX}.client.csr -subj "/C=CN/ST=GD/L=GZ/O=BMW/OU=Vehicle/CN=Vehicle1" echo "用根證書來簽發(fā)客戶端請求文件,生成客戶端證書client.crt" openssl x509 -req -in ${PFX}.client.csr -CA ${PFX}.root.crt -CAkey ${PFX}.rootkey.pem -CAcreateserial -days 3650 -out ${PFX}.client.crt echo "打包客戶端資料為pkcs12格式(client.pkcs12)" openssl pkcs12 -export -in ${PFX}.client.crt -inkey clientkey.pem -out ${PFX}.client.pkcs12 -passin "pass:$PASS" -passout "pass:$PASS" echo "生成信任客戶端的keystore,把根證書以及需要信任的客戶端的證書添加到這個keystore" keytool -importcert -alias ca -file ${PFX}.root.crt -keystore ${PFX}.clienttrust.jks -storepass "$PASS" <<EOF 是 EOF keytool -importcert -alias clientcert -file ${PFX}.client.crt -keystore ${PFX}.clienttrust.jks -storepass "$PASS" echo "--------產(chǎn)生服務(wù)端相關(guān)文件----" echo "生成服務(wù)器端的密匙" openssl genrsa -out ${PFX}.serverkey.pem 2048 echo "生成服務(wù)器端證書的請求文件。請求根證書來簽發(fā)" openssl req -new -key ${PFX}.serverkey.pem -out ${PFX}.server.csr -subj "/C=CN/ST=GD/L=GZ/O=BMW/OU=IT/CN=Broker" echo "用根證書來簽發(fā)服務(wù)器端請求文件,生成服務(wù)器端證書server.crt" openssl x509 -req -in ${PFX}.server.csr -CA ${PFX}.root.crt -CAkey ${PFX}.rootkey.pem -CAcreateserial -days 3650 -out ${PFX}.server.crt echo "打包服務(wù)器端資料為pkcs12格式(server.pkcs12 )" openssl pkcs12 -export -in ${PFX}.server.crt -inkey ${PFX}.serverkey.pem -out ${PFX}.server.pkcs12 -passin "pass:$PASS" -passout "pass:$PASS" echo "生成信任服務(wù)器端的keystore,把根證書以及需要信任的服務(wù)端的證書添加到這個keystore" keytool -importcert -alias ca -file ${PFX}.root.crt -keystore ${PFX}.servertrust.jks -storepass "$PASS" <<EOF 是 EOF keytool -importcert -alias servercert -file ${PFX}.server.crt -keystore ${PFX}.servertrust.jks -storepass "$PASS"
生成的文件目錄,如下圖所示:
#編碼
編寫 SSL Server
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocket; import java.net.Socket; public class SSLServer { private SSLServerSocket sslServerSocket; public static void main(String[] args) throws Exception { SSLServer server = new SSLServer(); server.initTestServer(); server.process(); } private SSLServerSocket initTestServer() throws Exception { // ssl-cert 放在 測試 resources 目錄下 String certDic = SSLServer.class.getClassLoader().getResource("ssl-cert").getPath(); sslServerSocket = initSocket(certDic + "/file.server.pkcs12", certDic + "/file.clienttrust.jks", "123456"); // 如果為 false 表示單向認證,否則為雙向認證 sslServerSocket.setNeedClientAuth(false); System.out.println("Server test initialted!"); return sslServerSocket; } private SSLServerSocket initSocket(String keyPath, String trustPath, String password) throws Exception { SSLContext context = SSLContext.getInstance("TLSv1.2"); char[] keystorePass = password.toCharArray(); context.init(SSLUtils.creatKey(keyPath, keystorePass).getKeyManagers(), SSLUtils.creatTrustJks(trustPath, keystorePass).getTrustManagers(), null); return (SSLServerSocket) context.getServerSocketFactory().createServerSocket(9999); } //服務(wù)端回復(fù)客戶端 private void process() throws Exception { String bye = "Hello, I am Server!"; while (true) { Socket socket = sslServerSocket.accept(); System.out.println("Received: " + SSLUtils.read(socket)); SSLUtils.write(bye, socket); } } }
編寫 SSL Client
import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; public class SSLClient { private SSLSocket sslSocket; public static void main(String[] args) throws Exception { SSLClient client = new SSLClient(); client.init(); client.process(); } private void init() throws Exception { // ssl-cert 放在 測試 resources 目錄下 String certDic = this.getClass().getClassLoader().getResource("ssl-cert").getPath(); initSocket(certDic + "/file.server.pkcs12", certDic + "/file.servertrust.jks", "123456"); System.out.println("Client initiated."); } private void initSocket(String keystorePath, String trustStorePath, String password) throws Exception { char[] keystorePass = password.toCharArray(); KeyManager[] keyManagers = null; KeyManagerFactory keyManagerFactory = SSLUtils.creatKey(keystorePath, keystorePass); if (keyManagerFactory != null) { keyManagers = keyManagerFactory.getKeyManagers(); } TrustManager[] trustManagers = null; TrustManagerFactory trustManagerFactory = SSLUtils.creatTrustJks(trustStorePath, keystorePass); if (trustManagerFactory != null) { trustManagers = trustManagerFactory.getTrustManagers(); } SSLContext context = SSLContext.getInstance("TLSv1.2"); context.init(keyManagers, trustManagers, null); String host = "127.0.0.1"; sslSocket = (SSLSocket) context.getSocketFactory().createSocket(host, 9999); } public void process() throws Exception { String hello = "Client Hello"; SSLUtils.write(hello, sslSocket); System.out.println(SSLUtils.read(sslSocket)); } }
通用編碼
import org.apache.commons.lang3.StringUtils; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.security.KeyStore; public class SSLUtils { public static void write(String message, Socket sslSocket) throws Exception { OutputStream out = sslSocket.getOutputStream(); byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8); out.write(messageBytes, 0, messageBytes.length); out.flush(); } public static String read(Socket sslSocket) throws Exception { InputStream in = sslSocket.getInputStream(); byte[] buffer = new byte[50]; in.read(buffer); return new String(buffer); } public static KeyManagerFactory creatKey(String keystorePath, char[] keystorePass) throws Exception { if (StringUtils.isEmpty(keystorePath)) { return null; } KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509"); kmf.init(loadKeyStore(keystorePath, keystorePass), keystorePass); return kmf; } public static TrustManagerFactory creatTrustJks(String trustClientKeystorePath, char[] keystorePass) throws Exception { if (StringUtils.isEmpty(trustClientKeystorePath)) { return null; } TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509"); tmf.init(loadKeyStore(trustClientKeystorePath, keystorePass)); return tmf; } private static KeyStore loadKeyStore(String keystorePath, char[] keystorePass) throws Exception { KeyStore serverKeyStore = KeyStore.getInstance(StringUtils.substringAfterLast(keystorePath, ".")); serverKeyStore.load(new FileInputStream(keystorePath), keystorePass); return serverKeyStore; } }
測試
啟動 SSLServer 和 SSLClient 可以得到的結(jié)果如下所示:
使用 wireshark 抓包如下所示:
這就是對應(yīng)的 SSL 連接
到此這篇關(guān)于一文詳解如何通過Java實現(xiàn)SSL交互功能的文章就介紹到這了,更多相關(guān)Java實現(xiàn)SSL交互內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用JavaFX工具構(gòu)建Reactive系統(tǒng)
這篇文章主要介紹了使用JavaFX構(gòu)建Reactive系統(tǒng),利用JavaFX工具集中的新的超棒特性來構(gòu)建響應(yīng)式的快速應(yīng)用程序,感興趣的小伙伴們可以參考一下2016-02-02SpringBoot使用spring.config.import多種方式導(dǎo)入配置文件
本文主要介紹了SpringBoot使用spring.config.import多種方式導(dǎo)入配置文件,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2022-05-05Java統(tǒng)計英文句子中出現(xiàn)次數(shù)最多的單詞并計算出現(xiàn)次數(shù)的方法
這篇文章主要介紹了Java統(tǒng)計英文句子中出現(xiàn)次數(shù)最多的單詞并計算出現(xiàn)次數(shù)的方法,涉及java針對英文句子的字符串遍歷、轉(zhuǎn)換、正則替換、計算等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01springboot+redis過期事件監(jiān)聽實現(xiàn)過程解析
這篇文章主要介紹了springboot+redis過期事件監(jiān)聽實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下2020-03-03