SSL的TCP通信

一切尽在代码中,额,自己测试的小例子,感觉很有用,做个记录。

服务器端:

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";// 定义服务器端要使用的证书
		String trust = "d:keys/trustclient.jks";// 定义服务器端要信任的证书
		/* 个人感觉,上面这两个属性在使用的时候完全可以定义为properties文件或者xml文件来使用 */

		KeyStore keyStore = KeyStore.getInstance("JKS");// 定义一个KeyStore用来存储服务器的秘钥文件
		keyStore.load(new FileInputStream(key), "123456".toCharArray());// 加载服务器端使用的证书,当然要输入要打开加密文件的密码了
		KeyStore trustStore = KeyStore.getInstance("JKS");// 定义一个KeyStore用来存储服务器信任的证书文件
		trustStore.load(new FileInputStream(trust), "123456".toCharArray());// 加载服务器端信任的证书文件,当然也要输入密码的
		/** 额,其实keyStore和truststore都是Keystore的大家都看到了,就是保存的秘钥文件不同而已了 */

		KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
				.getDefaultAlgorithm());/*
										 * 创建一个服务器的秘钥管理工厂,KeyManagerFactory.
										 * getDefaultAlgorithm
										 * ()是指定的默认的算法,记得是RSA··输出一下就OK了
										 */
		kmf.init(keyStore, "mipengcheng".toCharArray());/*
														 * 初始化,在初始化的时候需要自定秘钥的密码,
														 * 这个在创建的时候指定的
														 */
		TrustManagerFactory tmf = TrustManagerFactory
				.getInstance(TrustManagerFactory.getDefaultAlgorithm());/*
																		 * 创建一个服务器信任证书的管理工厂
																		 * ,
																		 * 同样指定了RSA的算法
																		 */
		tmf.init(trustStore);/* 初始化,由于信任的是证书,不是秘钥,所以不用指定密码什么的了 */

		SSLContext sslc = SSLContext.getInstance("TLSv1");/*
														 * 获得TLSv1版本的SSLContext,
														 * 还有个ssl3的
														 */
		sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(),
				new SecureRandom());/* 用两个工厂来初始化SSLContext */

		SSLServerSocketFactory sllFactory = sslc.getServerSocketFactory();/* 获得服务器端口工厂 */
		SSLServerSocket serverSocket = (SSLServerSocket) sllFactory
				.createServerSocket(9999);/* 创建serverSocket,在9999端口监听 */
		/* 这句很重要,是要开启客户端的安全证书验证滴 */
		serverSocket.setNeedClientAuth(true);
		System.out.println("服务器已经启动了........");
		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("服务器开始读取数据=====");
				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("服务器收到消息");
					}
				}
				System.out.println("服务器跳出循环");
				Thread.sleep(10000);
				out.close();
				read.close();

			} catch (Exception e) {
				e.printStackTrace();
			}

		}

	}
}

客户端:

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());
		/* 到这里结束======== */
		/** 上面注释包围的内容,和服务器端的一样,只是这里变成了客户端要使用的秘钥,客户端要信任的证书 */

		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.服务器端:

SSL的TCP通信_第1张图片

2.客户端:

SSL的TCP通信_第2张图片

在项目中使用到的证书

SSL的TCP通信_第3张图片

关于证书的创建,这里以服务器端的秘钥的创建和服务器要给客户端使用的信任证书的创建为例:

使用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

输入  的密钥口令
        (如果和密钥库口令相同, 按回车):
再次输入新口令:

使用第一行的命令来生成证书,指定名字为m.jks;然后根据提示就可以创建服务器端的秘钥了。


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


这条命令导出了服务器端的证书文件,用来供其他客户端验证服务器。但是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
证书已添加到密钥库中

这条命令就把服务器端给客户端验证的证书的jks文件生成了。


客户端的相关秘钥,证书的生成也是一样的。


本人才疏学浅,只是想折腾折腾,学习学习,如果有什么不对的,不足的地方,还请大家包涵,指教!


你可能感兴趣的:(java基础)