Java SSL通信Demo

一、数字证书创建

在SSL通信协议中,服务端必须有一个数字证书,当客户端连接到服务端时,会得到这个证书,然后客户端会判断这个证书是否是可信的,如果是,则交换信道加密密钥,进行通信。如果不信任这个证书,则连接失败。

1、keytool

JDK自带keytool工具命令案列:

keytool 
    -genkey 
    -alias demo
    -keyalg RSA 
    -keysize 1024 
    -validity 365 
    -keystore ./ks 
    -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" 
    -storepass ks 
    -keypass 123456

参数

参数含义

-genkey

生成秘钥

-alias

别名

-keyalg

秘钥算法

-keysize

秘钥长度

-validity

有效期

-keystore

生成秘钥库的存储路径和名称

-keypass

秘钥口令

-storepass

秘钥库口令

-dname

CN:姓名;OU:组织单位名称;O:组织名称;L:省/市/自治区名称;C:国家/地区代码

2、数字证书创建

(1)服务端
keytool -genkey -alias ssl-demo-server -keyalg RSA -keysize 1024 -validity 365 -keystore ./server -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass server -keypass 123456

java ssl 证书加入信任 java实现ssl_keytool

(2)客户端
keytool -genkey -alias ssl-demo-client -keyalg RSA -keysize 1024 -validity 365 -keystore ./client -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass client -keypass 123456

java ssl 证书加入信任 java实现ssl_网络协议_02

(3) 将服务端的证书导出来,并导入到客户端的仓库
[1] 服务端证书导出


keytool -export -alias ssl-demo-server -keystore ./server -file server.cer

java ssl 证书加入信任 java实现ssl_keytool_03

[2] 将服务端导出证书导入到客户端仓库
keytool -export -alias ssl-demo-server -keystore ./server -file server.cer

java ssl 证书加入信任 java实现ssl_客户端_04

[3]客户端证书导出
keytool -export -alias ssl-demo-client -keystore ./client -file client.cer

java ssl 证书加入信任 java实现ssl_ssl_05

[4] 将客户端导出证书导入到服务端仓库
keytool -import -trustcacerts -alias ssl-demo-client -file ./client.cer -keystore E:/store/server/server

java ssl 证书加入信任 java实现ssl_网络协议_06

二、SSL单向握手通信

SSL单向握手通信。即:客户端验证服务端的证书,服务端不验证客户端的证书。
 
 
 服务端设置:
 		/**
         * 设置是否需要验证客户端
         *  true:需要验证客户端
         *  false:不需要验证客户端
         */
        sslServerSocket.setNeedClientAuth(false);

1、服务端(不需要验证客户端)

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;


public class SSLServer {

    /**
     * 服务器端证书位置
     */
    private static String SERVER_KEY_STORE = "E:\\store\\server\\server";

    /**
     * 服务器端证书密码
     */
    private static String SERVER_KEY_STORE_PASSWORD = "123456";


    /**
     * 套接字
     */
    private static Socket socket;



    public static void main(String[] args) throws Exception {

        SSLServerSocket sslServerSocket = createSSLServerSocket();

        while (true) {

            /**
             * 服务端获取连接
             */
            socket = sslServerSocket.accept();

            messageHandle();

        }

    }


    /**
     * 客户端信息处理
     */
    public static void messageHandle() {


        /**
         * 字节输入流
         */
        InputStream inputStream = null;

        /**
         * 字符输入流
         */
        InputStreamReader inputStreamReader = null;


        /**
         * 缓冲区
         */
        BufferedReader bufferedReader = null;


        /**
         * 字节输出流
         */
        OutputStream outputStream = null;

        /**
         * 文本输出流
         */
        PrintWriter printWriter = null;


        try {


            /**
             * 获取连接字节输入流
             */
            inputStream = socket.getInputStream();


            /**
             * 将输字节输入流转换为字符输入流
             */
            inputStreamReader = new InputStreamReader(inputStream);


            /**
             * 将字符输入流的数据写到缓冲区
             */
            bufferedReader = new BufferedReader(inputStreamReader);


            /**
             * 获取连接字节输出流
             */
            outputStream = socket.getOutputStream();

            /**
             * 将字节输出流转化为文本输出流
             */
            printWriter = new PrintWriter(outputStream);


            /**
             * 读取客户端发送来的数据
             */
            String data = bufferedReader.readLine();
            System.out.println("客户端消息:" + data);

            /**
             * 向客户端返回消息
             */
            printWriter.println("你好,客户端,我已经接收到你发送的消息!");

            /**
             * 刷新流
             */
            printWriter.flush();


        } catch (IOException e) {

            e.printStackTrace();

        }


    }


