• SSL的TCP通信


    一切尽在代码中,额。自己測试的小样例。感觉非常实用,做个记录。

    server端:

    </pre><pre name="code" class="java">package com.mpc.test.clazz;
    
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.security.KeyStore;
    import java.security.SecureRandom;
    
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLServerSocket;
    import javax.net.ssl.SSLServerSocketFactory;
    import javax.net.ssl.TrustManagerFactory;
    
    public class SSLTest {
    	public static void main(String[] args) throws Exception {
    
    		String key = "d:/keys/m.jks";// 定义server端要使用的证书
    		String trust = "d:keys/trustclient.jks";// 定义server端要信任的证书
    		/* 个人感觉。上面这两个属性在使用的时候全然能够定义为properties文件或者xml文件来使用 */
    
    		KeyStore keyStore = KeyStore.getInstance("JKS");// 定义一个KeyStore用来存储server的秘钥文件
    		keyStore.load(new FileInputStream(key), "123456".toCharArray());// 载入server端使用的证书,当然要输入要打开加密文件的password了
    		KeyStore trustStore = KeyStore.getInstance("JKS");// 定义一个KeyStore用来存储server信任的证书文件
    		trustStore.load(new FileInputStream(trust), "123456".toCharArray());// 载入server端信任的证书文件,当然也要输入password的
    		/** 额,事实上keyStore和truststore都是Keystore的大家都看到了,就是保存的秘钥文件不同而已了 */
    
    		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
    				.getDefaultAlgorithm());/*
    										 * 创建一个server的秘钥管理工厂,KeyManagerFactory.
    										 * getDefaultAlgorithm
    										 * ()是指定的默认的算法,记得是RSA··输出一下就OK了
    										 */
    		kmf.init(keyStore, "mipengcheng".toCharArray());/*
    														 * 初始化。在初始化的时候须要自定秘钥的password,
    														 * 这个在创建的时候指定的
    														 */
    		TrustManagerFactory tmf = TrustManagerFactory
    				.getInstance(TrustManagerFactory.getDefaultAlgorithm());/*
    																		 * 创建一个server信任证书的管理工厂
    																		 * ,
    																		 * 相同指定了RSA的算法
    																		 */
    		tmf.init(trustStore);/* 初始化。因为信任的是证书,不是秘钥,所以不用指定password什么的了 */
    
    		SSLContext sslc = SSLContext.getInstance("TLSv1");/*
    														 * 获得TLSv1版本号的SSLContext,
    														 * 还有个ssl3的
    														 */
    		sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),
    				new SecureRandom());/* 用两个工厂来初始化SSLContext */
    
    		SSLServerSocketFactory sllFactory = sslc.getServerSocketFactory();/* 获得server端口工厂 */
    		SSLServerSocket serverSocket = (SSLServerSocket) sllFactory
    				.createServerSocket(9999);/* 创建serverSocket,在9999端口监听 */
    		/* 这句非常重要,是要开启客户端的安全证书验证滴 */
    		serverSocket.setNeedClientAuth(true);
    		System.out.println("server已经启动了........");
    		while (true) {
    			final Socket socket = serverSocket.accept();/*
    														 * accept用来堵塞监听线程,訪问一个处理一个
    														 */
    			System.out.println("接收到" + socket.getRemoteSocketAddress() + "的请求");
    			new Thread(new MyThread(socket)).start();/* 创建新的线程用来处理接受到的socket */
    		}
    	}
    
    	static class MyThread implements Runnable {
    		private Socket socket;
    
    		public MyThread(Socket socket) {
    			super();
    			this.socket = socket;
    		}
    
    		public void run() {
    			/** 这里是对接受的请求的处理,没什么东西了。

    */ try { System.out.println("server開始读取数据====="); BufferedReader read = new BufferedReader(new InputStreamReader( socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); String message; while (null != (message = read.readLine())) { if (message.equals("end")) { out.println("agree"); break; } else { System.out.println("结果" + message); out.println("server收到消息"); } } System.out.println("server跳出循环"); Thread.sleep(10000); out.close(); read.close(); } catch (Exception e) { e.printStackTrace(); } } } }


    client:

    package com.mpc.test.clazz;
    
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.security.KeyStore;
    import java.security.SecureRandom;
    
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManagerFactory;
    
    public class SSLTestClient {
    	public static void main(String[] args) throws Exception {
    		/* 从这里開始======== */
    		String key = "d:/keys/trustm.jks";
    		String client = "d:/keys/client.jks";
    		KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    		keyStore.load(new FileInputStream(key), "123456".toCharArray());
    		KeyStore clientStore = KeyStore.getInstance(KeyStore.getDefaultType());
    		clientStore.load(new FileInputStream(client), "123456".toCharArray());
    		TrustManagerFactory tmf = TrustManagerFactory
    				.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    		tmf.init(keyStore);
    		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
    				.getDefaultAlgorithm());
    		kmf.init(clientStore, "123456".toCharArray());
    		SSLContext sslc = SSLContext.getInstance("TLSv1");
    		sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),
    				new SecureRandom());
    		/* 到这里结束======== */
    		/** 上面凝视包围的内容,和server端的一样。仅仅是这里变成了客户端要使用的秘钥,客户端要信任的证书 */
    
    		SSLSocketFactory sslSocketFactory = sslc.getSocketFactory();/* 获得socketFactory */
    		SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(
    				"127.0.0.1", 9999);/* 訪问本机的9999端口 */
    		socket.setKeepAlive(true);/*长连接···*/
    		
    		/*以下都是消息的处理,没什么东西了*/
    		BufferedReader read = new BufferedReader(new InputStreamReader(
    				socket.getInputStream()));
    		PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
    		out.println("cilent message");
    		String message;
    		int i = 0;
    		while (null != (message = read.readLine())) {
    			System.out.println(message);
    			i++;
    			if (message.equals("agree")) {
    				break;
    			} else {
    
    			}
    			Thread.sleep(1000);
    			out.println("cilent message");
    			if (i == 5) {
    				out.println("end");
    			}
    
    		}
    		socket.close();
    		out.close();
    		read.close();
    		System.out.println("客户端跳出了while循环");
    	}
    }
    


    測试结果:

    1.server端:


    2.client:


    在项目中使用到的证书


    关于证书的创建。这里以server端的秘钥的创建和server要给client使用的信任证书的创建为例:

    使用jdk自带的keytool来创建。

    D:keys>keytool -genkeypair -alias mkey -keyalg RSA -validity 7 -keystore m.jks
    输入密钥库口令:
    再次输入新口令:
    您的名字与姓氏是什么?

    [Unknown]: mi 您的组织单位名称是什么? [Unknown]: my 您的组织名称是什么? [Unknown]: isis 您所在的城市或区域名称是什么? [Unknown]: city 您所在的省/市/自治区名称是什么? [Unknown]: state 该单位的双字母国家/地区代码是什么? [Unknown]: china CN=mi, OU=my, O=isis, L=city, ST=state, C=china是否正确?

    [否]: y 输入 <mkey> 的密钥口令 (假设和密钥库口令同样, 按回车): 再次输入新口令:


    使用第一行的命令来生成证书。指定名字为m.jks。然后依据提示就能够创建server端的秘钥了。


    D:keys>keytool -export -alias mkey -keystore m.jks -rfc -file rootca.cer
    输入密钥库口令:
    存储在文件 <rootca.cer> 中的证书


    这条命令导出了server端的证书文件,用来供其它client验证server。可是java貌似不用这个,所以在把它导成jks的。


    D:keys>keytool -import -alias mcer -file rootca.cer -keystore trustm.jks
    输入密钥库口令:
    再次输入新口令:
    全部者: CN=mi, OU=my, O=isis, L=city, ST=state, C=china
    公布者: CN=mi, OU=my, O=isis, L=city, ST=state, C=china
    序列号: 2ed10bf7
    有效期開始日期: Wed Jan 27 16:24:15 CST 2016, 截止日期: Wed Feb 03 16:24:15 CST
    2016
    证书指纹:
             MD5: 44:3A:CB:4D:B3:BE:FF:63:67:61:0C:19:97:DA:02:09
             SHA1: 5E:D2:48:8F:37:29:00:94:99:AB:A1:93:B0:1F:2E:65:74:39:06:50
             SHA256: 98:B3:62:6F:3A:77:F5:9E:BA:29:A8:55:16:E7:47:92:79:ED:45:26:E9:
    7F:A8:ED:88:82:89:AA:FD:4C:3A:35
             签名算法名称: SHA256withRSA
             版本号: 3
    
    扩展:
    
    #1: ObjectId: 2.5.29.14 Criticality=false
    SubjectKeyIdentifier [
    KeyIdentifier [
    0000: B0 51 15 9A E5 2F 8A 29   D2 4E 15 AE 0B 86 83 13  .Q.../.).N......
    0010: EE BC 7B E2                                        ....
    ]
    ]
    
    是否信任此证书?

    [否]: y 证书已加入到密钥库中


    这条命令就把server端给client验证的证书的jks文件生成了。


    client的相关秘钥,证书的生成也是一样的。


    本人才疏学浅,仅仅是想折腾折腾。学习学习,假设有什么不正确的,不足的地方,还请大家包涵。不吝赐教!


  • 相关阅读:
    关于Application.Lock和Lock(obj)
    ViewState保存在服务器,可定时清空
    firefox选中flash会出现虚线框
    png for ie6背景透明
    用SQL Server Profiler看sql效率时,发现会隔几秒自动执行一些东西
    ServerXMLHTTP的setTimeouts超时设置
    asp.net 正则表达式过滤所有html标签
    .NET技术开发、VS2005快捷键大全
    在TOMCAT中使用JNDI连接数据源
    设计模式系列之Factory深入研究
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7359951.html
Copyright © 2020-2023  润新知