Java SSL/TLS Socket实现

时间:2022-09-04 07:27:02

通信端无需向对方证明自己的身份,则称该端处于“客户模式”,否则称其处于“服务器模式”,无论是客户端还是服务器端,都可处于“客户模式”或者“服务器模式”

首先生成服务器端认证证书,使用java自带的keytool工具:

Java SSL/TLS Socket实现

其中:

-genkey:生成一对非对称密钥

-keyalg:加密算法

-keystore:证书存放路径

-alias:密钥对别名,该别名是公开的

相同的方式,生成客户端认证证书,不过命名为client_rsa.key,别名为clientkey

Java SSL/TLS Socket实现

使用jdk1.5,唯一需要引入的包为log4j-1.2.14.jar

客户端认证:

package com.test.client.auth;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Properties; import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory; import com.test.server.config.Configuration; public class Auth {
private static SSLContext sslContext; public static SSLContext getSSLContext() throws Exception{
Properties p = Configuration.getConfig();
String protocol = p.getProperty("protocol");
String sCertificateFile = p.getProperty("serverCertificateFile");
String sCertificatePwd = p.getProperty("serverCertificatePwd");
String sMainPwd = p.getProperty("serverMainPwd");
String cCertificateFile = p.getProperty("clientCertificateFile");
String cCertificatePwd = p.getProperty("clientCertificatePwd");
String cMainPwd = p.getProperty("clientMainPwd"); //KeyStore class is used to save certificate.
char[] c_pwd = sCertificatePwd.toCharArray();
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(sCertificateFile), c_pwd); //TrustManagerFactory class is used to create TrustManager class.
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
char[] m_pwd = sMainPwd.toCharArray();
trustManagerFactory.init(keyStore);
//TrustManager class is used to decide weather to trust the certificate
//or not.
TrustManager[] tms = trustManagerFactory.getTrustManagers(); KeyManager[] kms = null;
if(Configuration.getConfig().getProperty("authority").equals("2")){
//KeyStore class is used to save certificate.
c_pwd = cCertificatePwd.toCharArray();
keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(cCertificateFile), c_pwd); //KeyManagerFactory class is used to create KeyManager class.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
m_pwd = cMainPwd.toCharArray();
keyManagerFactory.init(keyStore, m_pwd);
//KeyManager class is used to choose a certificate
//to prove the identity of the client side.
kms = keyManagerFactory.getKeyManagers();
} //SSLContext class is used to set all the properties about secure communication.
//Such as protocol type and so on.
sslContext = SSLContext.getInstance(protocol);
sslContext.init(kms, tms, null); return sslContext;
}
}

客户端主程序:

