SSLSocket定义
SSLSocket扩展Socket并提供使用SSL或TLS协议的安全套接字。它也是基于正常的流套接字,但是在网络传输协议(如TCP)上添加了安全保护层。
SSLSocket相关类
类 | 功能描述 |
---|---|
SSLContext | 该类的实例表示安全套接字协议的实现,是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工厂 |
SSLSocket | 扩展自Socket |
SSLServerSocket | 扩展自ServerSocket |
SSLSocketFactory | 抽象类,扩展自SocketFactory,是SSLSocket的工厂 |
SSLServerSocketFactory | 抽象类,扩展自ServerSocketFactory,是SSLServerSocket的工厂 |
KeysStore | 密钥和证书的存储设施 |
KeyManager | 接口,Java Secure Socket Extension密钥管理器 |
TrustManger | 接口,信任管理器 |
X509TrustedManager | TrustManger的子接口,管理X509证书,验证远程安全套接字 |
SSLServerSocket实现
SSLServerSocket需要证书进行安全全验证
使用keytool工具生成一个名称为seckey证书
$ keytool -genkey -keystore seckey -keyalg rsa -alias SSL
服务端编码
package cn.sh.sslsocket.server;
import javax.net.ssl.*;
import java.io.*;
import java.net.Socket;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* @author sh
*/
public class SSLSocketServer {
public static void main(String[] args) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
//准备KeyStore相关信息
String keyName = "SSL";
String keyStoreName = "/Users/sh/workspace/netty-demo/src/cn/sh/sslsocket/seckey";
char[] keyStorePwd = "123456".toCharArray();
char[] keyPwd = "1234567890".toCharArray();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
//装载生成的seckey
try(InputStream in = new FileInputStream(new File(keyStoreName))) {
keyStore.load(in, keyStorePwd);
}
//初始化KeyManagerFactory
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyPwd);
//初始化SSLContext
SSLContext context = SSLContext.getInstance(keyName);
context.init(kmf.getKeyManagers(), new TrustManager[]{getX509TrustManger()}, new SecureRandom());
//监听和接受客户端连接
SSLServerSocketFactory factory = context.getServerSocketFactory();
SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(10002);
System.out.println("服务器端已启动!!!");
//等待客户端连接
Socket client = serverSocket.accept();
System.out.println("客户端地址:" + client.getRemoteSocketAddress());
//准备输出流,用于向客户端发送信息
OutputStream output = client.getOutputStream();
//获取输入流,用于读取客户端发送的信息
InputStream in = client.getInputStream();
byte[] buf = new byte[1024];
int len;
if ((len = in.read(buf)) != -1) {
output.write(buf, 0, len);
}
//冲刷数据
output.flush();
//关闭输入输出流
output.close();
in.close();
serverSocket.close();
}
public static X509TrustManager getX509TrustManger() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
}
客户端实现
普通Socket连接服务器
实现
package cn.sh.sslsocket.client;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* @author sh
*/
public class SocketClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 10002);
OutputStream output = socket.getOutputStream();
InputStream input = socket.getInputStream();
output.write("I am SocketClient".getBytes());
output.flush();
byte[] buf = new byte[1024];
int len;
StringBuilder builder = new StringBuilder();
while ((len = input.read(buf)) != -1) {
builder.append(new String(buf, 0, len));
}
System.out.println("client received:" + builder.toString());
}
}
运行结果
服务器结果如下图
服务端会抛出异常javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
客户端结果如下图
客户端接收到乱码
使用SSLSocket,不使用证书
编码实现
package cn.sh.sslsocket.client;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author sh
*/
public class NoUseKeySSLSocketClient {
public static void main(String[] args) throws IOException {
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslSocket = (SSLSocket) factory.createSocket("localhost", 10002);
OutputStream output = sslSocket.getOutputStream();
InputStream input = sslSocket.getInputStream();
output.write("I am NoUseKeySSLSocketClient".getBytes());
output.flush();
byte[] buf = new byte[1024];
int len;
StringBuilder builder = new StringBuilder();
while ((len = input.read(buf)) != -1) {
builder.append(new String(buf, 0, len));
}
System.out.println("client received:" + builder.toString());
}
}
运行结果
服务器结果如下图
服务端会抛出异常javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
客户端结果如下图
客户端会抛出异常sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
使用SSLSocket,并且使用证书
编码实现
package cn.sh.sslsocket.client;
import cn.sh.sslsocket.server.SSLSocketServer;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* @author sh
*/
public class SSLSocketClient {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, IOException {
SSLContext context = SSLContext.getInstance("SSL");
context.init(null, new TrustManager[]{SSLSocketServer.getX509TrustManger()}, new SecureRandom());
SSLSocketFactory factory = context.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) factory.createSocket("localhost", 10002);
OutputStream output = sslSocket.getOutputStream();
InputStream input = sslSocket.getInputStream();
output.write("I am SSLSocketClient".getBytes());
output.flush();
byte[] buf = new byte[1024];
int len;
StringBuilder builder = new StringBuilder();
while ((len = input.read(buf)) != -1) {
builder.append(new String(buf, 0, len));
}
output.close();
System.out.println("client received:" + builder.toString());
}
}
运行结果
服务器结果如下图
客户端结果如下图
代码地址
本文章的代码在cn.sh.sslsocket包中!