java简述jvm工作原理理

博客分类:
今天被问到关于https原理的问题,结果由于知识掌握不牢靠,停留于表面,很多细节都无法回答清楚,于是决定把https的原理弄个明白,废话不多说,我们先看看https的定义
(由于很久未写博客,排版有些凌乱,请谅解)
一:什么是https协议
在说HTTPS之前先说说什么是HTTP,HTTP就是我们平时浏览网页时候使用的一种协议。HTTP协议传输的数据都是未加密的,也就是明文的,因此使 用HTTP协议传输隐私信息非常不安全。为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。SSL目前的版本是3.0,被IETF(Internet Engineering Task Force)定义在RFC 6101中,之后IETF对SSL 3.0进行了升级,于是出现了TLS(Transport Layer Security) 1.0,定义在RFC 2246。实际上我们现在的HTTPS都是用的TLS协议,但是由于SSL出现的时间比较早,并且依旧被现在浏览器所支持,因此SSL依然是HTTPS的 代名词,但无论是TLS还是SSL都是上个世纪的事情,SSL最后一个版本是3.0,今后TLS将会继承SSL优良血统继续为我们进行加密服务。目前 TLS的版本是1.2,定义在RFC 5246中,暂时还没有被广泛的使用。对历史感兴趣的朋友可以参考,这里有对TLS/SSL详尽的叙述。
二:https的工作原理是什么
HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握 手过程中将确立双方加密传输数据的密码信息,通常情况下会配合数字证书实现。
TLS/SSL协议不仅仅是一套加密传输的协议,更是一件经过艺术家精心设计的艺术品,TLS/SSL中使用 非对称加密,对称加密以及HASH算法。
这里我们先看看这上面提到的几种技术(如果你对这些技术已经非常了解,那么请跳过该段落,直接到段落三)
数字证书是一种权威性的电子文档,由权威公正的第三方机构,即CA中心签发的证书。它以数字证书为核心的加密技术可以对网络上传输的信息进行加密和解密、数字签名和签名验证,确保网上传递信息的机密性、完整性。 使用了数字证书,即使您发送的信息在网上被他人截获,甚至您丢失了个人的账户、密码等信息,仍可以保证您的账户、资金安全。
它能提供在Internet上进行身份验证的一种权威性电子文档,人们可以在互联网交往中用它来证明自己的身份和识别对方的身份。当然在数字证书认证的过程中证书认证中心(CA)作为权威的、公正的、可信赖的第三方,其作用是至关重要的.如何判断数字认证中心公正第三方的地位是权威可信的。VeriSign、GeoTrust、Thawte 是国际权威数字证书颁发认证机构的“三巨头”,其中,应用最广的为VerSign签发的电子商务数字证书。CER(Canonical Encoding Rules,规范编码格式) 是数字证书的一种编码格式,它是BER(Basic Encoding Rules 基本编码格式) 的一个变种,比BER 规定得更严格。后缀的证书文件有两种编码:DER(Distinguished Encoding Rule 卓越编码格式) 同样是BER的一个变种,DER使用定长模式。PKCS(Public-Key Cryptography Standards,公钥加密标准) 由RSA实验室和其他安全系统开发商为公钥密码的发展而制定的一系列标准。pfx是指以pkcs#12格式存储的证书和相应私钥。 在Security编程中,有几种典型的密码交换信息文件格式: DER-encoded certificate: .cer, .crt PEM-encoded message: .pem PKCS#12 Personal Information Exchange: .pfx, .p12 PKCS#10 Certification Request: .p10 .csrPKCS#7 cert request response: .p7r PKCS#7 binary message: .p7b .p7c .spccer/.crt 是用于存放证书,它是2进制形式存放pem 跟crt/cer的区别是它以Ascii来表示pfx/p12 用于存放个人证书/私钥,他通常包含保护密码,2进制方式 p10 .csr 是证书请求 p7r是CA对证书请求的回复,只用于导入 p7b .p7c .spc 以树状展示证书链(certificate chain),同时也支持单个证书,不含私钥
非对称加密算法
1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是"公开密钥系统"。相对于"对称加密算法"这种方法也叫做"非对称加密算法"。与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。甲方只能用其专用密钥解密由其公用密钥加密后的任何信息。非对称加密算法的保密性比较好,它消除了最终用户交换密钥的需要,但加密和解密花费时间长、速度慢,它不适合于对文件加密而只适用于对少量数据进行加密。 经典的非对称加密算法如RSA算法等安全性都相当高. 非对称加密的典型应用是数字签名。采用双钥密码系统的加密方法,在一个过程中使用两个密钥,一个用于加密,另一个用于解密,这种加密方法称为非对称加密,也称为公钥加密,因为其中一个密钥是公开的(另一个则需要保密)。
DH (Diffie-Hellman)
Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理。
RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
EL Gamal算法是公钥密码体制中的一种 ,在密码学中占有重要的地位。但该算法所采用的幂剩余计算耗时太多的问题 ,一直是制约其广泛应用的瓶颈问题。提出一种通过建表 ,以及对传统二进制算法进行改进 ,即将指数进行 2 k进制化 ,减少原 BR算法迭代次数 ,提高加密解密速度的算法。
ECC ECC (Elliptical Curve Cryptography,椭圆曲线加密)算法不椭圆曲线理论为基础,在创建密钥时可以更快,更小,并且更有效,它是用大质数的积来产生。
目前Java 6公提供了DH和RSA两种算法实现,通过Bouncy Castle可以实现Elmal算法支持,另ECC加密算法,目前没有开源组件提支持
对称加密算法
对加密和解密使用相同密钥的加密算法。由于其速度,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密。对称式数据加密的方式的工作原理如图。所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥实际上是一种算法,通信发送方使用这种算法加密数据,接收方再以同样的算法解密数据。因此对称式加密本身不是安全的。常用的对称加密有:
DES、IDEA、RC2、RC4、SKIPJACK算法等 。
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
常用的摘要算法包括MD5,SHA1,SHA256
消息摘要算法的特点:① 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。② 消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。③ 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。④ 消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。⑤ 好的摘要算法,无法找到两条消息,是它们的摘要相同。
消息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向Hash 函数将需加密 的明文"摘要"成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致 。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。
HASH函数的抗冲突性使得如果一段明文稍有变化,哪怕只更改该段落的一个字母,通过哈希算法作用后都将产生不同的值。而HASH算法的单向性使得要找到到哈希值相同的两个不 同的输入消息,在计算上是不可能的。所以数据的哈希值,即消息摘要,可以检验数据的完整性。哈希函数的这种对不同的输入能够生成不同的值的特性使得无法找到两个具有相同哈希值的输入。因此,如果两个文档经哈希转换后成为相同的值,就可以肯定它们是同一文档。 所以,当希望有效地比较两个数据块时,就可以比较它们的哈希值。例如,可以通过比较邮件发送前和发送后的哈希值来验证该邮件在传递时是否修改
消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在 密钥的管理与分发问题,适合于分布式网络相同上使用。由于其加密计算的工作量相当可观,所以以前的这种算法通常只用于数据量有限的情况下的加密,例如计算机的口令就是 用不可逆加密算法加密的。
三 https握手的过程详细描述
1.浏览器将自己支持的一套加密规则发送给网站,如RSA加密算法,DES对称加密算法,SHA1摘要算法2.网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息(证书中的私钥只能用于服务器端进行解密,在握手的整个过程中,都用到了证书中的公钥和浏览器发送给服务器的随机密码以及对称加密算法)
3.获得网站证书之后浏览器要做以下工作:
a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示。
b) 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥加密。
c) 使用约定好的HASH算法计算握手消息(如SHA1),并使用生成的随机数对消息进行加密,最后将之前生成的被公钥加密的随机数密码,HASH摘要值一起发送给服务器
4.网站接收浏览器发来的数据之后要做以下的操作:
a) 使用自己的私钥将信息解密并取出浏览器发送给服务器的随机密码,使用密码解密浏览器发来的握手消息,并验证HASH是否与浏览器发来的一致。
b) 使用随机密码加密一段握手消息,发送给浏览器。
5.浏览器解密并计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束,之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
从上面的4个大的步骤可以看到,握手的整个过程使用到了数字证书、对称加密、HASH摘要算法,接下来我们用实际代码来实现整个过程
四 使用java代码模拟整个握手过程
一:准备工作
1、创建java证书,
C:\& keytool -genkey -alias wangyi -keypass wangyi -keyalg RSA -keysize 1024 -keystore https.keystore -storepass wangyi
2、将创建的证书保存到C盘(为了方便演示)
C:\&keytool -export -keystore https.keystore -alias wangyi -file https.crt -storepass wangyi
二:代码实现
代码包含6个类,分别为:
CertifcateUtils
证书操作类
Des对称加密和解密工具类
HttpsMockBase
HttpsMockClient
HttpsMockServer
SocketUtils
socket工具类
import java.io.ByteArrayInputS
import java.io.FileInputS
import java.io.InputS
import java.security.KeyS
import java.security.PrivateK
import java.security.PublicK
import java.security.cert.CertificateF
* Created by kingj on .
public class CertifcateUtils {
public static byte[] readCertifacates() throws Exception{
CertificateFactory factory=CertificateFactory.getInstance("X.509");
InputStream in=new FileInputStream("c:/https.crt");
java.security.cert.Certificate cate=factory.generateCertificate(in);
return cate.getEncoded();
public static byte[] readPrivateKey() throws
Exception{
KeyStore store=KeyStore.getInstance("JKS");
InputStream in=new FileInputStream("c:/https.keystore");
store.load(in,"wangyi".toCharArray());
PrivateKey pk=(PrivateKey)store.getKey("wangyi","wangyi".toCharArray());
return pk.getEncoded();
public static PrivateKey readPrivateKeys() throws
Exception{
KeyStore store=KeyStore.getInstance("JKS");
InputStream in=new FileInputStream("c:/https.keystore");
store.load(in,"wangyi".toCharArray());
PrivateKey pk=(PrivateKey)store.getKey("wangyi","wangyi".toCharArray());
public static PublicKey readPublicKeys() throws
Exception{
CertificateFactory factory=CertificateFactory.getInstance("X.509");
InputStream in=new FileInputStream("c:/https.crt");
java.security.cert.Certificate cate=factory.generateCertificate(in);
return cate.getPublicKey();
public static
java.security.cert.Certificate createCertiface(byte b[]) throws Exception{
CertificateFactory factory=CertificateFactory.getInstance("X.509");
InputStream in=new ByteArrayInputStream(b);
java.security.cert.Certificate cate=factory.generateCertificate(in);
public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n & b. n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" +
return hs.toUpperCase();
* Created by kingj on .
import org.apache.commons.codec.binary.H
import java.security.K
import java.security.SecureR
import javax.crypto.C
import javax.crypto.KeyG
import javax.crypto.SecretK
import javax.crypto.SecretKeyF
import javax.crypto.spec.DESKeyS
* DES Coder&br/&
* secret key length: 56 bit, default: 56 bit&br/&
* mode: ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128&br/&
* padding: Nopadding/PKCS5Padding/ISO10126Padding/
* @author Aub
public class DesCoder {
* 密钥算法
private static final String KEY_ALGORITHM = "DES";
private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
// private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/ISO10126Padding";
* 初始化密钥
* @return byte[] 密钥
* @throws Exception
public static byte[] initSecretKey(SecureRandom random) throws Exception{
//返回生成指定算法的秘密密钥的 KeyGenerator 对象
KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//初始化此密钥生成器,使其具有确定的密钥大小
kg.init(random);
//生成一个密钥
secretKey = kg.generateKey();
return secretKey.getEncoded();
* 转换密钥
* @param key 二进制密钥
* @return Key 密钥
* @throws Exception
public static Key toKey(byte[] key) throws Exception{
//实例化DES密钥规则
DESKeySpec dks = new DESKeySpec(key);
//实例化密钥工厂
SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM);
//生成密钥
secretKey = skf.generateSecret(dks);
return secretK
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
* @throws Exception
public static byte[] encrypt(byte[] data,Key key) throws Exception{
return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
* @param data 待加密数据
* @param key 二进制密钥
* @return byte[] 加密数据
* @throws Exception
public static byte[] encrypt(byte[] data,byte[] key) throws Exception{
return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
* @param data 待加密数据
* @param key 二进制密钥
* @param cipherAlgorithm 加密算法/工作模式/填充方式
* @return byte[] 加密数据
* @throws Exception
public static byte[] encrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{
//还原密钥
Key k = toKey(key);
return encrypt(data, k, cipherAlgorithm);
* @param data 待加密数据
* @param key 密钥
* @param cipherAlgorithm 加密算法/工作模式/填充方式
* @return byte[] 加密数据
* @throws Exception
public static byte[] encrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
//使用密钥初始化,设置为加密模式
cipher.init(Cipher.ENCRYPT_MODE, key);
//执行操作
return cipher.doFinal(data);
* @param data 待解密数据
* @param key 二进制密钥
* @return byte[] 解密数据
* @throws Exception
public static byte[] decrypt(byte[] data,byte[] key) throws Exception{
return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
* @throws Exception
public static byte[] decrypt(byte[] data,Key key) throws Exception{
return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
* @param data 待解密数据
* @param key 二进制密钥
* @param cipherAlgorithm 加密算法/工作模式/填充方式
* @return byte[] 解密数据
* @throws Exception
public static byte[] decrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{
//还原密钥
Key k = toKey(key);
return decrypt(data, k, cipherAlgorithm);
* @param data 待解密数据
* @param key 密钥
* @param cipherAlgorithm 加密算法/工作模式/填充方式
* @return byte[] 解密数据
* @throws Exception
public static byte[] decrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{
Cipher cipher = Cipher.getInstance(cipherAlgorithm);
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, key);
//执行操作
return cipher.doFinal(data);
private static String
showByteArray(byte[] data){
if(null == data){
StringBuilder sb = new StringBuilder("{");
for(byte b:data){
sb.append(b).append(",");
sb.deleteCharAt(sb.length()-1);
sb.append("}");
return sb.toString();
import com.sun.org.apache.bcel.internal.generic.NEW;
import javax.crypto.*;
import javax.crypto.spec.DESKeyS
import java.security.*;
import java.security.spec.InvalidKeySpecE
import java.util.R
* Created by kingj on .
public class HttpsMockBase {
static PrivateKey privateK
static PublicKey publicK
public static boolean byteEquals(byte a[],byte[] b){
boolean equals=
if(a==null || b==null){
if(a!=null && b!=null){
if(a.length!=b.length){
for(int i=0;i&a.i++){
if(a[i]!=b[i]){
public static byte[] decrypt(byte data[]) throws Exception{
// 对数据解密
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
public static byte[] decrypt(byte data[],SecureRandom seed) throws Exception{
// 对数据解密
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey,seed);
return cipher.doFinal(data);
public static byte[] decryptByPublicKey(byte data[],SecureRandom seed) throws Exception{
if(publicKey==null){
publicKey=CertifcateUtils.readPublicKeys();
// 对数据解密
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
if(seed==null){
cipher.init(Cipher.DECRYPT_MODE, publicKey);
cipher.init(Cipher.DECRYPT_MODE, publicKey,seed);
return cipher.doFinal(data);
public static byte[] decryptByDes(byte data[],SecureRandom seed) throws Exception{
if(publicKey==null){
publicKey=CertifcateUtils.readPublicKeys();
// 对数据解密
Cipher cipher = Cipher.getInstance("DES");
if(seed==null){
cipher.init(Cipher.DECRYPT_MODE, publicKey);
cipher.init(Cipher.DECRYPT_MODE, publicKey,seed);
return cipher.doFinal(data);
public static byte[] encryptByPublicKey(byte[] data, SecureRandom seed)
throws Exception {
if(publicKey==null){
publicKey=CertifcateUtils.readPublicKeys();
// 对数据加密
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
if(seed==null){
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipher.init(Cipher.ENCRYPT_MODE, publicKey,seed);
return cipher.doFinal(data);
public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n & b. n++) {
stmp = (Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" +
hs = hs +"
return hs.toUpperCase();
public static byte[] cactHash(byte[] bytes) {
byte[] _bytes =
MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(bytes);
_bytes = md.digest();
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
static String random(){
StringBuilder builder=new StringBuilder();
Random random=new Random();
int seedLength=10;
for(int i=0;i&seedLi++){
builder.append(digits[random.nextInt(seedLength)]);
return builder.toString();
static char[] digits={
'0','1','2','3','4',
'5','6','7','8','9',
'a','b','c','d','e',
'f','g','h','i','j'
import java.io.DataInputS
import java.io.DataOutputS
import java.net.S
import java.security.K
import java.security.SecureR
* Created by kingj on .
public class HttpsMockClient extends
HttpsMockBase {
static DataInputS
static DataOutputS
public static void main(String args[]) throws
Exception{
int port=80;
Socket s=new Socket("localhost",port);
s.setReceiveBufferSize(102400);
s.setKeepAlive(true);
in=new DataInputStream(s.getInputStream());
out=new DataOutputStream(s.getOutputStream());
shakeHands();
System.out.println("------------------------------------------------------------------");
String name="duck";
writeBytes(name.getBytes());
int len=in.readInt();
byte[] msg=readBytes(len);
System.out.println("服务器反馈消息:"+byte2hex(msg));
Thread.sleep();
private static void shakeHands() throws Exception {
//第一步 客户端发送自己支持的hash算法
String supportHash="SHA1";
int length=supportHash.getBytes().
out.writeInt(length);
SocketUtils.writeBytes(out, supportHash.getBytes(), length);
//第二步 客户端验证服务器端证书是否合法
int skip=in.readInt();
byte[] certificate=SocketUtils.readBytes(in,skip);
java.security.cert.Certificate cc= CertifcateUtils.createCertiface(certificate);
publicKey=cc.getPublicKey();
cc.verify(publicKey);
System.out.println("客户端校验服务器端证书是否合法:" +true);
客户端校验服务器端发送过来的证书成功,生成随机数并用公钥加密
System.out.println("客户端校验服务器端发送过来的证书成功,生成随机数并用公钥加密");
SecureRandom seed=new SecureRandom();
int seedLength=2;
byte seedBytes[]=seed.generateSeed(seedLength);
System.out.println("生成的随机数为 : " + byte2hex(seedBytes));
System.out.println("将随机数用公钥加密后发送到服务器");
byte[] encrptedSeed=encryptByPublicKey(seedBytes, null);
SocketUtils.writeBytes(out,encrptedSeed,encrptedSeed.length);
System.out.println("加密后的seed值为 :" + byte2hex(encrptedSeed));
String message=random();
System.out.println("客户端生成消息为:"+message);
System.out.println("使用随机数并用公钥对消息加密");
byte[] encrpt=encryptByPublicKey(message.getBytes(),seed);
System.out.println("加密后消息位数为 : " +encrpt.length);
SocketUtils.writeBytes(out,encrpt,encrpt.length);
System.out.println("客户端使用SHA1计算消息摘要");
byte hash[]=cactHash(message.getBytes());
System.out.println("摘要信息为:"+byte2hex(hash));
System.out.println("消息加密完成,摘要计算完成,发送服务器");
SocketUtils.writeBytes(out,hash,hash.length);
System.out.println("客户端向服务器发送消息完成,开始接受服务器端发送回来的消息和摘要");
System.out.println("接受服务器端发送的消息");
int serverMessageLength=in.readInt();
byte[] serverMessage=SocketUtils.readBytes(in,serverMessageLength);
System.out.println("服务器端的消息内容为 :" + byte2hex(serverMessage));
System.out.println("开始用之前生成的随机密码和DES算法解密消息,密码为:"+byte2hex(seedBytes));
byte[] desKey= DesCoder.initSecretKey(new SecureRandom(seedBytes));
key=DesCoder.toKey(desKey);
byte[] decrpytedServerMsg=DesCoder.decrypt(serverMessage, key);
System.out.println("解密后的消息为:"+byte2hex(decrpytedServerMsg));
int serverHashLength=in.readInt();
byte[] serverHash=SocketUtils.readBytes(in,serverHashLength);
System.out.println("开始接受服务器端的摘要消息:"+byte2hex(serverHash));
byte[] serverHashValues=cactHash(decrpytedServerMsg);
System.out.println("计算服务器端发送过来的消息的摘要 : " +byte2hex(serverHashValues));
System.out.println("判断服务器端发送过来的hash摘要是否和计算出的摘要一致");
boolean isHashEquals=byteEquals(serverHashValues,serverHash);
if(isHashEquals){
System.out.println("验证完成,握手成功");
System.out.println("验证失败,握手失败");
public static byte[] readBytes(int length) throws
Exception{
byte[] undecrpty=SocketUtils.readBytes(in,length);
System.out.println("读取未解密消息:"+byte2hex(undecrpty));
return DesCoder.decrypt(undecrpty,key);
public static void writeBytes(byte[] data) throws
Exception{
byte[] encrpted=DesCoder.encrypt(data,key);
System.out.println("写入加密后消息:"+byte2hex(encrpted));
SocketUtils.writeBytes(out,encrpted,encrpted.length);
import javax.net.ServerSocketF
import java.io.DataInputS
import java.io.DataOutputS
import java.net.ServerS
import java.net.S
import java.security.K
import java.security.SecureR
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
* Created by kingj on .
public class HttpsMockServer extends HttpsMockBase {
static DataInputS
static DataOutputS
static ExecutorService executorService= Executors.newFixedThreadPool(20);
public static void main(String args[]) throws Exception{
int port=80;
ServerSocket ss= ServerSocketFactory.getDefault().createServerSocket(port);
ss.setReceiveBufferSize(102400);
ss.setReuseAddress(false);
while(true){
final Socket s = ss.accept();
doHttpsShakeHands(s);
executorService.execute(new Runnable() {
public void run() {
doSocketTransport(s);
}catch (Exception e){
e.printStackTrace();
private static void doSocketTransport(Socket s){
System.out.println("--------------------------------------------------------");
int length=in.readInt();
byte[] clientMsg=readBytes(length);
System.out.println("客户端指令内容为:" + byte2hex(clientMsg));
writeBytes("服务器已经接受请求".getBytes());
}catch (Exception ex){
ex.printStackTrace();
public static byte[] readBytes(int length) throws
Exception{
byte[] undecrpty=SocketUtils.readBytes(in,length);
System.out.println("读取未解密消息:"+byte2hex(undecrpty));
return DesCoder.decrypt(undecrpty,key);
public static void writeBytes(byte[] data) throws
Exception{
byte[] encrpted=DesCoder.encrypt(data,key);
System.out.println("写入加密后消息:"+byte2hex(encrpted));
SocketUtils.writeBytes(out,encrpted,encrpted.length);
private static void doHttpsShakeHands(Socket s) throws Exception {
in=new DataInputStream(s.getInputStream());
out=new DataOutputStream(s.getOutputStream());
//第一步 获取客户端发送的支持的验证规则,包括hash算法,这里选用SHA1作为hash
int length=in.readInt();
in.skipBytes(4);
byte[] clientSupportHash=SocketUtils.readBytes(in,length);
String clientHash=new String(clientSupportHash);
hash=clientH
System.out.println("客户端发送了hash算法为:"+clientHash);
//第二步,发送服务器证书到客户端
byte[] certificateBytes=CertifcateUtils.readCertifacates();
privateKey=CertifcateUtils.readPrivateKeys();
System.out.println("发送证书给客户端,字节长度为:"+certificateBytes.length);
System.out.println("证书内容为:" + byte2hex(certificateBytes));
SocketUtils.writeBytes(out, certificateBytes, certificateBytes.length);
System.out.println("获取客户端通过公钥加密后的随机数");
int secureByteLength=in.readInt();
byte[] secureBytes=SocketUtils.readBytes(in, secureByteLength);
System.out.println("读取到的客户端的随机数为:"+byte2hex(secureBytes));
byte secureSeed[]=decrypt(secureBytes);
System.out.println("解密后的随机数密码为:" +byte2hex(secureSeed));
//第三步 获取客户端加密字符串
int skip=in.readInt();
System.out.println("第三步 获取客户端加密消息,消息长度为 :" +skip);
byte[] data=SocketUtils.readBytes(in,skip);
System.out.println("客户端发送的加密消息为 : " +byte2hex(data));
System.out.println("用私钥对消息解密,并计算SHA1的hash值");
byte message[] =decrypt(data,new SecureRandom(secureBytes));
byte serverHash[]=cactHash(message);
System.out.println("获取客户端计算的SHA1摘要");
int hashSkip=in.readInt();
byte[] clientHashBytes=SocketUtils.readBytes(in,hashSkip);
System.out.println("客户端SHA1摘要为 : " + byte2hex(clientHashBytes));
System.out.println("开始比较客户端hash和服务器端从消息中计算的hash值是否一致");
boolean isHashEquals=byteEquals(serverHash,clientHashBytes);
System.out.println("是否一致结果为 : " + isHashEquals);
System.out.println("第一次校验客户端发送过来的消息和摘译一致,服务器开始向客户端发送消息和摘要");
System.out.println("生成密码用于加密服务器端消息,secureRandom : "+byte2hex(secureSeed));
SecureRandom secureRandom=new SecureRandom(secureSeed);
String randomMessage=random();
System.out.println("服务器端生成的随机消息为 : "+randomMessage);
System.out.println("用DES算法并使用客户端生成的随机密码对消息加密");
byte[] desKey=DesCoder.initSecretKey(secureRandom);
key=DesCoder.toKey(desKey);
byte serverMessage[]=DesCoder.encrypt(randomMessage.getBytes(), key);
SocketUtils.writeBytes(out,serverMessage,serverMessage.length);
System.out.println("服务器端发送的机密后的消息为:"+byte2hex(serverMessage)+",加密密码为:"+byte2hex(secureSeed));
System.out.println("服务器端开始计算hash摘要值");
byte serverMessageHash[]=cactHash(randomMessage.getBytes());
System.out.println("服务器端计算的hash摘要值为 :" +byte2hex(serverMessageHash));
SocketUtils.writeBytes(out,serverMessageHash,serverMessageHash.length);
System.out.println("握手成功,之后所有通信都将使用DES加密算法进行加密");
import java.io.ByteArrayInputS
import java.io.DataInputS
import java.io.DataOutputS
import java.io.IOE
import java.net.S
import java.util.A
* Created by kingj on .
public class SocketUtils {
public static void close(Socket s){
s.shutdownInput();
s.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
public static byte[] readBytes(DataInputStream in,int length) throws IOException {
byte[] data=new byte[length];
while(r&length){
r+=in.read(data,r,length-r);
public static void writeBytes(DataOutputStream out,byte[] bytes,int length) throws IOException{
out.writeInt(length);
out.write(bytes,0,length);
out.flush();
通过运行上述代码,我们可以看看服务器端和客户端控制台打印的消息记录(https握手完成后,整个过程数据传输都需要客户端和服务端使用约定的DES算法对数据进行加密和解密)
1、服务端消息记录
客户端发送了hash算法为:SHA1发送证书给客户端,字节长度为:618证书内容为:
E3获取客户端通过公钥加密后的随机数读取到的客户端的随机数为:
1E解密后的随机数密码为:
D4第三步 获取客户端加密消息,消息长度为 :128客户端发送的加密消息为 :
1E用私钥对消息解密,并计算SHA1的hash值获取客户端计算的SHA1摘要客户端SHA1摘要为 : 01
D8开始比较客户端hash和服务器端从消息中计算的hash值是否一致是否一致结果为 : true第一次校验客户端发送过来的消息和摘译一致,服务器开始向客户端发送消息和摘要生成密码用于加密服务器端消息,secureRandom :
(使用客户端第一次传过来的密码)服务器端生成的随机消息为 : 用DES算法并使用客户端生成的随机密码对消息加密服务器端发送的机密后的消息为:
1B,加密密码为:
(使用客户端第一次传过来的密码)服务器端开始计算hash摘要值服务器端计算的hash摘要值为 :
1402握手成功,之后所有通信都将使用DES加密算法进行加密--------------------------------------------------------读取未解密消息:
F5客户端指令内容为:
6B写入加密后消息:
2、客户端消息记录
客户端校验服务器端证书是否合法:true (校验证书)客户端校验服务器端发送过来的证书成功,生成随机数并用公钥加密生成的随机数为 :
(客户端生成了随机密码,用于整个握手过程中)将随机数用公钥加密后发送到服务器加密后的seed值为 :
1E客户端生成消息为:使用随机数并用公钥对消息加密加密后消息位数为 : 128客户端使用SHA1计算消息摘要摘要信息为:01
D8消息加密完成,摘要计算完成,发送服务器客户端向服务器发送消息完成,开始接受服务器端发送回来的消息和摘要接受服务器端发送的消息服务器端的消息内容为 :
1B开始用之前生成的随机密码和DES算法解密消息,密码为:
D4解密后的消息为:
39开始接受服务器端的摘要消息:
1402计算服务器端发送过来的消息的摘要 :
1402判断服务器端发送过来的hash摘要是否和计算出的摘要一致验证完成,握手成功------------------------------------------------------------------写入加密后消息:
F5读取未解密消息:
D8服务器反馈消息:
下载次数: 786
浏览 53643
浏览: 335243 次
来自: 成都
如果是使用http client请求https的接口,http ...
看了半天,真的是半天,总算是把这些概念都理清了,谢谢博主
请问下,在内外层事务均是REQUIRED的情况下,内层事务抛出 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 java原理 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信