package com.test.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Properties; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory; import org.apache.log4j.Logger; import com.test.client.auth.Auth;
import com.test.server.config.Configuration;
import com.test.tools.SocketIO; public class Client {
static Logger logger = Logger.getLogger(Client.class);
private SSLContext sslContext;
private int port = 10000;
private String host = "127.0.0.1";
private SSLSocket socket;
private Properties p; public Client(){
try {
p = Configuration.getConfig();
Integer authority = Integer.valueOf(p.getProperty("authority")); sslContext = Auth.getSSLContext();
SSLSocketFactory factory = (SSLSocketFactory) sslContext.getSocketFactory();
socket = (SSLSocket)factory.createSocket();
String[] pwdsuits = socket.getSupportedCipherSuites();
socket.setEnabledCipherSuites(pwdsuits);//socket可以使用所有支持的加密套件
if(authority.intValue() == 2){
socket.setUseClientMode(false);
socket.setNeedClientAuth(true);
}else{
socket.setUseClientMode(true);
socket.setWantClientAuth(true);
} SocketAddress address = new InetSocketAddress(host, port);
socket.connect(address, 0);
} catch (Exception e) {
e.printStackTrace();
logger.error("socket establish failed!");
}
} public void request(){
try{
String encoding = p.getProperty("socketStreamEncoding"); DataOutputStream output = SocketIO.getDataOutput(socket);
String user = "name";
byte[] bytes = user.getBytes(encoding);
short length = (short)bytes.length;
short pwd = (short)123; output.writeShort(length);
output.write(bytes);
output.writeShort(pwd); DataInputStream input = SocketIO.getDataInput(socket);
length = input.readShort();
bytes = new byte[length];
input.read(bytes); logger.info("request result:"+new String(bytes,encoding));
}catch(Exception e){
e.printStackTrace();
logger.error("request error");
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} public static void main(String[] args){
Client client = new Client();
client.request();
}
}

服务器端认证:

package com.test.server.auth;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Properties; import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory; import com.test.server.config.Configuration; public class Auth {
private static SSLContext sslContext; public static SSLContext getSSLContext() throws Exception{
Properties p = Configuration.getConfig();
String protocol = p.getProperty("protocol");
String sCertificateFile = p.getProperty("serverCertificateFile");
String sCertificatePwd = p.getProperty("serverCertificatePwd");
String sMainPwd = p.getProperty("serverMainPwd");
String cCertificateFile = p.getProperty("clientCertificateFile");
String cCertificatePwd = p.getProperty("clientCertificatePwd");
String cMainPwd = p.getProperty("clientMainPwd"); //KeyStore class is used to save certificate.
char[] c_pwd = sCertificatePwd.toCharArray();
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(sCertificateFile), c_pwd); //KeyManagerFactory class is used to create KeyManager class.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
char[] m_pwd = sMainPwd.toCharArray();
keyManagerFactory.init(keyStore, m_pwd);
//KeyManager class is used to choose a certificate
//to prove the identity of the server side.
KeyManager[] kms = keyManagerFactory.getKeyManagers(); TrustManager[] tms = null;
if(Configuration.getConfig().getProperty("authority").equals("2")){
//KeyStore class is used to save certificate.
c_pwd = cCertificatePwd.toCharArray();
keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(cCertificateFile), c_pwd); //TrustManagerFactory class is used to create TrustManager class.
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
m_pwd = cMainPwd.toCharArray();
trustManagerFactory.init(keyStore);
//TrustManager class is used to decide weather to trust the certificate
//or not.
tms = trustManagerFactory.getTrustManagers();
} //SSLContext class is used to set all the properties about secure communication.
//Such as protocol type and so on.
sslContext = SSLContext.getInstance(protocol);
sslContext.init(kms, tms, null); return sslContext;
}
}

服务器端主程序:

