//客戶端代碼如下
1 import java.io.*; 2 import java.net.InetSocketAddress; 3 import java.net.Socket; 4 5 import javax.net.ssl.SSLSocket; 6 import javax.net.ssl.SSLSocketFactory; 7 8 public class SslClient { 9 private SSLSocket s; 10 private DataOutputStream out; 11 private DataInputStream in; 12 13 public SslClient() throws IOException { 14 } 15 16 public void sendMessage(Socket s, String msg) { 17 try { 18 19 out = new DataOutputStream(s.getOutputStream()); 20 String jsonString = msg; 21 out.write(jsonString.getBytes()); 22 } catch (IOException e) { 23 } 24 25 } 26 27 public String receiveMessage(Socket s) { 28 try { 29 30 in = new DataInputStream(s.getInputStream()); 31 BufferedReader socketIn = new BufferedReader(new InputStreamReader(in));// 接受到 32 String res = socketIn.readLine(); 33 if (res == null || res.equals("null")) { 34 res = ""; 35 } 36 return res; 37 } catch (Exception e) { 38 return ""; 39 } 40 41 } 42 43 public String talk(String ip, int port, String trustStore, String trustStorePassword, int socketOutTime, String msg) 44 throws Exception { 45 try { 46 int connectTimeout = socketOutTime * 1000;//設置超時時間 47 System.setProperty("javax.net.ssl.trustStore", trustStore);// 設置可信任的密鑰倉庫 48 System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword); // 設置可信任的密鑰倉庫的密碼 49 SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault();// 利用工廠來創建SSLSocket安全套接字 50 s = (SSLSocket) sslsf.createSocket(); 51 s.connect(new InetSocketAddress(ip, port), connectTimeout); 52 s.startHandshake(); 53 54 System.out.println("向服務器發送:" + msg); 55 sendMessage(s, msg); 56 // 發字符串 57 String result = receiveMessage(s); 58 System.out.println("服務器返回:" + result); 59 out.close(); 60 in.close(); 61 if (s != null) { 62 s.close(); 63 } 64 return result; 65 66 } catch (Exception e) { 67 e.printStackTrace(); 68 out.close(); 69 in.close(); 70 if (s != null) { 71 s.close(); 72 } 73 return ""; 74 } 75 76 } 77 78 public static void main(String[] args) throws Exception { 79 SslClient c = new SslClient(); 80 String responseMsg = c.talk("xxx.xxx.xxx.xxx", 8089, "D:\\xxxx\\shfqtruststore.jks", "123456", 5, "test\n"); 81 System.out.println(responseMsg); 82 83 } 84 85 }
//服務端代碼如下 參考 https://blog.csdn.net/spdxspdx/article/details/84230574
1 import java.io.BufferedReader; 2 import java.io.DataOutputStream; 3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.security.KeyManagementException; 7 import java.security.KeyStore; 8 import java.security.KeyStoreException; 9 import java.security.NoSuchAlgorithmException; 10 import java.security.UnrecoverableKeyException; 11 import javax.net.ssl.KeyManagerFactory; 12 import javax.net.ssl.SSLContext; 13 import javax.net.ssl.SSLServerSocket; 14 import javax.net.ssl.SSLServerSocketFactory; 15 import javax.net.ssl.SSLSocket; 16 17 public class SSLServer { 18 public static void startSSLServer() throws IOException, java.security.cert.CertificateException { 19 int port = 8089;// 監聽端口 20 String keyFile = "D:\\xxxx\\shfqkeystore.jks";// 密鑰庫文件 21 String keyFilePass = "123456";// 密鑰庫的密碼 22 String keyPass = "123456";// 密鑰別名的密碼 23 SSLServerSocket sslsocket = null;// 安全連接套接字 24 KeyStore ks;// 密鑰庫 25 KeyManagerFactory kmf;// 密鑰管理工廠 26 SSLContext sslc = null;// 安全連接方式 27 // 初始化安全連接的密鑰 28 try { 29 ks = KeyStore.getInstance("JKS"); 30 ks.load(new FileInputStream(keyFile), keyFilePass.toCharArray()); 31 kmf = KeyManagerFactory.getInstance("SunX509"); 32 kmf.init(ks, keyPass.toCharArray()); 33 sslc = SSLContext.getInstance("SSLv3"); 34 sslc.init(kmf.getKeyManagers(), null, null); 35 } catch (KeyManagementException ex) { 36 ex.printStackTrace(); 37 } catch (UnrecoverableKeyException ex) { 38 ex.printStackTrace(); 39 } catch (KeyStoreException ex) { 40 ex.printStackTrace(); 41 } catch (NoSuchAlgorithmException ex) { 42 ex.printStackTrace(); 43 } 44 // 用安全連接的工廠來創建安全連接套接字 45 SSLServerSocketFactory sslssf = sslc.getServerSocketFactory(); 46 sslsocket = (SSLServerSocket) sslssf.createServerSocket(port);// 創建並進入監聽 47 System.out.println("Listening..."); 48 while (true) { 49 SSLSocket ssocket = (SSLSocket) sslsocket.accept();// 接受客戶端的連接 50 System.out.println("Server Connection ....."); 51 // 以下代碼同socket通訊實例中的代碼 52 BufferedReader socketIn = new BufferedReader(new InputStreamReader(ssocket.getInputStream())); 53 DataOutputStream socketOut = new DataOutputStream(ssocket.getOutputStream()); 54 String s = null; 55 System.out.println("Please wait client 's message.."); 56 s = socketIn.readLine(); 57 System.out.println("Client Message: " + s); 58 59 60 s = "接收成功"; 61 System.out.print("Server Message: " + s); 62 socketOut.write(s.getBytes()); 63 ssocket.close(); 64 } 65 66 } 67 68 public static void main(String[] args) { 69 try { 70 startSSLServer(); 71 } catch (Exception e) { 72 e.printStackTrace(); 73 } 74 } 75 }
其中用到的相關證書,可以參照 https://blog.csdn.net/shfqbluestone/article/details/21242323 ,文章中1—6來進行生成。
為防止上述文章鏈接失效,特在下方復制留存。
1 SSL單向認證概念
當客戶端(服務請求方)向服務端(服務提供方)發起請求時,服務器端需要向客戶端提供認證。服務端需要生成一個keystore和一個服務器密鑰對兒(公鑰和私鑰),客戶端需要生成一個truststore,然后導入服務端的公鑰證書。
2 keystore以及服務器密鑰對兒的生成
keytool -genkeypair -alias certificatekey -keyalg RSA -validity 365 -keystore shfqkeystore.jks 這條命令會在生成keystore后接着生成一個密鑰對兒。RSA是非對稱密鑰算法,也可以改為 keytool支持的其他密鑰算法,365代表的是證書的有效期,可以自己指定,shfqkeystore.jks是keystroe的名稱,也可以自己指定。打開cmd命令行,輸入: keytool -genkeypair -alias certificatekey -keyalg RSA -validity 365 -keystore shfqkeystore.jks 會提示輸入keystore的密碼,接着會提示輸入名字等信息,如下圖:
補充:輸入<certificatekey>的主密碼,是指生成服務端證書的私鑰。服務端私鑰如果和keystore的相同的話,直接按回車。建議直接按回車,即服務端私鑰和keystore的密碼相同。如果兩者的密碼不相同的話在服務端tomcat server.xml中配置完畢以后啟動tomcat會報一個UnrecoverableKeyException: Cannot recover key的異常(后面會介紹服務端 tomcat server.xml 的配置的)。
keytool會把生成的keystore文件默認保存到C:\Users\lenovo路徑下(用戶目錄下的計算機名稱下)接下來生成的所有文件也都保存到此處。
3 驗證新生成的keystor文件以及證書信息
可以執行下面的命令:
keytool -list -v -keystore shfqkeystore.jks
會顯示出以下信息,如圖:
4 導出公鑰證書
下面的命令可以導出自簽公鑰證書:
keytool -export -alias certificatekey -keystore shfqkeystore.jks -rfc -file shfqcert.cer
其中shfqcert.cer是導出證書的名稱,可以隨便起個名字,shfqkeystore.jks是2中生成的keystore 文件。
執行上面的命令會要求輸入shfqkeystore的密碼,會顯示以下信息,如下圖。
5 Truststore的生成以及公鑰證書的導入
把4生成的公鑰證書shfqcert.cer導入到truststore中
Keytool -import -alias certificatekey -file shfqcert.cer -keystore
shfqtruststore.jks
shfqcert.cer是4導出的公鑰證書,shfqtruststore.jks可以隨便起,是生成的truststore的文件名。這條命令首先會生成一個truststore,然后導入4生成的公鑰證書shfqcert.cer。
執行keytool -import -alias certificatekey -file shfqcert.cer -keystore shfqtruststore.jks后,首先會提示輸入truststore的密碼,如下圖:
6 驗證5生成的truststore文件
keytool -list -v -keystore shfqtruststore.jks
shfqtruststore.jks是5生成的truststore文件名。
到此為止,keystore、truststore、公鑰證書都已生成完畢。
博主運行上述例子時所用JDK版本為 1.7,其他版本應該差別不大。