//客户端代码如下
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,其他版本应该差别不大。