package com.test.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket; import org.apache.log4j.Logger; import com.test.server.auth.Auth;
import com.test.server.business.Job;
import com.test.server.config.Configuration; public class Server {
static Logger logger = Logger.getLogger(Server.class);
private SSLContext sslContext;
private SSLServerSocketFactory sslServerSocketFactory;
private SSLServerSocket sslServerSocket;
private final Executor executor; public Server() throws Exception{
Properties p = Configuration.getConfig();
Integer serverListenPort = Integer.valueOf(p.getProperty("serverListenPort"));
Integer serverThreadPoolSize = Integer.valueOf(p.getProperty("serverThreadPoolSize"));
Integer serverRequestQueueSize = Integer.valueOf(p.getProperty("serverRequestQueueSize"));
Integer authority = Integer.valueOf(p.getProperty("authority")); executor = Executors.newFixedThreadPool(serverThreadPoolSize); sslContext = Auth.getSSLContext();
sslServerSocketFactory = sslContext.getServerSocketFactory();
//Just create a TCP connection.SSL shake hand does not begin.
//The first time either side(server or client) try to get a socket input stream
//or output stream will case the SSL shake hand begin.
sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket();
String[] pwdsuits = sslServerSocket.getSupportedCipherSuites();
sslServerSocket.setEnabledCipherSuites(pwdsuits);
//Use client mode.Must prove its identity to the client side.
//Client mode is the default mode.
sslServerSocket.setUseClientMode(false);
if(authority.intValue() == 2){
//The communication will stop if the client side doesn't show its identity.
sslServerSocket.setNeedClientAuth(true);
}else{
//The communication will go on although the client side doesn't show its identity.
sslServerSocket.setWantClientAuth(true);
} sslServerSocket.setReuseAddress(true);
sslServerSocket.setReceiveBufferSize(128*1024);
sslServerSocket.setPerformancePreferences(3, 2, 1);
sslServerSocket.bind(new InetSocketAddress(serverListenPort),serverRequestQueueSize); logger.info("Server start up!");
logger.info("server port is:"+serverListenPort);
} private void service(){
while(true){
SSLSocket socket = null;
try{
logger.debug("Wait for client request!");
socket = (SSLSocket)sslServerSocket.accept();
logger.debug("Get client request!"); Runnable job = new Job(socket);
executor.execute(job);
}catch(Exception e){
logger.error("server run exception");
try {
socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
} public static void main(String[] args) {
Server server;
try{
server = new Server();
server.service();
}catch(Exception e){
e.printStackTrace();
logger.error("server socket establish error!");
}
}
}

服务器业务执行线程:

package com.test.server.business;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Properties; import org.apache.log4j.Logger; import com.test.server.config.Configuration;
import com.test.tools.SocketIO; public class Job implements Runnable {
static Logger logger = Logger.getLogger(Job.class);
private Socket socket; public Job(Socket socket){
this.socket = socket;
} public void run() {
Properties p = Configuration.getConfig();
String encoding = p.getProperty("socketStreamEncoding"); DataInputStream input = null;
DataOutputStream output = null;
try{
input = SocketIO.getDataInput(socket); short length = input.readShort();
byte[] bytes = new byte[length];
input.read(bytes);
String user = new String(bytes,encoding);
short pwd = input.readShort(); String result = null;
if(null != user && !user.equals("") && user.equals("name") && pwd == 123){
result = "login success";
}else{
result = "login failed";
}
logger.info("request user:"+user);
logger.info("request pwd:"+pwd); output = SocketIO.getDataOutput(socket); bytes = result.getBytes(encoding);
length = (short)bytes.length;
output.writeShort(length);
output.write(bytes); logger.info("response info:"+result);
}catch(Exception e){
e.printStackTrace();
logger.error("business thread run exception");
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
logger.error("server socket close error");
}
}
}
}

配置文件类:

package com.test.server.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties; import org.apache.log4j.Logger; public class Configuration {
private static Properties config; static Logger logger = Logger.getLogger(Configuration.class); public static Properties getConfig(){
try{
if(null == config){
File configFile = new File("./conf/conf.properties");
if(configFile.exists() && configFile.isFile()
&& configFile.canRead()){
InputStream input = new FileInputStream(configFile);
config = new Properties();
config.load(input);
}
}
}catch(Exception e){
//default set
config = new Properties();
config.setProperty("protocol", "TLSV1");
config.setProperty("serverCertificateFile", "./certificate/server_rsa.key");
config.setProperty("serverCertificatePwd", "123456");
config.setProperty("serverMainPwd", "654321");
config.setProperty("clientCertificateFile", "./certificate/client_rsa.key");
config.setProperty("clientCertificatePwd", "123456");
config.setProperty("clientMainPwd", "654321");
config.setProperty("serverListenPort", "10000");
config.setProperty("serverThreadPoolSize", "5");
config.setProperty("serverRequestQueueSize", "10");
config.setProperty("socketStreamEncoding", "UTF-8");
}
return config;
}
}

接口工具类:

package com.test.tools;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket; public class SocketIO{
public static DataInputStream getDataInput(Socket socket) throws IOException{
DataInputStream input = new DataInputStream(socket.getInputStream());
return input;
} public static DataOutputStream getDataOutput(Socket socket) throws IOException{
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
return out;
}
}

配置文件:

#1:单向认证,只有服务器端需证明其身份
#2:双向认证,服务器端和客户端都需证明其身份
authority=2
#通信协议
protocol=TLSV1
#服务器证书
serverCertificateFile=./certificate/server_rsa.key
#服务器证书密码
serverCertificatePwd=123456
#服务器证书主密码
serverMainPwd=654321
#客户端证书,如果为双向认证,则必须填写
clientCertificateFile=./certificate/client_rsa.key
#客户端证书密码
clientCertificatePwd=123456
#客户端证书主密码
clientMainPwd=654321
#服务器监听端口,注意root权限
serverListenPort=10000
#服务器线程池线程数(2*核数+1)
serverThreadPoolSize=5
#服务器Socket请求队列长度
serverRequestQueueSize=10
#字节流编码
socketStreamEncoding=GBK

日志文件:

log4j.rootLogger=debug,logOutput,fileLogOutput

log console out put
log4j.appender.logOutput=org.apache.log4j.ConsoleAppender
log4j.appender.logOutput.layout=org.apache.log4j.PatternLayout
log4j.appender.logOutput.layout.ConversionPattern=%p%d{[yy-MM-dd HH:mm:ss]}[%c] -> %m%n #log file out put
log4j.appender.fileLogOutput=org.apache.log4j.RollingFileAppender
log4j.appender.fileLogOutput.File=./log/server.log
log4j.appender.fileLogOutput.MaxFileSize=1000KB
log4j.appender.fileLogOutput.MaxBackupIndex=3
log4j.appender.fileLogOutput.layout=org.apache.log4j.PatternLayout
log4j.appender.fileLogOutput.layout.ConversionPattern=%p%d{[yy-MM-dd HH:mm:ss]}[%c] -> %m%n

运行后的结果:

客户端:

INFO[13-10-08 09:33:39][com.test.client.Client] -> request result:login success

服务端:

INFO[13-10-08 09:33:34][com.test.server.Server] -> Server start up!
INFO[13-10-08 09:33:34][com.test.server.Server] -> server port is:10000
DEBUG[13-10-08 09:33:34][com.test.server.Server] -> Wait for client request!
DEBUG[13-10-08 09:33:39][com.test.server.Server] -> Get client request!
DEBUG[13-10-08 09:33:39][com.test.server.Server] -> Wait for client request!
INFO[13-10-08 09:33:39][com.test.server.business.Job] -> request user:name
INFO[13-10-08 09:33:39][com.test.server.business.Job] -> request pwd:123
INFO[13-10-08 09:33:39][com.test.server.business.Job] -> response info:login success

PS:

1,不能随意的使用close()方法关闭socket输入输出流,使用close()方法关闭socket输入输出流会导致socket本身被关闭

2,字符串必须按照指定的编码转换为字节数组,字节数组也必须通过相同的编码转换为字符串,否则将会出现乱码

String[] pwdsuits = socket.getSupportedCipherSuites();
socket.setEnabledCipherSuites(pwdsuits);

加密套件(ciphersuits)包括一组加密参数,这些参数指定了加密算法、密钥长度等加密等信息。

[SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, ...

Java SSL/TLS Socket实现的更多相关文章

  1. Android网络编程系列 一 JavaSecurity之JSSE(SSL/TLS)

    摘要:     Java Security在Java存在已久了而且它是一个非常重要且独立的版块,包含了很多的知识点,常见的有MD5,DigitalSignature等,而Android在Java Se ...

  2. SSL/TLS加密传输与数字证书解读

    什么是ssl? secure socket layer(ssl)协议最初由netscape企业发展,现已成为网络用来鉴别网站和网页浏览者身份,以及在浏览器使用者及网页服务器之间进行加密通讯的全球化标准 ...

  3. java ssl https 连接详解 生成证书

    我们先来了解一下什么理HTTPS 1. HTTPS概念 1)简介 HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全 ...

  4. MINA、Netty、Twisted一起学(十一):SSL/TLS

    什么是SSL/TLS 不使用SSL/TLS的网络通信,一般都是明文传输,网络传输内容在传输过程中很容易被窃听甚至篡改,非常不安全.SSL/TLS协议就是为了解决这些安全问题而设计的.SSL/TLS协议 ...

  5. https Java SSL Exception protocol_version

    在java代码中,使用HttpClient爬取https页面时,遇到了这个bug:javax.net.ssl.SSLException: Received fatal alert: protocol_ ...

  6. java ssl https 连接详解 生成证书 tomcat keystone

    java ssl https 连接详解 生成证书 我们先来了解一下什么理HTTPS 1. HTTPS概念 1)简介 HTTPS(全称:Hypertext Transfer Protocol over ...

  7. 六、Mosquitto 高级应用之SSL/TLS

    mosquitto提供SSL支持加密的网络连接和身份验证.本章节讲述次功能的实现. 在此之前需要一些准备工作. 准本工作: 一台 Linux 服务器. 安装好 openssl (不会明白怎么安装 op ...

  8. 开源项目SMSS发开指南(四)——SSL/TLS加密通信详解

    本文将详细介绍如何在Java端.C++端和NodeJs端实现基于SSL/TLS的加密通信,重点分析Java端利用SocketChannel和SSLEngine从握手到数据发送/接收的完整过程.本文也涵 ...

  9. 开源项目SMSS发开指南(五)——SSL/TLS加密通信详解(下)

    继上一篇介绍如何在多种语言之间使用SSL加密通信,今天我们关注Java端的证书创建以及支持SSL的NioSocket服务端开发.完整源码 一.创建keystore文件 网上大多数是通过jdk命令创建秘 ...

随机推荐

  1. mysql 创建存储过程报错

    在创建存储过程前把结束符定义为 delimiter // 然后再创建就不会报错

  2. Why is HttpContext.Current null after await?

    今天在对项目代码进行异步化改进的时候,遇到一个奇怪的问题(莫笑,以前没遇过),正如标题一样,HttpContext.Current 在 await 异步执行之后,就会变为 null. 演示代码: pu ...

  3. 「脑洞」图片转HTML(支持动画)

    也许是受到很久以前看到的这玩意儿的原因:The Shapes of CSS 现在开脑洞写了个自动转换,顺便支持了动画……嗯,纯 CSS (:з」∠) 主要步骤就是用 Python 读图片,然后把像素全 ...

  4. Tomcat中解决sql server连接失败--- java.lang.ClassNotFoundException: com.microsoft.jdbc.sqlserver.SQLServerDriver

    php连接mysql数据库很容易,他俩真是黄金搭档.最近转战java连接微软sqlServer,步骤稍微复杂一点,但也不是太难,中途遇到了一点小问题,最后在csdn论坛里找到了答案http://bbs ...

  5. ServletContextDemo

    1.servlet 之间共享数据 package xw.servlet; import javax.servlet.ServletContext; import javax.servlet.http. ...

  6. 上海洋码头(www.ymatou.com)急招技术人才(职位:互联网软件开发工程师,.NET网站架构师,Web前端开发工程师,高级测试工程师,产品经理)

    对公司招聘职位有兴趣的童鞋可以把简历发送到zhangzhiqiang@ymatou.com,我们HR会快速给你答复. 互联网软件开发工程师 岗位职责: 1.参与洋码头各个平台(www.ymatou.c ...

  7. easyui源码翻译1.32--SearchBox(搜索框)

    前言 使用$.fn.searchbox.defaults重写默认值对象.下载该插件翻译源码 搜索框提示用户需要输入搜索的值.它可以结合一个菜单,允许用户选择不同的搜索类别.在用户按下回车键或点击组件右 ...

  8. win7下配置IIS服务器方法

    网站爱好初学者必看的win7系统配置自己的IIS,可以在你自己的电脑上配置网站服务器发不到网上,下面就跟着我的步骤一起做吧100%成功. 步骤方法 1.点击开始-------控制面板这个就是打开的控制 ...

  9. DIV+CSS区块框浮动设计

    在页面布局的时候,能够用绝对定位来实现,可是因为调整某个区块框时其它区块的位置不会对应的改变,所以这并非布局的首选方式.可是使用浮动的区块框能够向左或向右移动,直到它的外边缘碰到包括它区块的边框或还有 ...

  10. java集合基础

    集合概念与作用 1现实生活中把很多事物凑在一起就是集合.java中的集合类:是一种工具,就像是容器,存储任意数量的有共同属性的对象. 2在类的内部,对数据进行组织: 简单而快速的搜索大数量的条目 有的 ...