    /**
     * 创建SSL协议服务端Socket
     *
     * @return
     * @throws Exception
     */
    public static SSLServerSocket createSSLServerSocket() throws Exception {


        /**
         * SSL请求信托证书仓库注册
         */
        System.setProperty("javax.net.ssl.trustStore", SERVER_KEY_STORE);

        /**
         * 获取指定类型(jceks)的密钥存储库实例
         */
        KeyStore keyStore = KeyStore.getInstance("jceks");


        /**
         * 读取服务端证书
         */
        FileInputStream fileInputStream = new FileInputStream(SERVER_KEY_STORE);


        /**
         * 加载服务端证书到密钥存储库
         */
        keyStore.load(fileInputStream, null);


        /**
         * 获取密钥管理仓库实例
         */
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");


        /**
         * 初始化密钥管理仓库
         */
        keyManagerFactory.init(keyStore, SERVER_KEY_STORE_PASSWORD.toCharArray());


        /**
         *  获取协议为“TLS”的SSL上下文实例
         */
        SSLContext sslContext = SSLContext.getInstance("TLS");


        /**
         * 获取密钥管理仓库中所有的密钥管理器
         */
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

        /**
         * 初始化SSL上下文
         */
        sslContext.init(keyManagers, null, null);


        /**
         * 通过SSL上下文获取ServerSocket工厂
         */
        ServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory();

        /**
         * 创建一个服务端,端口为8848
         */
        ServerSocket serverSocket = serverSocketFactory.createServerSocket(8848);

        /**
         * 服务端向下转换为SSL协议的服务端
         */
        SSLServerSocket sslServerSocket = (SSLServerSocket) serverSocket;

        /**
         * 设置是否需要客户端验证
         *  true:需要验证客户端
         *  false:不需要验证客户端
         */
        sslServerSocket.setNeedClientAuth(false);


        /**
         * 返回
         */
        return sslServerSocket;

    }


}

2、客户端

import java.io.*;
import java.net.Socket;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {


    /**
     * 客户端证书地址
     */
    private static String CLIENT_KEY_STORE = "E:\\store\\client\\client";



    public static void main(String[] args) throws Exception {

        /**
         * SSL请求信托证书仓库注册
         */
        System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);


        /**
         *  获取Socket工厂
         */
        SocketFactory socketFactory = SSLSocketFactory.getDefault();

        /**
         * 创建Socket
         */
        Socket socket = socketFactory.createSocket("localhost", 8848);


        /**
         * 获取连接输出流
         */
        OutputStream outputStream = socket.getOutputStream();

        /**
         * 将字节输出流转化为文本输出流
         */
        PrintWriter writer = new PrintWriter(outputStream);

        /**
         * 获取连接字节输入流
         */
        InputStream inputStream = socket.getInputStream();


        /**
         * 将输字节输入流转换为字符输入流
         */
        InputStreamReader  inputStreamReader = new InputStreamReader(inputStream);


        /**
         * 将字符输入流的数据写到缓冲区
         */
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);


        /**
         * 向服务器发送信息
         */
        writer.println("你好,服务器(单向)");

        /**
         * 刷新流
         */
        writer.flush();

        /**
         * 获取服务器返回的信息
         */
        String data = bufferedReader.readLine();
        System.out.println(data);

        /**
         * 关闭连接
         */
        socket.close();

    }




}

3、运行测试

java ssl 证书加入信任 java实现ssl_客户端_07

三、SSL双向握手通信

1、服务端

/**
 		 * 修改此处参数即可
         * 设置是否需要客户端验证
         *  	true:需要验证客户端
         *  	false:不需要验证客户端
         */
        sslServerSocket.setNeedClientAuth(true);

2、客户端

import java.io.*;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.SocketFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

public class BothwaySSLClient {

    /**
     * 客户端证书地址
     */
    private static String CLIENT_KEY_STORE = "E:\\store\\client\\client";

    /**
     * 客户端证书密码
     */
    private static String CLIENT_KEY_STORE_PASSWORD = "123456";


    public static void main(String[] args) throws Exception {

        /**
         * SSL请求信托证书仓库注册
         */
        System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);


        /**
         * 获取连接
         */
        Socket socket = createSocket();


        /**
         * 获取连接输出流
         */
        OutputStream outputStream = socket.getOutputStream();

        /**
         * 将字节输出流转化为文本输出流
         */
        PrintWriter writer = new PrintWriter(outputStream);

        /**
         * 获取连接字节输入流
         */
        InputStream inputStream = socket.getInputStream();


        /**
         * 将输字节输入流转换为字符输入流
         */
        InputStreamReader  inputStreamReader = new InputStreamReader(inputStream);


        /**
         * 将字符输入流的数据写到缓冲区
         */
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);


        /**
         * 向服务器发送信息
         */
        writer.println("你好,服务器(双向)");

        /**
         * 刷新流
         */
        writer.flush();

        /**
         * 获取服务器返回的信息
         */
        String data = bufferedReader.readLine();
        System.out.println(data);

        /**
         * 关闭连接
         */
        socket.close();

    }



    public static Socket createSocket() throws Exception {

        /**
         * 获取指定类型(jceks)的密钥存储库实例
         */
        KeyStore keyStore = KeyStore.getInstance("jceks");

        /**
         * 读取服务端证书
         */
        FileInputStream fileInputStream = new FileInputStream(CLIENT_KEY_STORE);

        /**
         * 加载服务端证书到密钥存储库
         */
        keyStore.load(fileInputStream, null);

        /**
         * 获取密钥管理仓库实例
         */
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");

        /**
         * 初始化密钥管理仓库
         */
        keyManagerFactory.init(keyStore, CLIENT_KEY_STORE_PASSWORD.toCharArray());

        /**
         *  获取协议为“TLS”的SSL上下文实例
         */
        SSLContext sslContext = SSLContext.getInstance("TLS");

        /**
         * 获取密钥管理仓库中所有的密钥管理器
         */
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

        /**
         * 初始化SSL上下文
         */
        sslContext.init(keyManagers, null, null);

        /**
         * 通过SSL上下文获取Socket工厂
         */
        SocketFactory factory = sslContext.getSocketFactory();

        /**
         * 创建Socket(连接服务器)
         */
        Socket socket = factory.createSocket("localhost", 8848);

        /**
         * 返回
         */
        return socket;
    }

}

3、运行测试

java ssl 证书加入信任 java实现ssl_java ssl 证书加入信任_08