在使用Socket编写通讯程序时,通过添加对SSL的支持可以保障数据的安全和完整。Java提供了Java 安全套接字扩展——JSSE,JSSE是一个纯Java实现的SSL和TLS协议框架,抽象了SSL和TLS复杂的算法,使安全问题变得简单。使用JSSE来开发安全的Socket通讯程序需要一个证书来进行安全认证,认证支持单向认证和双向认证两种方式。
在编写通讯程序之前,需要先生成证书。这里使用java自带的keytool工具生成证书。
服务端证书:
创建服务端keystore
keytool -genkey -keystore server.jks -storepass 123456 -keyalg RSA -validity 365 -keypass 123456
导出服务端证书
keytool -export -keystore server.jks -storepass 123456 -file server.cer
将服务端证书导入到客户端trustkeystroe
keytool -import -keystore server_clientTrust.jks -storepass 123456 -file server.cer
客户端证书:
创建客户端keystore
keytool -genkey -keystore client.jks -storepass 123456 -keyalg RSA -validity 365 -keypass 123456
导出客户端证书
keytool -export -keystore client.jks -storepass 123456 -file client.cer
将客户端证书导入到服务端trustkeystroe
keytool -import -keystore client_serverTrust.jks -storepass 123456 -file client.cer
-keystore:指定密钥库的名称
-storepass:指定密钥库的密码
-keyalg:指定密钥的算法,默认值为DSA
-validity:指定创建的证书有效期多少天(默认 90)
-keypass:指定私钥的密码
以下是范例源码:
SSLBese源码:
public class SSLBese { protected static final int SERVER_PORT = 5900; protected static final String SERVER_JKS_FILE = "certificate/server.jks"; protected static final String SERVER_TRUST_JKS_FILE = "certificate/serverTrust.jks"; protected static final String CLIENT_JKS_FILE = "certificate/client.jks"; protected static final String CLIENT_TRUST_JKS_FILE = "certificate/clientTrust.jks"; protected static final String STOREPASS = "123456"; //密钥库的密码 protected static final String KEYPASS = "123456"; //私钥的密码 protected static int AUTH_MODULE = 2; //认证模式:0-非SSL认证,1-单向SSL认证,2-双向SSL认证 protected String read(InputStream is) throws Exception { BufferedInputStream in = new BufferedInputStream(is); byte[] buffer = new byte[1024]; in.read(buffer); return new String(buffer, "UTF-8"); } protected void write(OutputStream os, String msg) throws Exception { BufferedOutputStream out = new BufferedOutputStream(os); out.write(msg.getBytes("UTF-8")); out.flush(); } }
SSLServer源码:
public class SSLServer extends SSLBese{ private ServerSocket serverSocket; public void start(){ try { init(); Socket socket = serverSocket.accept(); String remoteAddress = socket.getRemoteSocketAddress().toString(); System.out.println("客户端连接:" + remoteAddress); while (true) { //read String recMsg = read(socket.getInputStream()); System.out.println(recMsg); //write String msg = "Server received!"; write(socket.getOutputStream(), msg); } } catch (Exception ex) { ex.printStackTrace(); } } private void init() throws Exception { if(serverSocket != null){ serverSocket.close(); serverSocket = null; } if(AUTH_MODULE == 0){ createServerSocket(); }else{ createSSLServerSocket(); } System.out.println("启动监听服务[" + SERVER_PORT + "] ..."); } private void createServerSocket() throws Exception { serverSocket = new ServerSocket(); serverSocket.setReuseAddress(true); serverSocket.bind(new InetSocketAddress(SERVER_PORT)); } private void createSSLServerSocket() throws Exception { //服务端私钥 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); //创建密钥管理器 KeyStore ks = KeyStore.getInstance("JKS"); //创建密钥库 ks.load(new FileInputStream(SERVER_JKS_FILE), STOREPASS.toCharArray()); //加载私钥 keyManagerFactory.init(ks, STOREPASS.toCharArray()); KeyManager[] kms = keyManagerFactory.getKeyManagers(); //客户端的授权证书(客户端公钥) TrustManager[] tms = null; if(AUTH_MODULE == 2){ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); //信任管理器 KeyStore tks = KeyStore.getInstance("JKS"); tks.load(new FileInputStream(CLIENT_TRUST_JKS_FILE), STOREPASS.toCharArray()); trustManagerFactory.init(tks); tms = trustManagerFactory.getTrustManagers(); } SSLContext ctx = SSLContext.getInstance("TLSV1"); ctx.init(kms, tms, null); serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(); ((SSLServerSocket)serverSocket).setEnabledCipherSuites(((SSLServerSocket)serverSocket).getSupportedCipherSuites()); ((SSLServerSocket)serverSocket).setUseClientMode(false); if(AUTH_MODULE == 2){ ((SSLServerSocket)serverSocket).setNeedClientAuth(true); //验证客户端证书 }else{ ((SSLServerSocket)serverSocket).setNeedClientAuth(false); } serverSocket.setReuseAddress(true); //是否允许重用绑定端口 serverSocket.bind(new InetSocketAddress(SERVER_PORT)); System.out.println("启用SSL安全认证"); } public static void main(String[] args) { SSLServer server = new SSLServer(); server.start(); } }
SSLClient源码:
public class SSLClient extends SSLBese{ private String serverIp; private int serverPort; private Socket socket; public SSLClient(String serverIp, int serverPort){ this.serverIp = serverIp; this.serverPort = serverPort; } public void execute(){ try { init(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); while(true){ //write String msg = "now time is " + sdf.format(new Date()); write(socket.getOutputStream(), msg); //read String recMsg = read(socket.getInputStream()); System.out.println(recMsg); TimeUnit.MILLISECONDS.sleep(1000); } } catch (Exception ex) { ex.printStackTrace(); } finally { if(socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void init() throws Exception { if(AUTH_MODULE == 0){ createSocket(); }else{ createSSLSocket(); } } private void createSocket() throws Exception { socket = new Socket(); socket.setKeepAlive(true); socket.setTcpNoDelay(true); //TCP不延迟发送 socket.setSoLinger(true, 0); //延迟n秒关闭Socket底层连接 socket.setSoTimeout(10000); socket.connect(new InetSocketAddress(this.serverIp, this.serverPort), 6000); } private void createSSLSocket() throws Exception { //客户端私钥 KeyManager[] kms = null; if(AUTH_MODULE == 2){ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream(CLIENT_JKS_FILE), STOREPASS.toCharArray()); keyManagerFactory.init(ks, STOREPASS.toCharArray()); kms = keyManagerFactory.getKeyManagers(); } //服务端的授权证书(服务端公钥) TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); KeyStore tks = KeyStore.getInstance("JKS"); tks.load(new FileInputStream(SERVER_TRUST_JKS_FILE), STOREPASS.toCharArray()); trustManagerFactory.init(tks); TrustManager[] tms = trustManagerFactory.getTrustManagers(); SSLContext ctx = SSLContext.getInstance("TLSV1"); ctx.init(kms, tms, null); socket = (SSLSocket)ctx.getSocketFactory().createSocket(); ((SSLSocket)socket).setEnabledCipherSuites(((SSLSocket)socket).getSupportedCipherSuites()); //可以使用所有支持的加密套件 ((SSLSocket)socket).setUseClientMode(true); socket.setKeepAlive(true); socket.setTcpNoDelay(true); socket.setSoLinger(true, 0); socket.setSoTimeout(10000); socket.connect(new InetSocketAddress(this.serverIp, this.serverPort), 6000); } public static void main(String[] args) { SSLClient client = new SSLClient("127.0.0.1", SERVER_PORT); client.execute(); } }
相关推荐
eclipse中使用Jetty插件实现https请求与SSL双向验证
SSL是Secure Socket Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准,目前已有3.0版本。SSL采用公开密钥技术。其目标是保证两个...
OpenSSL的应用程序是基于OpenSSL的密码算法库和SSL协议库写成的,所以也是一些非常好的OpenSSL的API使用范例,读懂所有这些范例,你对OpenSSL的API使用了解就比较全面了,当然,这也是一项锻炼你的意志力的工作。...
Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...
Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...
Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...
Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例...
一个简单的CS模式的聊天软件,用socket实现,比较简单。 凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 简单 EJB的真实世界模型(源代码...
在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...
在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...
在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...