java 通过SSL/TLS加密https建立连接
这个项目是基于与Ruby客户端进行通信,经过查看源代码,发现对方是经过TLS加密通信。第一次调试,尝试用serversocket与对方进行沟通,可以收到数据,但是无法获取http的包头数据,因此,将先对socket通信进行处理。
一、根据原有软件进行沟通,可以找到原来生成的rcs-db.key、rcs-db.crt文件,可知rcs-db.crt为证书,rcs-db.key为秘钥。因为并没有任何思路来处理这两个文件,我就先打开看一看。发现秘钥的内容如下:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDBajNHgexQbClBGOxJgTkevfZU4R/OmI2BZUgt3DD4RNO4cXtG
...........................................................................
-----END RSA PRIVATE KEY-----
可知使用的是RSA公钥加密算法。并且根据源码可知,是用OpenSSL加密的。开始我就根据http://blog.csdn.net/chaijunkun/article/details/7275632/这篇文章所讲将公钥和私钥都解了出来,可是并不知道怎么去使用。
然后查了一下,要通过一下步骤可以将key和certificate应用在Java里面。
安装好openssl。
首先将.key、crt文件转换成.jks文件及一对公私钥存储在新建的PKCS12 keystore中。
# Create PKCS12 keystore from private key and public certificate.
openssl pkcs12 -export -name myservercert -in selfsigned.crt -inkey server.key -out keystore.p12# Convert PKCS12 keystore into a JKS keystore
keytool -importkeystore -destkeystore mykeystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -alias myservercert
然后可以用这个命令来查看keystore中的jks。注意这里我们将jks的别名起为myservercert。crt,p12记得加上地址。
keytool -list -v -keystore mykeystore.jks
但是要保证是自签证的证书,否则需要按此步骤顺着证书链找到可信赖的证书。
相关概念:Keytool 是一个有效的安全钥匙和证书的管理工具。Java 中的 keytool.exe (位于 JDK\Bin 目录下)可以用来创建数字证书,所有的数字证书是以一条一条(采用别名区别)的形式存入证书库的中,证书库中的一条证书包含该条证书的私钥,公钥和对应的数字证书的信息。证书库中的一条证书可以导出数字证书文件,数字证书文件只包括主体信息和对应的公钥。 Keytool 把钥匙和证书储存到一个keystore.默任的实现keystore的是一个文件.它用一个密码保护钥匙。
因为是需要双向认证的,因此我们需要生成truststore。JSSE使用Truststore和Keystore文件来提供客户端和服务器之间的安全数据传输。keytool是一个工具可以用来创建包含公钥和密钥的的keystore文件,并且利用keystore文件来创建只包含公钥的truststore文件。我们通过下面的5步简单的创建truststore和keystore文件:
生成一个含有一个私钥的keystore文件
验证新生成的keystor而文件
导出凭证文件
把认凭证件导入到truststore文件
验证新创建的truststore文件
导出凭证文件 在这一步,你可以导出自我签署凭证或是Verisign或其他的认证机构的商业凭证的。这里只说导出自我签署的凭证: 通过执行下面的命令把自我签署的凭证保存到 “selfsignedcert.cer”文件 :
keytool -export -alias certificatekey -keystore keystore.jks -rfc -file selfsignedcert.cer
把认凭证件导入到truststore文件 执行下面的命令:
keytool -import -alias myservercert -file selfsignedcert.cer -keystore truststore.jks
最后验证新创建的truststore文件 执行下面的命令 :
keytool -list -v -keystore truststore.jks
二、至此,我们已经将Truststore和Keystore全部倒入keytool中了。因为我需要解析包头。全部的代码如下:
package com.cms.listener;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.StringTokenizer;import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;/*** Application Lifecycle Listener implementation class WorkerListener**/
public class WorkerListener implements ServletContextListener {//调用线程池ApplicationContext ctx = new ClassPathXmlApplicationContext("config/spring/applicationContext.xml"); ThreadPoolTaskExecutor taskExecutor = (ThreadPoolTaskExecutor)ctx.getBean("taskExecutor");//定义端口号public static final int SERVER_PORT = 442; /*** @see ServletContextListener#contextDestroyed(ServletContextEvent)*/public void contextDestroyed(ServletContextEvent arg0) { // TODO Auto-generated method stub}/*** @see ServletContextListener#contextInitialized(ServletContextEvent)*/public void contextInitialized(ServletContextEvent arg0) { // TODO Auto-generated method stubtry { String serverKeyStoreFile = "c:\\Windows\\System32\\mykeystore.jks"; String serverKeyStorePwd = "changeit"; String catServerKeyPwd = "changeit"; String serverTrustKeyStoreFile = "c:\\RCS\\DB\\config\\certs\\truststore.jks"; String serverTrustKeyStorePwd = "changeit"; KeyStore serverKeyStore = KeyStore.getInstance("JKS"); serverKeyStore.load(new FileInputStream(serverKeyStoreFile), serverKeyStorePwd.toCharArray()); KeyStore serverTrustKeyStore = KeyStore.getInstance("JKS"); serverTrustKeyStore.load(new FileInputStream(serverTrustKeyStoreFile), serverTrustKeyStorePwd.toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(serverKeyStore, catServerKeyPwd.toCharArray()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(serverTrustKeyStore); SSLContext sslContext = SSLContext.getInstance("TLSv1"); //第二个参数TrustManager[] 是认证管理器,在需要双向认证时使用sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(SERVER_PORT); //sslServerSocket.setNeedClientAuth(true); while (true) { SSLSocket s = (SSLSocket)sslServerSocket.accept(); Accepter accepter = new Accepter(s);accepter.service();} } catch (Exception e) { e.printStackTrace(); System.exit(1); } }class Accepter { private SSLSocket socket; public Accepter(SSLSocket socket) { this.socket = socket; System.out.println("连接到服务器的用户:" + socket);} public void service() { taskExecutor.execute(new Runnable() {public void run() {//这里编写处理业务代码synchronized (this) {try { // 第一阶段: 打开输入流 InputStream is = socket.getInputStream(); System.out.println("客户端发送的请求信息: >>>>>>>>>>>>>>>>>>>>>>>>>"); // 读取第一行, 请求地址 String line = readLine(is, 0);//打印请求行 System.out.print(line); // < Method > < URL > < HTTP Version > <\r\n> 取的是URL部分 String line2 = line;String httpversion = line2.substring(line2.length()-10).trim();httpversion = URLDecoder.decode(httpversion, "UTF-8");//反编码 URL 地址 String resource = line.substring(line.indexOf('/'), line.lastIndexOf('/') - 5); //获得请求的资源的地址 resource = URLDecoder.decode(resource, "UTF-8");//反编码 URL 地址 String method = new StringTokenizer(line).nextElement().toString();// 获取请求方法, GET 或者 POST int contentLength = 0;//如果为POST方法,则会有消息体长度 // 读取所有浏览器发送过来的请求参数头部信息 do { line = readLine(is, 0); //如果有Content-Length消息头时取出 if (line.startsWith("Content-Length")) { contentLength = Integer.parseInt(line.split(":")[1].trim()); } //打印请求部信息 System.out.print(line); //如果遇到了一个单独的回车换行,则表示请求头结束 } while (!line.equals("\r\n")); //如果是POST请求,则有请求体 if ("POST".equalsIgnoreCase(method)) { //注,这里只是简单的处理表单提交的参数,而对于上传文件这里是不能这样处理的, //因为上传的文件时消息体不只是一行,会有多行消息体 System.out.print(readLine(is, contentLength)); System.out.println(); } System.out.println("客户端发送的请求信息结束 <<<<<<<<<<<<<<<<<<<<<<<<<<"); System.out.println("用户请求的资源是(uri):" + resource); System.out.println("请求的类型是: " + method); System.out.println("请求的http版本是: " + httpversion); System.out.println("连接到服务器的用户:" + socket.getRemoteSocketAddress());} catch (Exception e) { // replace with other code e.printStackTrace(); } }}});} }
/* 这里我们自己模拟读取一行,因为如果使用API中的BufferedReader时,它是读取到一个回车换行后 才返回,否则如果没有读取,则一直阻塞,这就导致如果为POST请求时,表单中的元素会以消息体传送, 这时,消息体最末按标准是没有回车换行的,如果此时还使用BufferedReader来读时,则POST提交 时会阻塞。如果是POST提交时我们按照消息体的长度Content-Length来截取消息体,这样就不会阻塞 */private String readLine(InputStream is, int contentLe) throws IOException { ArrayList lineByteList = new ArrayList(); byte readByte; int total = 0; if (contentLe != 0) { do { readByte = (byte) is.read(); lineByteList.add(Byte.valueOf(readByte)); total++; } while (total < contentLe);//消息体读还未读完 } else { do { readByte = (byte) is.read(); lineByteList.add(Byte.valueOf(readByte)); } while (readByte != 10); } byte[] tmpByteArr = new byte[lineByteList.size()]; for (int i = 0; i < lineByteList.size(); i++) { tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue(); } lineByteList.clear(); String tmpStr = new String(tmpByteArr, "UTF-8");
/* http请求的header中有一个Referer属性,这个属性的意思就是如果当前请求是从别的页面链接过 来的,那个属性就是那个页面的url,如果请求的url是直接从浏览器地址栏输入的就没有这个值。得 到这个值可以实现很多有用的功能,例如防盗链,记录访问来源以及记住刚才访问的链接等。另外,浏 览器发送这个Referer链接时好像固定用UTF-8编码的,所以在GBK下出现乱码,我们在这里纠正一下 */if (tmpStr.startsWith("Referer")) {//如果有Referer头时,使用UTF-8编码 tmpStr = new String(tmpByteArr, "UTF-8"); } return tmpStr; }
}
java 通过SSL/TLS加密https建立连接相关推荐
- 解决Error基础连接已经关闭: 未能为SSL/TLS 安全通道建立信任关系
今天写程序的时候调用到一个第三方的DLL文件,本机调试一切都正常,但是程序不是到服务器以后一直提示一个BUG:"基础连接已经关闭: 未能为SSL/TLS 安全通道建立信任关系". ...
- C#运行出现:基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。
英文:The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secu ...
- C#Post接口报错信息:基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系--安全证书问题 解决方法
目录 一.说明: 二.错误信息: 三.解决方法 1.引用命名空间: 2.添加接收方法(CheckValidationResult): 3.post方法里面增加调用:CheckValidationRes ...
- HTTPS 建立连接的详细过程
目录 原文链接:HTTPS 建立连接的详细过程 - cccc_hi - 博客园 简介 对称加密和非对称加密 建立连接 tcp的三次挥手和四次挥手 HTTP请求过程 HTTPS 原文链接:HTTPS 建 ...
- 开源项目SMSS发开指南(四)——SSL/TLS加密通信详解
本文将详细介绍如何在Java端.C++端和NodeJs端实现基于SSL/TLS的加密通信,重点分析Java端利用SocketChannel和SSLEngine从握手到数据发送/接收的完整过程.本文也涵 ...
- 第四篇:网络安全,SSL/TLS加密技术
文章目录 一.前言 二.SSL/TLS 2.1 SSL/TLS是什么 2.2 SSL/TLS加密基本原理 2.3 SSL/TLS建立握手过程 三.CA & SSL Server & S ...
- 使用openssl进行ssl/tls加密传输会话测试
[小蜗牛嘻哈之作] 我们首先看看下面一段"对话": [root@pps ~]# openssl s_client -connect localhost:110 -starttls ...
- SSL TLS HTTP HTTPS SSH 分别是什么意思?
HTTP + SSL/TLS = HTTPS SSL(Secure Sockets Layer,安全套接字协议) TLS(Transport Layer Security,传输层安全协议) HTTP( ...
- https 中的SSL/TLS 加密
其实HTTPS从最终的数据解析的角度,与HTTP没有任何的区别,HTTPS就是将HTTP协议数据包放到SSL/TSL层加密后,在TCP/IP层组成IP数据报去传输,以此保证传输数据的安全:而对于接收端 ...
最新文章
- day060 ajax文件上传 json补充
- npm nodejs包管理工具 简介
- linux工科软件,linux基础网络工具学习笔记
- java集合——遗留的集合
- Linux namespace概述
- 【体系结构】Oracle如何保证提交的数据不丢失
- dozer无法映射java8中的LocalDateTime类型的解决方案
- zabbix_get查看agent端的key值提示没有权限:Permission denied
- MySQL服务 - 客户端工具mysql及mysqladmin使用介绍
- as本地仓库更改_如何将源仓库的更改同步到fork仓库?
- 中巨伟业加密芯片—SMEC98SP (SE98)在产品授权生产防复制的应用方法
- openid与商户appid不匹配
- java 新浪短链接_如何通过Java调用新浪短网址官方API接口实现短网址缩短功能
- EDK环境搭建UEFI工程模块文件介绍
- WireShark黑客发现之旅(5)—扫描探测
- 0320-复利计算器代码
- phpStudy配置站点解决各种不能访问问题(本地可www.xx.com访问)
- 慧荣SM2246主控固态硬盘开卡一直pretest解决方法
- 如何开启APP2SD功能
- LeetCode4.python实现:寻找两个有序数组中的中位数问题☆☆☆