HTTPS java6实现过程

一、知识预热

我这里就不在赘述https的原理了,网上已经有很好的文章,列表如下:

1、握手过程

HTTPS那些事儿(一)-实例分析:http://blog.youkuaiyun.com/sgbfblog/article/details/28180759

HTTPS那些事儿(二)-实例分析:http://blog.youkuaiyun.com/sgbfblog/article/details/30748177

2、握手报文示例

http://blog.youkuaiyun.com/tterminator/article/details/50675540

3、证书编码格式

http://blog.sina.com.cn/s/blog_7cd471930102x2kl.html


二、https java6如何实现?下面正式进入主题,开讲啦!

我建立一个名称为test的java web工程,index.jsp内容如下:

<html>
<head>
<title>test</title>
</head>
<body>
Hello World!
</body>
</html>

我打好war包放到tomcat应用服务器的webapps目录,tomcat的访问端口是8080,启动tomcat,在浏览器的地址栏输入:http://127.0.0.1:8080/test/index.jsp,就会显示一个这样页面:

那好,到底服务器返回什么数据给浏览器呢?

我们来还原真相!

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class test {
    public static void main(String[] args){
        try {
            URL url = new URL("http://127.0.0.1:8080/test/index.jsp");
            HttpURLConnection connection = (HttpURLConnection)url.openConnection();
            connection.connect();
            InputStream input = connection.getInputStream();
            byte[] bytes = new byte[1024];// index.jsp页面字节数远远小于1024
            int bytesLength = input.read(bytes);
            System.out.println("服务器返回:\n" + new String(bytes, 0, bytesLength));
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
我们运行一下这段代码,console输出:
服务器返回:
<html>
<head>
<title>test</title>
</head>
<body>
Hello World!
</body>
</html>
上面其实并不是完整的服务器返回给浏览器的内容,被我们输出的只是http报文体,但这并不重要!重要的是,我如果是用https的访问方式:https://127.0.0.1:8080/test/index.jsp,跟http的不同到底在哪里?
其实区别我们早就知道了,http服务器返回的数据没有加密,https服务器返回的数据有加密,就这么简单!
这里稍微补充一下加密知识(因为https都用到了下面这几种,不得不讲啊):
1、对称加密
加解密用同一把秘钥,数据用秘钥加密,就得用这把秘钥解密,这就是所谓的“对称”,比如:des、aes;
https使用对称加密方式加密http报文内容
2、非对称加密
秘钥是一对,数据用其中一把加密,就得用另一把解密,这就是所谓的“不对称”,比如:rsa;
https使用非对称加密来传输对称秘钥
3、摘要算法
不需要秘钥,数据经过摘要计算之后,生成一个固定长度的摘要值,比如:md5、sha;
https使用摘要算法,用来验证数据完整性
 
那好,https返回的数据是加密的(而且是对称加密)我们说了好几遍了,那就意味着,浏览器如果要知道服务器返回加密数据的原文(明文),双方在加密数据之前,需要确认对称加密的算法(des?aes?还是...)和对称密钥。
这个确认的过程,他们说是握手。
为了能看到这个握手的过程,需要tomcat配置支持https访问,用keytool生成一个秘钥库,在tomcat server.xml配置8443 Connector秘钥库地址,这个网上有现成的教程,这里不再赘述!
我们稍微改一下前面贴的代码:
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.InputStream;
import java.net.URL;

public class test {
    public static void main(String[] args){
        System.setProperty("javax.net.debug", "all");// 输出https握手过程
        System.setProperty("javax.net.ssl.trustStore", "e:/tomcat.keystore");// 值配置成与tomcat keyStoreFile一致,服务器发过来的证书,要存在于信任秘钥库中
        System.setProperty("javax.net.ssl.trustStorePassword", "123456");// 信任秘钥库密码
        System.setProperty("https.protocols", "TLSv1");// https协议版本
        try {
            URL url = new URL("https://127.0.0.1:8443/test/index.jsp");
            HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
            connection.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;// 证书里面有个扩展域,记录了服务器ip,如果与访问url里面的ip不一致不报错(其实是因为用keytool生成的证书,并没有这个扩展域)
                }
            });
            connection.connect();
            InputStream input = connection.getInputStream();
            byte[] bytes = new byte[1024];
            int bytesLength = input.read(bytes);
            System.out.println("服务器返回:\n" + new String(bytes, 0, bytesLength));
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
console输出了一大堆!天啦噜,鬼知道这些东西是什么啊?不急,听我慢慢给你道来......
我们先关注一下[Raw write]和[Raw read],我们和tomcat服务器之间建立socket连接之后,Raw write是我们写给服务器的字节内容,Raw read是服务器返回给我们的字节内容。
https报文格式:消息类型(第1字节),版本号(第2~3字节),消息体长度(第4~5字节),消息体(消息体长度个字节)
按顺序来看,我本地第一条是这样的:
[Raw write]: length = 80
0000: 16 03 01 00 4B 01 00 00   47 03 01 59 31 23 36 1F  ....K...G..Y1#6.
0010: 6C CC 70 97 E1 24 CD FA   0C 5D 27 5C A9 4C AF 49  l.p..$...]'\.L.I
0020: 2E 23 0F 35 00 4E 51 94   48 7E 99 00 00 20 00 04  .#.5.NQ.H.... ..
0030: 00 05 00 2F 00 33 00 32   00 0A 00 16 00 13 00 09  .../.3.2........
0040: 00 15 00 12 00 03 00 08   00 14 00 11 00 FF 01 00  ................
客户端消息的意思是这样的:
16 		->消息类型(1字节):握手
0301	->版本号(2字节):TLS 1.0
004B	->消息体长度(2字节):75字节
01 		->握手类型(1字节):client hello
000047 ->握手消息体长度(3字节):71字节
0301 	->版本号(2字节):TLS 1.0
593123361F6CCC7097E124CDFA0C5D275CA94CAF492E230F35004E5194487E99 ->秘钥随机数(32字节:4字节时间戳(秒) + 28字节随机数)
00		->会话SESSION ID长度(1字节):0字节
0020	->加密套件列表长度(2字节):32字节
0004	->SSL_RSA_WITH_RC4_128_MD5             
0005    ->SSL_RSA_WITH_RC4_128_SHA             
002F    ->TLS_RSA_WITH_AES_128_CBC_SHA         
0033    ->TLS_DHE_RSA_WITH_AES_128_CBC_SHA     
0032    ->TLS_DHE_DSS_WITH_AES_128_CBC_SHA     
000A    ->SSL_RSA_WITH_3DES_EDE_CBC_SHA        
0016    ->SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA    
0013    ->SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA    
0009    ->SSL_RSA_WITH_DES_CBC_SHA             
0015    ->SSL_DHE_RSA_WITH_DES_CBC_SHA         
0012    ->SSL_DHE_DSS_WITH_DES_CBC_SHA         
0003    ->SSL_RSA_EXPORT_WITH_RC4_40_MD5       
0008    ->SSL_RSA_EXPORT_WITH_DES40_CBC_SHA    
0014    ->SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
0011    ->SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
00FF    ->TLS_EMPTY_RENEGOTIATION_INFO_SCSV    
01	->压缩算法长度(1字节)
00	->压缩算法:0(NULL)
简言之:服务器你好,我把我支持的加密套件列表发给你了,你挑一个吧,我的秘钥随机数也发给你了,你先记着哦。
接着服务器回答了:
[Raw read]: length = 5
0000: 16 03 01 02 B5                                     .....
[Raw read]: length = 693
0000: 02 00 00 46 03 01 59 31   23 36 33 44 92 7B 7F CC  ...F..Y1#63D....
0010: CB FB 17 E0 DE BF AD 60   25 60 F2 7A 2B F2 86 A9  .......`%`.z+...
0020: 61 C3 81 57 A9 33 20 59   31 23 36 72 75 A3 D9 76  a..W.3 Y1#6ru..v
0030: 14 30 20 DE 26 5E 22 9A   A9 17 CC 25 37 15 82 FA  .0 .&^"....%7...
0040: BD BA 6E 08 77 C1 EE 00   2F 00 0B 00 02 63 00 02  ..n.w.../....c..
0050: 60 00 02 5D 30 82 02 59   30 82 01 C2 A0 03 02 01  `..]0..Y0.......
0060: 02 02 04 58 9D 62 4B 30   0D 06 09 2A 86 48 86 F7  ...X.bK0...*.H..
0070: 0D 01 01 05 05 00 30 71   31 0B 30 09 06 03 55 04  ......0q1.0...U.
0080: 06 13 02 43 4E 31 12 30   10 06 03 55 04 08 13 09  ...CN1.0...U....
0090: 31 32 37 2E 30 2E 30 2E   31 31 12 30 10 06 03 55  127.0.0.11.0...U
00A0: 04 07 13 09 31 32 37 2E   30 2E 30 2E 31 31 12 30  ....127.0.0.11.0
00B0: 10 06 03 55 04 0A 13 09   31 32 37 2E 30 2E 30 2E  ...U....127.0.0.
00C0: 31 31 12 30 10 06 03 55   04 0B 13 09 31 32 37 2E  11.0...U....127.
00D0: 30 2E 30 2E 31 31 12 30   10 06 03 55 04 03 13 09  0.0.11.0...U....
00E0: 31 32 37 2E 30 2E 30 2E   31 30 1E 17 0D 31 37 30  127.0.0.10...170
00F0: 32 31 30 30 36 34 38 34   33 5A 17 0D 31 37 30 35  210064843Z..1705
0100: 31 31 30 36 34 38 34 33   5A 30 71 31 0B 30 09 06  11064843Z0q1.0..
0110: 03 55 04 06 13 02 43 4E   31 12 30 10 06 03 55 04  .U....CN1.0...U.
0120: 08 13 09 31 32 37 2E 30   2E 30 2E 31 31 12 30 10  ...127.0.0.11.0.
0130: 06 03 55 04 07 13 09 31   32 37 2E 30 2E 30 2E 31  ..U....127.0.0.1
0140: 31 12 30 10 06 03 55 04   0A 13 09 31 32 37 2E 30  1.0...U....127.0
0150: 2E 30 2E 31 31 12 30 10   06 03 55 04 0B 13 09 31  .0.11.0...U....1
0160: 32 37 2E 30 2E 30 2E 31   31 12 30 10 06 03 55 04  27.0.0.11.0...U.
0170: 03 13 09 31 32 37 2E 30   2E 30 2E 31 30 81 9F 30  ...127.0.0.10..0
0180: 0D 06 09 2A 86 48 86 F7   0D 01 01 01 05 00 03 81  ...*.H..........
0190: 8D 00 30 81 89 02 81 81   00 C2 4E 1F 32 7B F7 65  ..0.......N.2..e
01A0: 43 BB 8C A6 70 A5 C6 86   07 C6 B9 1C F0 74 BF EB  C...p........t..
01B0: CE 44 A4 1D 54 A8 73 6F   8C 4D 6E C8 89 8F 75 33  .D..T.so.Mn...u3
01C0: C5 06 45 7F F6 EA 9F F6   40 15 27 CD 1F 2B 34 D0  ..E.....@.'..+4.
01D0: 3F EF DF F7 A7 82 E7 5A   0D 46 01 31 2E 47 1E D2  ?......Z.F.1.G..
01E0: 32 05 E3 DE 15 4E 96 79   C2 4A F3 83 43 E7 0D B0  2....N.y.J..C...
01F0: 8B EA D1 86 81 73 56 DC   56 48 B0 70 04 18 72 5B  .....sV.VH.p..r[
0200: A7 D5 AB B7 32 B3 5E DF   33 29 9B B8 29 28 F5 E4  ....2.^.3)..)(..
0210: AB 4B 03 13 D3 1A 2C F2   ED 02 03 01 00 01 30 0D  .K....,.......0.
0220: 06 09 2A 86 48 86 F7 0D   01 01 05 05 00 03 81 81  ..*.H...........
0230: 00 0E AC A0 C9 52 D4 50   84 A3 42 C3 99 92 28 87  .....R.P..B...(.
0240: 17 0B 2B E3 61 F1 54 AE   65 16 89 0D B7 73 42 D0  ..+.a.T.e....sB.
0250: 4B 2D D6 CE 5E 2C 71 45   B6 43 3E A9 09 AA 48 4D  K-..^,qE.C>...HM
0260: 9B 10 AF 89 E6 EF C2 19   92 C1 88 6D F5 56 64 12  ...........m.Vd.
0270: BC 0E 3D D6 B0 D2 17 7D   4F D4 CF A3 43 63 65 4D  ..=.....O...CceM
0280: AA 7D C4 CD 7C FA 44 33   AC F8 10 00 6B 07 7B 6C  ......D3....k..l
0290: BA C6 6F 81 84 A0 D4 0C   F9 A0 0F 86 90 77 6D CE  ..o..........wm.
02A0: D4 79 96 B6 B5 01 1E 66   21 9A 45 E2 DA F0 29 E6  .y.....f!.E...).
02B0: 62 0E 00 00 00                                     b....
服务器消息的意思如下:
16	->消息类型(1字节):握手           
0301    ->版本号(2字节):TLS 1.0          
02B5    ->消息体长度(2字节):693字节      
02      ->握手类型(1字节):Server Hello    
000046  ->握手消息体长度(3字节):70字节      
0301	->版本号(2字节):TLS 1.0
593123363344927B7FCCCBFB17E0DEBFAD602560F27A2BF286A961C38157A933 ->秘钥随机数(32字节:4字节时间戳(秒) + 28字节随机数)
20	->会话SESSION ID长度(1字节):32字节
593123367275A3D976143020DE265E229AA917CC25371582FABDBA6E0877C1EE ->会话SESSION ID
002F	->加密套件:TLS_RSA_WITH_AES_128_CBC_SHA
00	->压缩算法:0(NULL)
0B	->握手类型(1字节):certificate
000263	->握手消息体长度(3字节):611字节
000260	->证书消息长度(3字节):608字节
00025D	->证书长度(3字节):605字节
30820259308201C2A0030201020204589D624B300D06092A864886F70D01010505003071310B300906035504061302434E31123010060355040813093132372E302E302E3131123010060355040713093132372E302E302E3131123010060355040A13093132372E302E302E3131123010060355040B13093132372E302E302E3131123010060355040313093132372E302E302E31301E170D3137303231303036343834335A170D3137303531313036343834335A3071310B300906035504061302434E31123010060355040813093132372E302E302E3131123010060355040713093132372E302E302E3131123010060355040A13093132372E302E302E3131123010060355040B13093132372E302E302E3131123010060355040313093132372E302E302E3130819F300D06092A864886F70D010101050003818D0030818902818100C24E1F327BF76543BB8CA670A5C68607C6B91CF074BFEBCE44A41D54A8736F8C4D6EC8898F7533C506457FF6EA9FF6401527CD1F2B34D03FEFDFF7A782E75A0D4601312E471ED23205E3DE154E9679C24AF38343E70DB08BEAD186817356DC5648B0700418725BA7D5ABB732B35EDF33299BB82928F5E4AB4B0313D31A2CF2ED0203010001300D06092A864886F70D0101050500038181000EACA0C952D45084A342C399922887170B2BE361F154AE6516890DB77342D04B2DD6CE5E2C7145B6433EA909AA484D9B10AF89E6EFC21992C1886DF5566412BC0E3DD6B0D2177D4FD4CFA34363654DAA7DC4CD7CFA4433ACF810006B077B6CBAC66F8184A0D40CF9A00F8690776DCED47996B6B5011E66219A45E2DAF029E662 ->证书
0E	->握手类型(1字节):server_hello_done
000000	->握手消息体长度(3字节):0字节
服务端说了三句话,简言之:
1、客户端你好!我从你的列表挑了这个加密套件:TLS_RSA_WITH_AES_128_CBC_SHA,我们的非对称用RSA,对称用AES,摘要算法用SHA,我的秘钥随机数也发给你了,你也记着哦。
2、我把证书发给你了,你看一下
3、我说完了
这时候,客户端说了一句:
[Raw write]: length = 139
0000: 16 03 01 00 86 10 00 00   82 00 80 BA 28 87 10 7E  ............(...
0010: 63 72 06 4B 5E 16 C8 53   FD 1A 7A 65 46 DD D1 4D  cr.K^..S..zeF..M
0020: 3E 95 88 89 F4 40 E4 5C   DF 51 F7 2C A2 5C AD 6D  >....@.\.Q.,.\.m
0030: A3 A1 08 3B F0 5E 0C 88   64 B3 1D F8 34 67 7B 49  ...;.^..d...4g.I
0040: F6 5F 67 0A FB 3F 54 1F   24 AF 43 DD A6 BB 4B 1E  ._g..?T.$.C...K.
0050: 3D D6 DC 63 92 75 61 40   D2 3A E0 66 74 80 D0 B6  =..c.ua@.:.ft...
0060: E6 31 7D AA CA BB 8D 40   6B 45 97 80 81 D6 31 A6  .1.....@kE....1.
0070: 0C DF BF 7B 60 E4 9E E8   D2 09 C0 2E 68 14 EB B4  ....`.......h...
0080: 27 72 FF CC 5F F9 94 3E   FB 90 FC                 'r.._..>...
这个客户端消息的意思是:
16	->消息类型(1字节):握手
0301	->版本号(2字节):TLS 1.0 
0086	->消息体长度(2字节):134字节
10	->握手类型(1字节):ClientKeyExchange
000082	->握手消息体长度(3字节):130字节
0080	->秘钥长度(3字节):128字节
BA2887107E6372064B5E16C853FD1A7A6546DDD14D3E958889F440E45CDF51F72CA25CAD6DA3A1083BF05E0C8864B31DF834677B49F65F670AFB3F541F24AF43DDA6BB4B1E3DD6DC6392756140D23AE0667480D0B6E6317DAACABB8D406B45978081D631A60CDFBF7B60E49EE8D209C02E6814EBB42772FFCC5FF9943EFB90FC ->对称秘钥值(非对称加密,用服务器证书的公钥加密)
通过消息ClientKeyExchange,客户端把最重要的对称秘钥值(preMaster)传给了服务器。注意,真正的对称秘钥(masterKey)是需要通过preMaster和秘钥随机数杂交产生的,接着看完你就会懂。
紧接着,客户端说了这样一句话:
[Raw write]: length = 6
0000: 14 03 01 00 01 01
这是个ChangeCipherSpec消息(消息类型=0x14),客户端告知服务器,我和你之后的报文,消息体内容我会加密,你要用我们之间的秘钥解密才能看到明文。
然后,客户端又说了句话
[Raw write]: length = 53
0000: 16 03 01 00 30 2E 8C A5   C3 91 B3 50 41 1F 0B 9B  ....0......PA...
0010: 24 51 7A E0 36 6E 10 5F   0A 56 1A 47 E4 AD 23 B9  $Qz.6n._.V.G..#.
0020: 1D A3 2A 3D 02 15 98 83   4D D0 89 86 54 B8 B5 25  ..*=....M...T..%
0030: 86 95 B1 5D 20                                     ...] 
这条客户端消息翻译如下:
16  ->消息类型(1字节):握手
0301->版本号(2字节):TLS 1.0
0030->消息体长度(2字节):48字节
2E8CA5C391B350411F0B9B24517AE0366E105F0A561A47E4AD23B91DA32A3D021598834DD0898654B8B5258695B15D20 ->Finishd消息体
这时候服务器也回了个ChangeCipherSpec消息
[Raw read]: length = 5
0000: 14 03 01 00 01                                     .....
[Raw read]: length = 1
0000: 01    
服务器告知客户端,我和你之后的报文,消息体内容我会加密,你要用我们之间的秘钥解密才能看到明文。
最后,客户端收到服务器发送的Finished消息,这个消息是握手的最后一个消息:
[Raw read]: length = 5
0000: 16 03 01 00 30                                     ....0
[Raw read]: length = 48
0000: 17 96 79 E2 09 64 BE F2   1B 84 B1 72 DE E0 9B D5  ..y..d.....r....
0010: 70 0C EB 8E 37 17 3F A9   17 8F 41 8B 1A 3E EC 0D  p...7.?...A..>..
0020: A8 C1 34 2F 6E 3D 2C 0E   DD B2 61 8E 7A DF E3 7B  ..4/n=,...a.z...
main, READ: TLSv1 Handshake, length = 48
服务端的Finished消息整理一下:
16  ->消息类型(1字节):握手
0301->版本号(2字节):TLS 1.0
0030->消息体长度(2字节):48字节
179679E20964BEF21B84B172DEE09BD5700CEB8E37173FA9178F418B1A3EEC0DA8C1342F6E3D2C0EDDB2618E7ADFE37B ->Finishd消息体
Finished消息是握手的最后一步,至关重要!握手成不成功,就看Finished消息里面的摘要字符串验证能不能通过,客户端发过来的Finished,服务器会验,服务器发回应的Finished,客户端来验。对方怎么验?咱们接着往下说。
Finished消息是握手结束报文,因为这条消息是在ChangeCipherSpec消息之后发送的,消息体已被对称秘钥加密,服务器或客户端用秘钥解密之后才能得到消息体明文。
用客户端Finished消息来举例,Finishd消息体解密之后包含两部分:1、握手消息的摘要,让对方来核实收到的报文有没有被篡改的;2、Finished消息本身的消息消息验证码,对方验证Finished消息本身有没有被篡改的。
这里稍微梳理一下握手过程:
1 客户端:Client Hello,发送了客户端秘钥随机数和加密套件列表
2 服务器:Server Hello,回应了服务器秘钥随机数(与客户端秘钥随机数不同),选择了一个加密套件
          Certificate,返回服务器证书
          Server Hello Done,说完了
3 客户端:ClientKeyExchange,传送秘钥值(PreMaster)给服务器,并经过服务器证书里面的公钥加密
4 客户端:ChangeCipherSpec,告知服务器,我开始说密文了
5 客户端:Finished,你验一下摘要,看看我们说的话有没有被人篡改
6 服务器:ChangeCipherSpec,告知客户端,我开始说密文了
7 服务器:Finished,你验一下摘要,看看我们说的话有没有被人篡改
到此,握手结束!通过握手,双方确认了一个重要的事情那就是对称秘钥,有了对称秘钥,接下来就开始传输数据咯。
下面这个是客户端发送的经过加密的请求:
[Raw write]: length = 197
0000: 17 03 01 00 C0 D3 1B 8F   27 35 7A B1 0B 43 96 60  ........'5z..C.`
0010: 03 2C ED E5 0D B3 C5 8D   06 E3 54 BA 66 D8 3D 21  .,........T.f.=!
0020: C7 E7 3F 0A 61 19 11 D1   81 04 0F FC 41 99 DB 58  ..?.a.......A..X
0030: CA 82 B2 65 16 C2 29 D6   5B 0B 03 AD 65 D8 23 B5  ...e..).[...e.#.
0040: FE 73 B9 59 2F 21 81 85   73 35 A2 88 FF 0D 22 60  .s.Y/!..s5...."`
0050: 6C 49 49 99 D9 E9 1B D8   1D 1E A0 F6 5B 11 5B 90  lII.........[.[.
0060: CF F6 3B 72 D3 29 7C 16   A8 A9 19 C1 58 0C A7 BC  ..;r.)......X...
0070: 3C DA 58 F0 A1 B8 BA 4E   D6 58 21 0B 99 3B A9 6E  <.X....N.X!..;.n
0080: 69 1A D3 78 F7 6E E6 91   68 1F FD 18 5D A0 62 E3  i..x.n..h...].b.
0090: 85 A5 E2 84 63 F4 AA 32   E9 EB AD 57 0E 00 12 C3  ....c..2...W....
00A0: 1D A1 88 6D 0F 3B 0B 7C   39 3A B8 24 34 2E 09 AF  ...m.;..9:.$4...
00B0: 70 16 72 15 ED AB 2B FA   FE 8E CC 33 0E 9B E9 9C  p.r...+....3....
00C0: 6C 2A F1 F2 68                                     l*..h
然后服务器回应了一个这样的经过加密的应答:
[Raw read]: length = 5
0000: 17 03 01 01 30                                     ....0
[Raw read]: length = 304
0000: F3 60 41 1E 57 F2 3A 3B   FD 4E 76 4D 7F FF 62 BC  .`A.W.:;.NvM..b.
0010: F6 8C 18 0C EC 25 F2 A3   E0 E9 FD E1 39 56 42 75  .....%......9VBu
0020: 57 7B AE 75 62 9D 1C 6F   7F FA 89 40 62 F6 9C F9  W..ub..o...@b...
0030: F0 19 61 BC CD F1 5F 7F   E8 F4 C2 EF 46 0B A5 9E  ..a..._.....F...
0040: 3A CC B3 F9 E1 AF 8B 97   22 C3 20 07 78 41 88 8D  :.......". .xA..
0050: AE 05 9B FF 01 3F 12 AE   C1 6B 60 40 B1 A0 A6 C7  .....?...k`@....
0060: D6 6E EB 99 36 A0 22 15   87 94 D0 B8 9D 7E 2D F2  .n..6.".......-.
0070: 2F DC F2 BC 80 98 C5 97   8A 07 B9 A8 04 AA 4D 99  /.............M.
0080: 5A 53 43 F0 7A 5E A3 CD   BA BF 11 8D CB 71 05 AE  ZSC.z^.......q..
0090: 3B 45 6A F4 29 FA 13 66   90 C6 08 14 28 19 E7 F9  ;Ej.)..f....(...
00A0: 32 8A 4C F6 47 40 13 9C   9E F7 58 50 EA 44 68 60  2.L.G@....XP.Dh`
00B0: 48 9E 97 86 F8 D1 32 BD   6E C0 F0 6C B5 96 FF 23  H.....2.n..l...#
00C0: F8 B0 B4 E6 B1 AB 91 57   CD CB 52 7A 01 CC CA 3D  .......W..Rz...=
00D0: 7E 0E 7C AD 26 17 8E 08   00 78 A3 0D 69 8A 25 D9  ....&....x..i.%.
00E0: D2 42 F8 7A 0D 5E BD 89   9F 0B 73 CA 78 9D 18 D0  .B.z.^....s.x...
00F0: 51 C9 8A 4B 5A 54 C6 BE   6C C2 D1 B4 8B 19 26 12  Q..KZT..l.....&.
0100: 74 C3 74 EB 11 DD D3 2C   8E D3 10 99 CE D5 57 57  t.t....,......WW
0110: 45 C2 F1 56 ED 2D FB 09   70 80 16 0C 9A 4D BF 85  E..V.-..p....M..
0120: 23 E6 AA D2 B4 EE 18 21   F0 B3 5F D5 B6 52 91 B8  #......!.._..R..
可以看得出,这下的消息类型是0x17了,这表明这是一个http应用报文了,只不过报文体经过了加密,我接下来会上一段代码,真实还原https握手过程和http报文加解密以及防篡改校验,其中很多代码是从jsse.jar反编译中截取的,看得可能会费劲。
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
import sun.security.internal.spec.TlsKeyMaterialSpec;
import sun.security.internal.spec.TlsMasterSecretParameterSpec;
import sun.security.internal.spec.TlsPrfParameterSpec;

public class testSsl3 {

	public static void main(String[] args) {
		/**
		 * 我使用keytool生成一个密钥库,里面只有一对非对称密钥信息,别名为:tomcat
		 */
		String rasAlias = "tomcat";// 非对称密钥别名
		char[] keyStorePassword = "123456".toCharArray();// 密钥库密码
		String keyStorePath = "e:/tomcat.keystore";// 密钥库路径
		FileInputStream keyStoreFileInput = null;
		try {
			// 1 加载密钥库,拿出私钥
			keyStoreFileInput = new FileInputStream(keyStorePath);
			KeyStore keyStore = KeyStore.getInstance("JKS");
			keyStore.load(keyStoreFileInput, keyStorePassword);
			PrivateKey privateKey = (PrivateKey) keyStore.getKey(rasAlias, keyStorePassword);// 获取私钥
			// 2 非对称解密ClientKeyExchange消息被加密的preMaster
			String preMasterEncryptStr = "BA2887107E6372064B5E16C853FD1A7A6546DDD14D3E958889F440E45CDF51F72CA25CAD6DA3A1083BF05E0C8864B31DF834677B49F65F670AFB3F541F24AF43DDA6BB4B1E3DD6DC6392756140D23AE0667480D0B6E6317DAACABB8D406B45978081D631A60CDFBF7B60E49EE8D209C02E6814EBB42772FFCC5FF9943EFB90FC";// 客户端ClientKeyExchange消息送给服务器的preMaster
			byte[] preMasterDecryptBts = rsaUpdate(privateKey, Cipher.DECRYPT_MODE, preMasterEncryptStr);// 客户端ClientKeyExchange消息送给服务器的preMaster是经过服务器证书公钥加密,所以必须用私钥解密,私钥存在于密钥库中
			String preMasterDecryptStr = byte2hex(preMasterDecryptBts);
			System.out.println("preMaster(我解密的):\n" + preMasterDecryptStr);
			// 3 preMaster+密钥随机数生成对称密钥
			/** java6 解密preMaster的过程[begin] **/
			Cipher cipher_premaster = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher_premaster.init(Cipher.UNWRAP_MODE, privateKey);
			SecretKey preMasterKey = ((SecretKey) cipher_premaster.unwrap(hex2byte(preMasterEncryptStr), "TlsRsaPremasterSecret", Cipher.SECRET_KEY));
			/** java6 解密preMaster的过程[end] **/
			preMasterDecryptStr = byte2hex(preMasterKey.getEncoded());
			System.out.println("preMaster(java6方式解密的):\n" + preMasterDecryptStr);
			byte[] clnt_random = hex2byte("593123361F6CCC7097E124CDFA0C5D275CA94CAF492E230F35004E5194487E99");// 客户端密钥随机数
			byte[] svr_random = hex2byte("593123363344927B7FCCCBFB17E0DEBFAD602560F27A2BF286A961C38157A933");// 服务器密钥随机数
			TlsMasterSecretParameterSpec localTlsMasterSecretParameterSpec = new TlsMasterSecretParameterSpec(preMasterKey, 3, 1, clnt_random, svr_random);
			KeyGenerator keyGenerator1 = KeyGenerator.getInstance("SunTlsMasterSecret");
			keyGenerator1.init(localTlsMasterSecretParameterSpec);
			SecretKey masterKey = keyGenerator1.generateKey();
			String masterStr = byte2hex(masterKey.getEncoded());
			System.out.println("masterKey:\n" + masterStr);
			TlsKeyMaterialParameterSpec localTlsKeyMaterialParameterSpec = new TlsKeyMaterialParameterSpec(masterKey, 3, 1, clnt_random, svr_random, "AES", 16, 0, 16, 20);
			KeyGenerator keyGenerator2 = KeyGenerator.getInstance("SunTlsKeyMaterial");
			keyGenerator2.init(localTlsKeyMaterialParameterSpec);
			TlsKeyMaterialSpec localObject1 = (TlsKeyMaterialSpec) keyGenerator2.generateKey();
			SecretKey clntWriteKey = ((TlsKeyMaterialSpec) localObject1).getClientCipherKey();// 客户端加解密数据使用的密钥
			SecretKey svrWriteKey = ((TlsKeyMaterialSpec) localObject1).getServerCipherKey();// 服务器加解密数据使用的密钥
			IvParameterSpec clntWriteIV = ((TlsKeyMaterialSpec) localObject1).getClientIv();// 客户端向量
			IvParameterSpec svrWriteIV = ((TlsKeyMaterialSpec) localObject1).getServerIv();// 服务器向量
			SecretKey clntMacSecret = ((TlsKeyMaterialSpec) localObject1).getClientMacKey();// 客户端生成消息验证码密钥
			SecretKey svrMacSecret = ((TlsKeyMaterialSpec) localObject1).getServerMacKey();// 服务器生成消息验证码密钥
			System.out.println("clntWriteKey:\n" + byte2hex(clntWriteKey.getEncoded()));
			System.out.println("clntWriteIV:\n" + byte2hex(clntWriteIV.getIV()));
			System.out.println("clntMacSecret:\n" + byte2hex(clntMacSecret.getEncoded()));
			System.out.println("svrWriteKey:\n" + byte2hex(svrWriteKey.getEncoded()));
			System.out.println("svrWriteIV:\n" + byte2hex(svrWriteIV.getIV()));
			System.out.println("svrMacSecret:\n" + byte2hex(svrMacSecret.getEncoded()));
			// 4 对称解密客户端Finished消息
			Cipher cipher_client = Cipher.getInstance("AES/CBC/NoPadding");
			cipher_client.init(Cipher.DECRYPT_MODE, clntWriteKey, clntWriteIV);
			String clientFinishedEncryptStr = "16030100302E8CA5C391B350411F0B9B24517AE0366E105F0A561A47E4AD23B91DA32A3D021598834DD0898654B8B5258695B15D20";
			byte[] clientFinishedEncryptBts = hex2byte(clientFinishedEncryptStr);
			cipher_client.update(clientFinishedEncryptBts, 5, clientFinishedEncryptBts.length - 5, clientFinishedEncryptBts, 5);// 只解密消息体
			String clientFinishedDecryptStr = byte2hex(clientFinishedEncryptBts);
			System.out.println("client finished decrypt:\n" + clientFinishedDecryptStr);
			int clientFinishedPaddingLength = Integer.valueOf(clientFinishedDecryptStr.substring(clientFinishedDecryptStr.length() -1), 16) + 1;// Finished填充的字节数
			String clientFinishedStr = clientFinishedDecryptStr.substring(10, clientFinishedDecryptStr.length() - clientFinishedPaddingLength * 2);// 截出Finished
			System.out.println("client finished:\n" + clientFinishedStr);
			int clientFinishedLength = Integer.valueOf(clientFinishedStr.substring(2, 8), 16);// Finished长度:去掉1字节的0x14,后面3字节为长度
			String clientHandShakeMacStr = clientFinishedStr.substring(8, 8 + clientFinishedLength*2);// 客户端握手消息验证码
			String clientFinishedMacStr = clientFinishedStr.substring(8 + clientFinishedLength*2);// Finished消息验证码
			System.out.println("client handshake mac(报文里的):\n" + clientHandShakeMacStr);
			System.out.println("client finished mac(报文里的):\n" + clientFinishedMacStr);
			Mac clientMac = Mac.getInstance("HmacSHA1");
			clientMac.init(clntMacSecret);
			clientMac.update(hex2byte("00000000000000001603010010"));// 第8字节是计算次数,第9字节是消息类型,第10~11字节是版本号,第12~13字节是数据长度:即clientFinishedLength
			clientMac.update(hex2byte(clientFinishedStr.substring(0, 8 + clientFinishedLength*2)));
			byte[] clientFinishedMacBts = clientMac.doFinal();
			String clientFinishedMacStr2 = byte2hex(clientFinishedMacBts);
			System.out.println("client finished mac(我计算的):\n" + clientFinishedMacStr2);// 服务器验证客户端发过来的finished报文有没有被篡改,过程就是根据Finished原文计算出clinet finished mac,比较与Finished报文末尾的client finished mac是否一致
			// 5 验证客户端握手消息验证码
			String clientStr = "client finished";
			StringBuilder clientSb = new StringBuilder();
			/** Client Hello **/
			clientSb.append("010000470301593123361F6CCC7097E124CDFA0C5D275CA94CAF492E230F35004E5194487E9900002000040005002F00330032000A00160013000900150012000300080014001100FF0100");
			/** Server Hello **/
			clientSb.append("020000460301593123363344927B7FCCCBFB17E0DEBFAD602560F27A2BF286A961C38157A93320593123367275A3D976143020DE265E229AA917CC25371582FABDBA6E0877C1EE002F00");
			/** Certificate **/
			clientSb.append("0B00026300026000025D30820259308201C2A0030201020204589D624B300D06092A864886F70D01010505003071310B300906035504061302434E31123010060355040813093132372E302E302E3131123010060355040713093132372E302E302E3131123010060355040A13093132372E302E302E3131123010060355040B13093132372E302E302E3131123010060355040313093132372E302E302E31301E170D3137303231303036343834335A170D3137303531313036343834335A3071310B300906035504061302434E31123010060355040813093132372E302E302E3131123010060355040713093132372E302E302E3131123010060355040A13093132372E302E302E3131123010060355040B13093132372E302E302E3131123010060355040313093132372E302E302E3130819F300D06092A864886F70D010101050003818D0030818902818100C24E1F327BF76543BB8CA670A5C68607C6B91CF074BFEBCE44A41D54A8736F8C4D6EC8898F7533C506457FF6EA9FF6401527CD1F2B34D03FEFDFF7A782E75A0D4601312E471ED23205E3DE154E9679C24AF38343E70DB08BEAD186817356DC5648B0700418725BA7D5ABB732B35EDF33299BB82928F5E4AB4B0313D31A2CF2ED0203010001300D06092A864886F70D0101050500038181000EACA0C952D45084A342C399922887170B2BE361F154AE6516890DB77342D04B2DD6CE5E2C7145B6433EA909AA484D9B10AF89E6EFC21992C1886DF5566412BC0E3DD6B0D2177D4FD4CFA34363654DAA7DC4CD7CFA4433ACF810006B077B6CBAC66F8184A0D40CF9A00F8690776DCED47996B6B5011E66219A45E2DAF029E662");
			/** Server Hello Done **/
			clientSb.append("0E000000");
			/** Client Key Exchange **/
			clientSb.append("100000820080BA2887107E6372064B5E16C853FD1A7A6546DDD14D3E958889F440E45CDF51F72CA25CAD6DA3A1083BF05E0C8864B31DF834677B49F65F670AFB3F541F24AF43DDA6BB4B1E3DD6DC6392756140D23AE0667480D0B6E6317DAACABB8D406B45978081D631A60CDFBF7B60E49EE8D209C02E6814EBB42772FFCC5FF9943EFB90FC");
			MessageDigest clientMd5 = MessageDigest.getInstance("MD5");
			MessageDigest clientSha = MessageDigest.getInstance("SHA");
			clientMd5.update(hex2byte(clientSb.toString()));
			clientSha.update(hex2byte(clientSb.toString()));
			byte[] arrayOfByteClient = new byte[36];
			clientMd5.digest(arrayOfByteClient, 0, 16);
			clientSha.digest(arrayOfByteClient, 16, 20);
			TlsPrfParameterSpec tlsPrfParameterSpecClient = new TlsPrfParameterSpec(masterKey, clientStr, arrayOfByteClient, 12);
			KeyGenerator keyGeneratorClient = KeyGenerator.getInstance("SunTlsPrf");
			keyGeneratorClient.init(tlsPrfParameterSpecClient);
			SecretKey secretKeyClient = keyGeneratorClient.generateKey();
			byte[] clientHandShakeMacBts = secretKeyClient.getEncoded();
			String clientHandShakeMacStr2 = byte2hex(clientHandShakeMacBts);
			System.out.println("client handshake mac(我计算的):\n" + clientHandShakeMacStr2);// 服务器验证握手消息有没有篡改,过程就是客户端Finished消息和之前握手类型消息明文,按顺序拼接计算出client handshake mac,比较与客户端Finished消息内的client handshake mac是否一致
			// 6 对称解密服务器Finished消息
			Cipher cipher_server = Cipher.getInstance("AES/CBC/NoPadding");
			cipher_server.init(Cipher.DECRYPT_MODE, svrWriteKey, svrWriteIV);
			String serverFinishedEncryptStr = "1603010030179679E20964BEF21B84B172DEE09BD5700CEB8E37173FA9178F418B1A3EEC0DA8C1342F6E3D2C0EDDB2618E7ADFE37B";
			byte[] serverFinishedEncryptBts = hex2byte(serverFinishedEncryptStr);
			cipher_server.update(serverFinishedEncryptBts, 5, serverFinishedEncryptBts.length - 5, serverFinishedEncryptBts, 5);// 只解密消息体
			String serverFinishedDecryptStr = byte2hex(serverFinishedEncryptBts);
			System.out.println("server finished decrypt:\n" + serverFinishedDecryptStr);
			int serverFinishedPaddingLength = Integer.valueOf(serverFinishedDecryptStr.substring(serverFinishedDecryptStr.length() -1), 16) + 1;// Finished填充的字节数
			String serverFinishedStr = serverFinishedDecryptStr.substring(10, serverFinishedDecryptStr.length() - serverFinishedPaddingLength * 2);// 截出Finished
			System.out.println("server finished:\n" + serverFinishedStr);
			int serverFinishedLength = Integer.valueOf(serverFinishedStr.substring(2, 8), 16);// Finished长度:去掉1字节的0x14,后面3字节为长度
			String serverHandShakeMacStr = serverFinishedStr.substring(8, 8 + serverFinishedLength*2);// 服务端握手消息验证码
			String serverFinishedMacStr = serverFinishedStr.substring(8 + serverFinishedLength*2);// Finished消息验证码
			System.out.println("server handshake mac(报文里的):\n" + serverHandShakeMacStr);
			System.out.println("server finished mac(报文里的):\n" + serverFinishedMacStr);
			Mac serverMac = Mac.getInstance("HmacSHA1");
			serverMac.init(svrMacSecret);
			serverMac.update(hex2byte("00000000000000001603010010"));// 第8字节是计算次数,第9字节是消息类型,第10~11字节是版本号,第12~13字节是数据长度:即serverFinishedLength
			serverMac.update(hex2byte(serverFinishedStr.substring(0, 8 + serverFinishedLength*2)));
			byte[] finishedMacBts = serverMac.doFinal();
			String finishedMacStr2 = byte2hex(finishedMacBts);
			System.out.println("server finished mac(我计算的):\n" + finishedMacStr2);// 客户端验证服务器发过来的finished报文有没有被篡改,过程就是根据Finished原文计算出server finished mac,比较与Finished报文末尾的里面的server finished mac是否一致
			// 7 验证服务器握手消息验证码
			String serverStr = "server finished";
			StringBuilder serverSb = new StringBuilder();
			/** Client Hello **/
			serverSb.append("010000470301593123361F6CCC7097E124CDFA0C5D275CA94CAF492E230F35004E5194487E9900002000040005002F00330032000A00160013000900150012000300080014001100FF0100");
			/** Server Hello **/
			serverSb.append("020000460301593123363344927B7FCCCBFB17E0DEBFAD602560F27A2BF286A961C38157A93320593123367275A3D976143020DE265E229AA917CC25371582FABDBA6E0877C1EE002F00");
			/** Certificate **/
			serverSb.append("0B00026300026000025D30820259308201C2A0030201020204589D624B300D06092A864886F70D01010505003071310B300906035504061302434E31123010060355040813093132372E302E302E3131123010060355040713093132372E302E302E3131123010060355040A13093132372E302E302E3131123010060355040B13093132372E302E302E3131123010060355040313093132372E302E302E31301E170D3137303231303036343834335A170D3137303531313036343834335A3071310B300906035504061302434E31123010060355040813093132372E302E302E3131123010060355040713093132372E302E302E3131123010060355040A13093132372E302E302E3131123010060355040B13093132372E302E302E3131123010060355040313093132372E302E302E3130819F300D06092A864886F70D010101050003818D0030818902818100C24E1F327BF76543BB8CA670A5C68607C6B91CF074BFEBCE44A41D54A8736F8C4D6EC8898F7533C506457FF6EA9FF6401527CD1F2B34D03FEFDFF7A782E75A0D4601312E471ED23205E3DE154E9679C24AF38343E70DB08BEAD186817356DC5648B0700418725BA7D5ABB732B35EDF33299BB82928F5E4AB4B0313D31A2CF2ED0203010001300D06092A864886F70D0101050500038181000EACA0C952D45084A342C399922887170B2BE361F154AE6516890DB77342D04B2DD6CE5E2C7145B6433EA909AA484D9B10AF89E6EFC21992C1886DF5566412BC0E3DD6B0D2177D4FD4CFA34363654DAA7DC4CD7CFA4433ACF810006B077B6CBAC66F8184A0D40CF9A00F8690776DCED47996B6B5011E66219A45E2DAF029E662");
			/** Server Hello Done **/
			serverSb.append("0E000000");
			/** Client Key Exchange **/
			serverSb.append("100000820080BA2887107E6372064B5E16C853FD1A7A6546DDD14D3E958889F440E45CDF51F72CA25CAD6DA3A1083BF05E0C8864B31DF834677B49F65F670AFB3F541F24AF43DDA6BB4B1E3DD6DC6392756140D23AE0667480D0B6E6317DAACABB8D406B45978081D631A60CDFBF7B60E49EE8D209C02E6814EBB42772FFCC5FF9943EFB90FC");
			/** Client Finished **/
			serverSb.append("1400000CE983C22990366CD0A35E41B3");
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			MessageDigest sha = MessageDigest.getInstance("SHA");
			md5.update(hex2byte(serverSb.toString()));
			sha.update(hex2byte(serverSb.toString()));
			byte[] arrayOfByteServer = new byte[36];
			md5.digest(arrayOfByteServer, 0, 16);
			sha.digest(arrayOfByteServer, 16, 20);
			TlsPrfParameterSpec tlsPrfParameterSpecServer = new TlsPrfParameterSpec(masterKey, serverStr, arrayOfByteServer, 12);
			KeyGenerator keyGeneratorServer = KeyGenerator.getInstance("SunTlsPrf");
			keyGeneratorServer.init(tlsPrfParameterSpecServer);
			SecretKey secretKeyServer = keyGeneratorServer.generateKey();
			byte[] serverHandShakeMacBts = secretKeyServer.getEncoded();
			String serverHandShakeMacStr2 = byte2hex(serverHandShakeMacBts);
			System.out.println("server handshake mac(我计算的):\n" + serverHandShakeMacStr2);// 客户端验证握手消息有没有篡改,过程就是服务器Finished消息和之前握手类型消息明文,按顺序拼接计算出server handshake mac,比较与服务器Finished内的server handshake mac是否一致
			// 8解密http请求内容,验证请求mac
			String httpRequestEncryptStr = "17030100C0D31B8F27357AB10B439660032CEDE50DB3C58D06E354BA66D83D21C7E73F0A611911D181040FFC4199DB58CA82B26516C229D65B0B03AD65D823B5FE73B9592F2181857335A288FF0D22606C494999D9E91BD81D1EA0F65B115B90CFF63B72D3297C16A8A919C1580CA7BC3CDA58F0A1B8BA4ED658210B993BA96E691AD378F76EE691681FFD185DA062E385A5E28463F4AA32E9EBAD570E0012C31DA1886D0F3B0B7C393AB824342E09AF70167215EDAB2BFAFE8ECC330E9BE99C6C2AF1F268";
			byte[] httpRequestEncryptBts = hex2byte(httpRequestEncryptStr);
			cipher_client.update(httpRequestEncryptBts, 5, httpRequestEncryptBts.length - 5, httpRequestEncryptBts, 5);
			int requestPaddingLen = httpRequestEncryptBts[httpRequestEncryptBts.length - 1] + 1;// 填充字节数
			byte[] requestMacBts = new byte[20];
			/** https报文头5字节 ,20字节消息鉴别码 ,还有末尾的填充字节,掐头去尾剩下中间的就是被加密的http报文 **/
			System.arraycopy(httpRequestEncryptBts, httpRequestEncryptBts.length - requestPaddingLen - 20, requestMacBts, 0, requestMacBts.length);
			byte[] requestMacSrcBts = new byte[httpRequestEncryptBts.length - requestPaddingLen - 5 - 20];
			System.arraycopy(httpRequestEncryptBts, 5, requestMacSrcBts, 0, requestMacSrcBts.length);
			clientMac.update(hex2byte("000000000000000117030100A7"));// 第8字节是计算次数,第9字节是消息类型,第10~11字节是版本号,第12~13字节是数据长度:即requestMacSrcBts长度
			clientMac.update(requestMacSrcBts);
			byte[] requestMacBts2 = clientMac.doFinal();
			System.out.println("http请求解密(十六进制):" + byte2hex(httpRequestEncryptBts));
			System.out.println("http请求字节填充数:" + requestPaddingLen);
			System.out.println("http请求mac:" + byte2hex(requestMacBts));
			System.out.println("http请求计算mac数据源:" + byte2hex(requestMacSrcBts));
			System.out.println("http请求计算mac结果:" + byte2hex(requestMacBts2));
			System.out.println("http请求解密(文本):\n" + new String(httpRequestEncryptBts, 5, httpRequestEncryptBts.length - requestPaddingLen - 5 - 20, "ISO-8859-1"));
			// 9解密http响应内容,验证响应mac
			String httpResponseEncryptStr = "1703010130F360411E57F23A3BFD4E764D7FFF62BCF68C180CEC25F2A3E0E9FDE139564275577BAE75629D1C6F7FFA894062F69CF9F01961BCCDF15F7FE8F4C2EF460BA59E3ACCB3F9E1AF8B9722C320077841888DAE059BFF013F12AEC16B6040B1A0A6C7D66EEB9936A022158794D0B89D7E2DF22FDCF2BC8098C5978A07B9A804AA4D995A5343F07A5EA3CDBABF118DCB7105AE3B456AF429FA136690C608142819E7F9328A4CF64740139C9EF75850EA446860489E9786F8D132BD6EC0F06CB596FF23F8B0B4E6B1AB9157CDCB527A01CCCA3D7E0E7CAD26178E080078A30D698A25D9D242F87A0D5EBD899F0B73CA789D18D051C98A4B5A54C6BE6CC2D1B48B19261274C374EB11DDD32C8ED31099CED5575745C2F156ED2DFB097080160C9A4DBF8523E6AAD2B4EE1821F0B35FD5B65291B8";
			byte[] httpResponseEncryptBts = hex2byte(httpResponseEncryptStr);
			cipher_server.update(httpResponseEncryptBts, 5, httpResponseEncryptBts.length - 5, httpResponseEncryptBts, 5);
			int responsePaddingLen = httpResponseEncryptBts[httpResponseEncryptBts.length - 1] + 1;// 填充字节数
			byte[] responseMacBts = new byte[20];
			System.arraycopy(httpResponseEncryptBts, httpResponseEncryptBts.length - responsePaddingLen - 20, responseMacBts, 0, responseMacBts.length);
			byte[] responseMacSrcBts = new byte[httpResponseEncryptBts.length - responsePaddingLen - 5 - 20];
			System.arraycopy(httpResponseEncryptBts, 5, responseMacSrcBts, 0, responseMacSrcBts.length);
			serverMac.update(hex2byte("0000000000000001170301011A"));// 第8字节是计算次数,第9字节是消息类型,第10~11字节是版本号,第12~13字节是数据长度:即responseMacSrcBts长度
			serverMac.update(responseMacSrcBts);
			byte[] responseMacBts2 = serverMac.doFinal();
			System.out.println("http响应解密(十六进制):" + byte2hex(httpResponseEncryptBts));
			System.out.println("http响应字节填充数:" + responsePaddingLen);
			System.out.println("http响应mac:" + byte2hex(responseMacBts));
			System.out.println("http响应计算mac数据源:" + byte2hex(responseMacSrcBts));
			System.out.println("http响应计算mac结果:" + byte2hex(responseMacBts2));
			System.out.println("http响应解密(文本):\n" + new String(httpResponseEncryptBts, 5, httpResponseEncryptBts.length - responsePaddingLen - 5 - 20, "ISO-8859-1"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * RSA加解密
	 * @param key 密钥
	 * @param opmode 操作模式:加密/解密
	 * @param data 数据
	 * @return
	 */
	public static byte[] rsaUpdate(Key key, int opmode, String data) {
		try {
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(opmode, key);
			return cipher.doFinal(hex2byte(data));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 十六进制字符串转字节数组
	 * @param hex 十六进制字符串
	 * @return
	 */
	public static byte[] hex2byte(String hex){
		int length = hex.length();
		if (length%2 != 0){
			throw new RuntimeException("长度错误");
		}
		
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		for (int i = 0; i < length; i += 2){
			int v = Integer.valueOf(hex.substring(i, i+2), 16);
			bo.write(v);
		}
		return bo.toByteArray();
	}
	
	/**
	 * 字节数组转16进制字符串
	 * @param bytes
	 * @param start_index
	 * @param length
	 * @return
	 */
	public static String byte2hex(byte[] bytes, int start_index, int length){
		if (bytes == null){
			return null;
		}
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes){
			if (--start_index >= 0){
				continue;
			}
			if (--length < 0){
				break;
			}
			String hex = Integer.toHexString(b & 0xff);
			if (hex.length() == 1){
				hex = "0" + hex;
			}
			sb.append(hex);
		}
		return sb.toString().toUpperCase();
	}
	
	/**
	 * 字节数组转16进制字符串
	 * @param bytes
	 * @param start_index
	 * @param length
	 * @return
	 */
	public static String byte2hex(byte[] bytes){
		return byte2hex(bytes, 0, bytes.length);
	}
}


console输出如下:
preMaster(我解密的):
0301A423A5A3FC070A11DCA8259B7D469909C5E37AD34CD9567473213B4AE072A3D7EC4A365DFB1BF18A0459365FB358
preMaster(java6方式解密的):
0301A423A5A3FC070A11DCA8259B7D469909C5E37AD34CD9567473213B4AE072A3D7EC4A365DFB1BF18A0459365FB358
masterKey:
ADCD2A11D8BB3F26B4C6DDA62053C4BDD64B5EA79EE86EB4E257F04D234F1567A14A7162C871B919D3A073C229F86AF4
clntWriteKey:
97CCEB77738E5CBE81D3EA7C5A02A447
clntWriteIV:
2FED03D9D60E03A86C1280BDD487F347
clntMacSecret:
D8513F838891D9A0F5E1A04970CD04B4006E34F4
svrWriteKey:
BC6E8027E3B15062AF1B44BF801F1398
svrWriteIV:
4AAF38831283AC3322097820479E42EF
svrMacSecret:
FE8241F0661862654C9609F5BDD6DBC86BE72674
client finished decrypt:
16030100301400000CE983C22990366CD0A35E41B36B32481B52B5CF31909A31871F5085768D4359FB0B0B0B0B0B0B0B0B0B0B0B0B
client finished:
1400000CE983C22990366CD0A35E41B36B32481B52B5CF31909A31871F5085768D4359FB
client handshake mac(报文里的):
E983C22990366CD0A35E41B3
client finished mac(报文里的):
6B32481B52B5CF31909A31871F5085768D4359FB
client finished mac(我计算的):
6B32481B52B5CF31909A31871F5085768D4359FB
client handshake mac(我计算的):
E983C22990366CD0A35E41B3
server finished decrypt:
16030100301400000C70774150DE43C5D2EF19F7E0DE1D1F0D4A4B4698290586CB5FFF446AC79F0E9A0B0B0B0B0B0B0B0B0B0B0B0B
server finished:
1400000C70774150DE43C5D2EF19F7E0DE1D1F0D4A4B4698290586CB5FFF446AC79F0E9A
server handshake mac(报文里的):
70774150DE43C5D2EF19F7E0
server finished mac(报文里的):
DE1D1F0D4A4B4698290586CB5FFF446AC79F0E9A
server finished mac(我计算的):
DE1D1F0D4A4B4698290586CB5FFF446AC79F0E9A
server handshake mac(我计算的):
70774150DE43C5D2EF19F7E0
http请求解密(十六进制):17030100C0474554202F746573742F696E6465782E6A737020485454502F312E310D0A557365722D4167656E743A204A6176612F312E362E305F32370D0A486F73743A203132372E302E302E313A383434330D0A4163636570743A20746578742F68746D6C2C20696D6167652F6769662C20696D6167652F6A7065672C202A3B20713D2E322C202A2F2A3B20713D2E320D0A436F6E6E656374696F6E3A206B6565702D616C6976650D0A0D0A4DFCB522DBB0EBA964958B5E79A6A21E15CE4EC70404040404
http请求字节填充数:5
http请求mac:4DFCB522DBB0EBA964958B5E79A6A21E15CE4EC7
http请求计算mac数据源:474554202F746573742F696E6465782E6A737020485454502F312E310D0A557365722D4167656E743A204A6176612F312E362E305F32370D0A486F73743A203132372E302E302E313A383434330D0A4163636570743A20746578742F68746D6C2C20696D6167652F6769662C20696D6167652F6A7065672C202A3B20713D2E322C202A2F2A3B20713D2E320D0A436F6E6E656374696F6E3A206B6565702D616C6976650D0A0D0A
http请求计算mac结果:4DFCB522DBB0EBA964958B5E79A6A21E15CE4EC7
http请求解密(文本):
GET /test/index.jsp HTTP/1.1
User-Agent: Java/1.6.0_27
Host: 127.0.0.1:8443
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive




http响应解密(十六进制):1703010130485454502F312E3120323030204F4B0D0A5365727665723A204170616368652D436F796F74652F312E310D0A5365742D436F6F6B69653A204A53455353494F4E49443D45343533443138394237413430354645304536374344303330463130433532343B20506174683D2F746573743B205365637572650D0A436F6E74656E742D547970653A20746578742F68746D6C0D0A436F6E74656E742D4C656E6774683A2037370D0A446174653A204672692C203032204A756E20323031372030383A33353A303220474D540D0A0D0A3C68746D6C3E0A3C686561643E0A3C7469746C653E746573743C2F7469746C653E0A3C2F686561643E0A3C626F64793E0A48656C6C6F20576F726C64210A3C2F626F64793E0A3C2F68746D6C3E4358380EF3D9A0D11C69FD77082A45D86C25FCFA0101
http响应字节填充数:2
http响应mac:4358380EF3D9A0D11C69FD77082A45D86C25FCFA
http响应计算mac数据源:485454502F312E3120323030204F4B0D0A5365727665723A204170616368652D436F796F74652F312E310D0A5365742D436F6F6B69653A204A53455353494F4E49443D45343533443138394237413430354645304536374344303330463130433532343B20506174683D2F746573743B205365637572650D0A436F6E74656E742D547970653A20746578742F68746D6C0D0A436F6E74656E742D4C656E6774683A2037370D0A446174653A204672692C203032204A756E20323031372030383A33353A303220474D540D0A0D0A3C68746D6C3E0A3C686561643E0A3C7469746C653E746573743C2F7469746C653E0A3C2F686561643E0A3C626F64793E0A48656C6C6F20576F726C64210A3C2F626F64793E0A3C2F68746D6C3E
http响应计算mac结果:4358380EF3D9A0D11C69FD77082A45D86C25FCFA
http响应解密(文本):
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E453D189B7A405FE0E67CD030F10C524; Path=/test; Secure
Content-Type: text/html
Content-Length: 77
Date: Fri, 02 Jun 2017 08:35:02 GMT


<html>
<head>
<title>test</title>
</head>
<body>
Hello World!
</body>
</html>
https生成对称秘钥过程,是由客户端生成一个preMaster,通过服务器公钥加密,传输给服务器,通过preMaster和密钥随机数生成masterKey,再有masterKey分散出6个对称相关数据:客户端、服务器加密数据密钥,客户端、服务器计算消息验证码密钥,客户端、服务器向量。
客户端的加密数据密钥和客户端向量,用来加密客户端数据,服务器用这两个数据解密客户端密文。
服务器的加密数据密钥和服务器向量,用来加密服务器数据,客户端用这两个数据解密服务器密文。
握手消息类型消息验证码:握手消息按顺序拼接,先摘要计算,再使用计算消息验证码密钥加密生成密文,存在Finished消息体中。
Finished消息和Application消息(消息类型=0x17)的消息验证码:消息体使用计算消息验证码密钥加密生成的密文。
java6实现https大致如我上面贴的代码,有很多地方我没有做出很详细的说明,完全是由于篇幅和时间原因。因为本人完全没有阅读过相关规范文档,所有的东西是从网上来了解,代码也是看的反编译,所以定义了一些自己认为好理解的词汇,还请谅解。
大家可以通过评论与我交流。















 
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值