安全网络通信(二)----创建基于TLS的安全服务器和安全客户端

JSSE简介

JSSE封装了底层复杂的安全通信细节,使得开发人员能方便的利用它来开发安全的网络应用程序。

JSSE只要包括四个包:

  • javax.net.ssl

包括进行安全通信的类,比如SSLServerSocket和SSLSocket类。

  • javax.net

包括安全套接字的工厂类,比如SSLServerSocketFactory和SSLSocketFactory类。

  • java.security.cert

包括处理数字证书的类,如X509Certificate类。

  • com.sun.net.ssl

包括SUN公司提供的JSSE的实现类。

代码示例


客户端

import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.*;
import java.util.Arrays;
import java.util.stream.Stream;

public class EchoClient {
    private String host = "localhost";
    private int port = 8000;
    private SSLSocket socket;

    public EchoClient()throws Exception{        

        //秘钥库密码
        String passphrase = "123456";
        char[] password = passphrase.toCharArray();
        //秘钥库文件名  
        String trustStoreFile = "test.keys"; 
        //JKS是SUN支持的KeyStore的类型
        KeyStore ts = KeyStore.getInstance("JKS");
        //打开数字证书
        ts.load(new FileInputStream(trustStoreFile), password);
        //创建TrustManager对象
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(ts);
        /**
         * SSLContext类负责设置与安全通信有关的各种信息:
         *1>使用的协议(SSL/TLS);
         *2>自身的数字证书以及对方的数字证书;
         * SSLContext还负责构造SSLServerSocketFactory、SSLSocketFactory和SSLEngine对象
         */
        //使用TLS协议
        SSLContext sslContext = SSLContext.getInstance("TLS");
        /**
         * init(KeyManager[] km, TrustManager[] tm, SecureRandom random)
         * 参数random:用于设置安全随机数,如果为null,则采用默认的SecureRandom实现;
         * 参数km:如果为空,会创建一个默认的KeyManager对象,该对象从系统属性javax.net.ssl.keyStore
         * 中获取数字证书,若不存在这个属性,那么KeyStore对象的内容为空;
         * 参数tm:如果为空,会创建一个默认的TrustManager对象,以及与之相关的KeyStore对象
         * KeyStore对象按照以下步骤获取数字证书:
         * >先尝试从系统属性javax.net.ssl.trustStore中获取数字证书
         * >若上一步失败,就尝试把<JDK目录>/jre/security/jsscacerts文件作为数字证书文件
         * >若上一步失败,就尝试把<JDK目录>/jre/security/cacerts文件作为数字证书文件
         * >若上一步失败,则KeyStore对象内容为空
         */
        sslContext.init(null, tmf.getTrustManagers(), null);

        /**
         * SSLSocket类是Socket的子类,
         * SSLSocket类还具有与安全通信有关的方法:
         * 1>设置加密套件
         * 2>处理握手结束事件
         * 3>管理SSL/TLS会话
         * 4>客户端模式
         */
        //创建SSLSocket对象
        SSLSocketFactory factory=sslContext.getSocketFactory();
        socket=(SSLSocket)factory.createSocket(host,port);

        socket.addHandshakeCompletedListener(new HandshakeCompletedListener() {
            @Override
            public void handshakeCompleted(HandshakeCompletedEvent event) {             
                System.out.println(event.getCipherSuite());             
                System.out.println(event.getSession().getPeerHost());
            }
        });
    }

    public static void main(String args[]) throws Exception {
        new EchoClient().talk();
    }

    private PrintWriter getWriter(Socket socket) throws IOException {
        OutputStream socketOut = socket.getOutputStream();
        return new PrintWriter(socketOut, true);
    }

    private BufferedReader getReader(Socket socket) throws IOException {
        InputStream socketIn = socket.getInputStream();
        return new BufferedReader(new InputStreamReader(socketIn));
    }

    public void talk() throws IOException {
        try {
            BufferedReader br = getReader(socket);
            PrintWriter pw = getWriter(socket);
            BufferedReader localReader = new BufferedReader(
                    new InputStreamReader(System.in));
            String msg = null;
            while ((msg = localReader.readLine()) != null) {

                pw.println(msg);
                System.out.println(br.readLine());

                if (msg.equals("bye"))
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服务器端


import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.*;

public class EchoServer {
  private int port=8000;
  private SSLServerSocket serverSocket;

  public EchoServer() throws Exception {
    //输出跟踪日志
    //System.setProperty("javax.net.debug", "all"); 
    SSLContext context=createSSLContext();
    SSLServerSocketFactory factory=context.getServerSocketFactory();
    serverSocket =(SSLServerSocket)factory.createServerSocket(port);
    System.out.println("服务器启动");
    System.out.println(serverSocket.getUseClientMode()? "客户模式":"服务器模式");
    System.out.println(serverSocket.getNeedClientAuth()? "需要验证对方身份":"不需要验证对方身份");

    String[] supported=serverSocket.getSupportedCipherSuites();
    serverSocket.setEnabledCipherSuites(supported);
  }


  public SSLContext createSSLContext() throws Exception {
    String keyStoreFile = "test.keys";
    String passphrase = "123456";
    KeyStore ks = KeyStore.getInstance("JKS");
    char[] password = passphrase.toCharArray();
    ks.load(new FileInputStream(keyStoreFile), password);
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, password);

    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(kmf.getKeyManagers(), null, null);

    //当要求客户端提供安全证书时,服务器端可创建TrustManagerFactory,
    //并由它创建TrustManager,TrustManger根据与之关联的KeyStore中的信息,
    //来决定是否相信客户提供的安全证书。
    //String trustStoreFile = "client.keys";    
    //KeyStore ts = KeyStore.getInstance("JKS");
    //ts.load(new FileInputStream(trustStoreFile), password);
    //TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
    //tmf.init(ts);
    //sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    return sslContext;
  }


  public String echo(String msg) {
    return "echo:" + msg;
  }

  private PrintWriter getWriter(Socket socket)throws IOException{
    OutputStream socketOut = socket.getOutputStream();
    return new PrintWriter(socketOut,true);
  }
  private BufferedReader getReader(Socket socket)throws IOException{
    InputStream socketIn = socket.getInputStream();
    return new BufferedReader(new InputStreamReader(socketIn));
  }

  public void service() {
    while (true) {
      Socket socket=null;
      try {
        socket = serverSocket.accept();  //等待客户连接
        System.out.println("New connection accepted " 
                        +socket.getInetAddress() + ":" +socket.getPort());
        BufferedReader br =getReader(socket);
        PrintWriter pw = getWriter(socket);

        String msg = null;
        while ((msg = br.readLine()) != null) {
          System.out.println(msg); 
          pw.println(echo(msg));
          if (msg.equals("bye")) //如果客户发送的消息为“bye”,就结束通信
            break;
        }
      }catch (IOException e) {
         e.printStackTrace();
      }finally {
         try{
if(socket!=null)socket.close();  //断开连接
         }catch (IOException e) {e.printStackTrace();}
      }
    }
  }

  public static void main(String args[])throws Exception {
    new EchoServer().service();
  }
}

猜你喜欢

转载自blog.csdn.net/qq_34444097/article/details/79860063