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();
}
}