HTTPS实现原理

1,243 阅读25分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

术语扫盲

80端口:80端口是为HTTP(HyperText Transport Protocol)即超文本传输协议开放的默认端口

443端口:443端口即网页浏览端口,主要是用于HTTPS服务,是提供加密和通过安全端口传输的另一种HTTP。是https的默认端口。

小结:访问网页如不加端口号,使用http协议访问网页,是请求的服务器的80端口;使用https协议请求的是服务器的443端口。


SSL(Secure Sockets Layer 安全套接层) :位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。

TLS:(Transport LayerSecurity,传输层安全协议) :用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。

TLS记录协议: 是一种分层协议,,这种协议被用来封装几种高层协议(如HTTP,SMTP等)。使用有TLS握手协议产生的安全参数,它首先将上层被传输的数据分片成便于管理的块,然后对数据有选择性地压缩,计算出消息认证码MAC(如MD5或SHA),加密(如NULL,DES,3DES等),最后将结果送出。接收到的数据经过解密,校验,解压缩,重组后被传输到上层客户端。TLS记录协议位于TLS握手协议的下面,在可靠的传输协议(如TCP/IP)上面。其负责识别不同的消息类型,以及每条消息的完整性、安全性验证。

小结: 两个协议都是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。SSL协议的发展历史比较早,第一版由于漏洞比较多,1994年公布了第二个版本。1996年5月, TLS工作组成立,开始将SSL从Netscape迁移至IETF。SSL是Netscape开发的专门用户保护Web通讯的,目前版本为3.0。最新版本的TLS 1.0是IETF(工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本。两者差别极小,可以理解为SSL 3.1,它是写入了RFC的。 SSL 3.0和TLS 1.0有轻微差别,但两种规范其实大致相同。

网景公司(Netscape)在1994年推出首版网页浏览器,网景导航者时,推出HTTPS协议,以SSL进行加密,这是SSL的起源。IETF将SSL进行标准化,1999年公布第一版TLS标准文件。随后又公布RFC 5246 (2008年8月)与 RFC 6176 (2011年3月)。在浏览器、电子邮件、即时通信、VoIP、网络传真等应用程序中,广泛支持这个协议。


X.509: 是密码学里公钥证书的格式标准。 X.509 证书己应用在包括TLS/SSL在内的众多 Intenet协议里.同时它也用在很多非在线应用场景里,比如电子签名服务。X.509证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构CA的签名,也可以是自签名)。对于一份经由可信的证书签发机构签名或者可以通过其它方式验证的证书,证书的拥有者就可以用证书及相应的私钥来创建安全的通信,对文档进行数字签名.

OpenSSL: OpenSSL是一个开源项目,包括密码库和SSL/TLS工具集。 OpenSSL项目是安全套接字层(secure sockets layer, SSL)和传输层安全(transport layer security, TLS)协议的一个实现,是大家共同努力开发出的代码可靠、功能齐全、商业级别的开源工具集。 可以使用该项目生成数字证书。

HTTPS: 超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS,常称为HTTP over TLS、HTTP over SSL或HTTP Secure)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。它其实就是HTTP+加密+身份认证+完整性保护

OSI模型层

开放系统互联(open systems interconnection, OSI):网络通信的理论模型,简单来说,所有的功能都被映射到七个层上。最底层是最接近物理通信链路的层,后面的层依次建立在其他层之上,提供更高级别的抽象。最顶层就是应用层,携带着应用数据

层号OSI层描述协议示例
7应用层应用数据HTTP、 SMTP、 IMAP
6表示层数据表示、转换和加密SSL/ TLS
5会话层多连接管理
4传输层包或流的可靠传输TCP、 UDP
3网络层网络节点间的路由与数据分发IP、 IPSec
2数据链路层可靠的本地数据连接( LAN)以太网
1物理层直接物理数据连接(电缆)CAT5

现实中的协议并非总能与OSI模型完全对应。比如SPDY和HTTP/2因为要对连接进行管理,所以被归入会话层协议,但它们却在数据加密以后生效。第五层及更高层的划分经常是模糊的。

img

OSI参考模型 和 TCP/IP协议群

证书

内容字段

一般遵从X.509格式规范的证书,会有以下的内容,它们以字段的方式表示:

  • 版本:现行通用版本是 V3

  • 序号:用以识别每一张证书,特别在撤消证书的时候有用

  • 主体:拥有此证书的法人或自然人身份或机器,包括:

    • 国家(C,Country)
    • 州/省(S,State)
    • 地域/城市(L,Location)
    • 组织/单位(O,Organization)
    • 通用名称(CN,Common Name):在TLS应用上,此字段一般是网域
  • 发行者:以数字签名形式签署此证书的数字证书认证机构

  • 有效期开始时间:此证书的有效开始时间,在此前该证书并未生效

  • 有效期结束时间:此证书的有效结束时间,在此后该证书作废

  • 公开密钥用途:指定证书上公钥的用途,例如数字签名、服务器验证、客户端验证等

  • 公开密钥

  • 公开密钥指纹

  • 数字签名

  • 数字签名算法

  • 主体别名:例如一个网站可能会有多个网域(www.wikipedia.org, zh.wikipedia.org, zh.m.wikipedia.org 都是维基百科)、一个组织可能会有多个网站(*.wikipedia.org, *.wikibooks.org, *.wikidata.org 都是维基媒体基金会旗下的网域),不同的网域可以一并使用同一张证书,方便实现应用及管理

申领及使用

申领.png 向证书机构申领签发电子证书的进程

数字证书一般由数字证书认证机构签发,简单的程序如下:

申领

  1. 鲍伯在自己的机器上使用密码学安全伪随机数生成器产生一对足够强的密钥
  2. 鲍伯的私钥不会向任何人发送
  3. 鲍伯把他的公钥,连同主体消息、使用目的等组成证书签署请求,发送给发行人伊凡
  4. 伊凡(用另外一些渠道)核实鲍伯的身份
  5. 如果伊凡信任这个请求,他便使用鲍伯的公钥和主体消息,加上证书有效期、用途等限制条件,组成证书的基本数据
  6. 伊凡用自己私钥在证书上加密签署
  7. 伊凡把加密好的证书发送给鲍伯(伊凡也可以透过证书透明度公布他签发了新的证书)

使用

主条目:公开密钥加密 § 加密过程

  1. 鲍伯与爱丽丝事先可能互不认识,但鲍伯与爱丽丝都信任伊凡,爱丽丝验证过证书上伊凡的签署有效无误后,便可以信任证书是属于鲍伯的
  2. 爱丽丝可以使用证书上的公钥加密明文,得到密文并发送给鲍伯
  3. 鲍伯可以可以用自己的私钥把密文解密,得到明文

单元格式

电子证书可以二进制或Base64形式存储,常见的二进制文件扩展名有 .cer、.crt、.der,Base64的文件扩展名则通常是 .pem。如果把证书和私钥一起存储,则可以使用PKCS#12(.p12)格式。

HTTPS工作原理

HTTPS是利用SSL/TLS来加密数据包的。本结通过TLS 1.2 的宏观概述,来理解HTTPS的工作原理。

TLS协议由两层组成:TLS记录协议和TLS握手协议。

TLS握手协议

每一个TLS连接都会以握手开始。 尽管可以选择对任意一端进行身份验证,但人们几乎都启用了对服务器的身份验证。完整的握手如图所示

img

1. Client Hello

  • 客户端发起TLS握手请求

    struct {
            ProtocolVersion client_version;
            Random random;
            SessionID session_id;     
            CipherSuite cipher_suites<2..2^16-2>;
            CompressionMethod compression_methods<1..2^8-1>;
            select (extensions_present) {
                case false:
                    struct {};
                case true:
                    Extension extensions<0..2^16-1>;
            };
        } ClientHello;
    
  • 数据包括内容:

    • ProtocolVersion/协议版本(客户端期望支持的握手协议版本

    • Random/安全随机数(MasterSecret生成用到,协议文档里面说是28个字节,但是实际抓包看到是32个字节,这里怀疑是各个协议文档版本不同,还有使用加密套件的不同,导致的差异,具体博主就没有在继续深究了,如果有朋友知道可以留言给我)

    • SessionID/会话ID

      • 这个值是被服务端设置的,如果这个值为空,表示客户端与服务端没有存活的https会话,需要与服务端进行完整的握手。
      • 如果这个值存在,则表明客户端期望恢复上一次的https会话,这时候客户端与服务端只需要进行快速的握手过程。(这里我们只会分析完整的握手过程进行学习)
    • CipherSuite/加密套件(客户端支持的加密套件列表)

      • 如果sessionid不为空,可以不传这个值,服务端可以从上一次会话中恢复这个值。

      • 每个加密组件(Cipher Suite)都包括了下面5类算法

        TLS Cipher Suite Registry

        ,图中百度使用的是就是

        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

        这个加密套件:

        • 1、authentication (认证算法):RSA
        • 2、encryption (加密算法 ):AEAD_AES_128_GCM
        • 3、message authentication code (消息认证码算法 简称MAC):SHA256
        • 4、key exchange (密钥交换算法):ECDHE
        • 5、key derivation function (密钥衍生算法)
    • CompressionMethod/压缩方法

      • 加密前进行数据压缩
      • 因为压缩方法被攻击,在TLS1.3协议版本上已经彻底禁止压缩了。(这里有两种攻击方式BREACH、CRIME,有时间博主会来研究)
    • Extension/扩展数据(session ticket在扩展里面,可见下图)

  • 消息内容如下图:

3.jpg

2. Server Hello

  • 服务端回应Client Hello请求

    struct {
            ProtocolVersion server_version;
            Random random;
            SessionID session_id;
            CipherSuite cipher_suite;
            CompressionMethod compression_method;
            select (extensions_present) {
                case false:
                    struct {};
                case true:
                    Extension extensions<0..2^16-1>;
            };
        } ServerHello;
    
  • 主要发送数据内容:

    • ProtocolVersion/握手协议版本

      • 服务端最高支持的握手协议版本,TLS/SSL协议都是向下兼容的。
    • Random/随机数

      • 服务端生成32字节安全随机数(MasterSecret生成会用到)
    • SessionID/会话ID

      • 如果客户端hello有发送session id,服务端从内存中查找,并尝试恢复之前的会话状态。

        • 恢复成功,服务端返回同样的session id。
        • 恢复不成功,服务端此字段返回空。
    • CipherSuite/加密组件

      • 服务端从客户端hello的cipher suite列表中选择一个加密套件,如果是恢复上一次的会话,则从会话状态中恢复上一次相同的加密套件。
    • CompressionMethod/压缩方法

      • 服务端从客户端hello的compression_methods列表中选择一个压缩方法,如果是恢复上一次的会话,则从会话状态中恢复上一次相同的压缩方法。
    • Extension/扩展(如下图)

  • 消息如下面所示:

6764230-9437955ec901ebca.jpg

3. Server Certificate

  • 服务端发送的是一个证书链,可能包含多个证书

    • 第一个证书为网站的证书。
    • 第二个证书为颁发证书给网站的机构的证书。
    • 在这个例子中第三个证书是CA机构的根证书,可以忽略不用发送,因为这个CA的根证书是CA自己给自己颁发的。 这里构成了一个证书信任链,也就是 GlobalSign Root CA信任GlobalSign Organization Validation CA,而他又信任baidu.com的证书。 如下图所示:

4.jpg

  • CA证书的类型有3类:DV ( domain validation),OV ( organization validation),EV ( extended validation),证书申请难度从前往后递增。
  • 证书中都包含了哪些信息? ```html
  • 证书版本号(Version)
  • 证书序列号(Serial Number)
  • 签名算法标识符(Signature Algorithm) 签名算法标识用来指定由CA签发证书时所使用的"签名算法"。算法标识符用来指定CA签发证书时所使用的: 1) 公开密钥算法 2) hash算法 example: sha256WithRSAEncryption 须向国际知名标准组织(如ISO)注册
  • 签发机构名(Issuer)
  • 有效期(Validity):指定证书的有效期
  • 证书用户名(Subject)
  • 证书持有者公开密钥信息(Subject Public Key Info) 证书持有者公开密钥信息域包含两个重要信息: 1) 证书持有者的公开密钥的值 2) 公开密钥使用的算法标识符。此标识符包含公开密钥算法和hash算法。
  • 扩展项(extension)
  • 签发者唯一标识符(Issuer Unique Identifier)
  • 证书持有者唯一标识符(Subject Unique Identifier)
  • 签名算法(Signature Algorithm)
  • 签名值(Issuer's Signature) ```
  • 如下图所示

5.jpg

6.jpg

如何校验服务端证书呢?

7.jpg

  • 签名的生成:CA先将证书信息生成hash摘要,然后再用CA机构的私钥进行加密。

  • 签名的校验:使用CA机构的公钥进行解密签名,得到hash摘要A,再计算证书信息的hash摘要B。比对是否一致。 #### 详细解释服务端的证书是怎么生成的?

  • 服务端的证书是由CA (Certificate Authority,证书认证中心)颁发的。他是一个负责发放和管理数字证书的第三方权威机构,它负责管理PKI(Public Key Infrastructure,公开密钥基础设施)结构下的所有用户(包括各种应用程序)的证书,把用户的公钥和用户的其他信息捆绑在一起,在网上验证用户的身份。

  • 一般情况下网站方向CA申请一个证书。CA会给网站方生成一对非对称加密的公钥私钥,公钥会做到证书里面,私钥则会给到网站方。

  • CA会先做一个“数字签名”(生成过程:明文 --> hash运算 --> 摘要 --> 私钥加密 --> 数字签名)

    • 就是将网站方的信息网站方的公钥签名算法等信息(就是Wireshark Packet 20中的数据,除了“签名值”),计算一个hash值(图中hash算法是SHA256),然后CA再用自己私钥做加密(图中公开密钥算法是RSA),最后的这个密文就是“数字签名”(也就是我们在图中看到“encrypted”签名值)。
  • CA最后将“网站方信息”、“网站方公钥”、“签名算法”、“签名值”都做到证书里面(就是Wireshark Packet 20中的我们看到那些数据),证书就做好了,CA会把“证书”和“网站方的私钥”给到网站方。

CA怎么验证证书是不是自己颁发的呢?以及做证书内容校验?

  • 首先浏览器(校验网站的证书)或操作系统(校验应用的证书),会在操作系统存储的系统信任的根证书里面去查找“证书颁发机构”是否是信任的。如下图系统根证书:

8.jpg

* 浏览器通常也会内置大多数主流权威CA的根证书。
* 如果查找不到对应的可信CA,则判断这个证书是伪造的,不可信的。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
  • 如果找到对应的CA机构,则取出CA机构证书里面的公钥信息,将网站方证书中的签名值(也就是数字签名)做解密,得到网站证书信息的hash摘要A。
  • 然后将网站证书中的信息,做hash得到摘要B,比对摘要A和摘要B是否一致。如果不一致,说明网站证书中的信息被修改了。(浏览器则会提醒该证书不是可信任机构颁发的,并询问是否要继续访问)
  • 如果摘要hash一致,则说明证书中的信息未被修改,这时浏览器会比对您现在正在访问的网站与证书中网站信息是否一致,比如域名是否一致、证书是否在有效期内等。(如果出现问题,浏览器将会提醒你,并询问是否要继续访问)
  • 另外大部分浏览器也会在线校验证书,是否在有效期内(将证书序列号通过在线证书状态协议“OCSP”发送给CA做校验)。
  • 证书校验成功,最后将从证书中取出网站方的公钥,用于后面的握手签名。

4. Server Key Exchange

  • 这个步骤是密钥协商的服务端部分,最终的密钥将会用于传输数据对称加密。
  • 服务端需要发送一个Diffie-Hellman算法的公钥,和指定使用哪种椭圆曲线多项式。
  • 我们到Client Key Exchange的时候,再来讲这个密钥协商过程。
  • 这里还有一个签名,校验这个流程的数据是否被篡改。如下图所示,客户端收到Server Key Exchange数据后,可以用上个流程中获得的证书公钥对签名值解密,获得摘要A。并将这次数据明文做SHA512的hash,获得摘要B,做比对。(这里对协商算法做签名校验,目的可能是防止中间人对协商算法方式做篡改,虽然DH算法不担心公钥在不安全的网络中传输,但是其他算法可能需要考虑被篡改的情况。所以猜测服务端密钥协商时做签名是这个目的,因为服务端这时已经确定是DH算法了,所以客户端协商时就不需要做签名了,DH算法不需要考虑这个安全问题)
  • 发送的数据如下图示:

11.jpg

5. Server Hello Done

  • 服务端发送ServerHelloDone消息表示,已经发送完了密钥协商需要的消息,并且客户端可以开始进行客户端的密钥协商处理了,也就是Client Key Exchange。
  • 收到ServerHelloDone后,客户端需要确认服务器是否提供了合法的证书,并且确认服务器的ServerHello消息里面的参数是否可以接受。

6. Client Key Exchange

  • 客户端生成自己用于密钥协商的公私钥,并发送此公钥

  • 这时客户端已经知道了服务端密钥协商的公钥以及自己的公钥

  • 我们以EC Diffie-Hellman密钥协商协议为例,来看看客户端、服务端是怎么协商出相同的密钥的(这里协商出来的是PreMasterSecret,不是最终的对称加密用到的密钥)。

  • EC Diffie-Hellman使用到一个数学难题,就是在给定的椭圆曲线上的一个点P,一个整数k,求Q=kP很容易;但是给定一个点P、Q,知道Q=kP,求整数k确实很难。

  • 服务端确定了密钥协商算法为“EC Diffie-Hellman”,发送给客户端。现在两端都知道了使用的是哪个曲线参数(椭圆曲线E、阶N、基点G)。

  • Server Key Change:服务端随机生成一个整数a,计算A=a*G,生成服务端公钥A,发送给客户端。

  • Client Key Change:客户端随机生成一个整数b,计算B=b*G,生成服务端公钥B,发送给服务端。

  • 客户端计算出PreMasterSecret:Q=bA=b(a*G)

  • 服务端计算出PreMasterSecret:Q'=aB=a(b*G),这两个计算结果是相等的,此时双方协商好对称密钥值。

  • 并且即使攻击者截获到双方公钥A、B,仍然无法计算出PreMasterSecret,因为攻击者需要知道随机整数a、b的其中任意一个,可是之前我们就提到过EC Diffie-Hellman协议中,知道A、G求a是很难的。

  • 真正对称加密使用到的密钥生成(这里使用到了client、server一开始hello中传输的随机数):

    • MasterSecret = PRF(PreMasterSecret, "master secret", Client.random || Server.random)[0..47] -- 固定取前 48 字节
    • KeyBlock = PRF(MasterSecret, "key expansion", Server.random || Client.random) -- 长度为由双方确定的密码算法套件决定
    • KeyBlock才是最终用来做对称加密的密钥块 6.3. Key Calculation

7. Client Change Cipher Spec

  • 这个过程就是告诉服务端,他已经准备好MasterSecret了,可以进行数据加密传输了。
  • 这个协议是冗余的,在TLS 1.3里面直接被删除了。

8. Client Finished

  • 这条消息是用来确定双方的MasterSecret是否正确生成,发送的是verify_data消息。
struct {
    opaque verify_data[verify_data_length];
} Finished;
​
verify_data
   PRF(master_secret, finished_label,Hash(handshake_messages))
      [0..verify_data_length-1];
  • verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))

    • PRF是伪随机函数(pseudorandom function,PRF)

    • master_secret是密钥协商时,计算出来的

    • finished_label:对客户端发的Finished消息来说,固定是字符串 "client finished". 对服务器发的Finished消息来说,固定是字符串 "server finished".

    • handshake_messages,是各端握手过程中发送的所有消息的,类型如下:

      struct {
          HandshakeType msg_type;    /* handshake type */
          uint24 length;             /* bytes in message */
          select (HandshakeType) {
              case hello_request:       HelloRequest;  //HelloRequest是服务端在任何时候都可以发出的,告诉客户端需要重新进行握手协议,客户端随即发送新的ClientHello    
              case client_hello:        ClientHello;
              case server_hello:        ServerHello;
              case certificate:         Certificate;//服务端或客户端发送自己证书给客户端。
              case server_key_exchange: ServerKeyExchange;
              case certificate_request: CertificateRequest;//服务端请求,客户端发送自己的客户端证书,给服务端做校验。这个步骤在博文中没有提到,看以后有需要再了解。
              case server_hello_done:   ServerHelloDone;
              case certificate_verify:  CertificateVerify;//客户端发出,从client hello开始,一直到CertificateVerify之前的所有消息的hash加上客户端证书对应私钥的加密结果。
              case client_key_exchange: ClientKeyExchange;
              case finished:            Finished;
          } body;
      } Handshake;
      
  • 但不包括ChangeCipherSpec、alerts之类的消息。并且最后一个发送Finished的一方,需要把前一个发送Finished的内容包括进去。

  • 注意这里每个端发送自己的握手消息就可以,比如Client发送内容包括ClientHello、Certificate(有发送的话)、CertificateVerify(如果有发送的话)、ClientKeyExchange、Finished(如果是最后一方需要包含)。服务端同理。

12.jpg

  • 因为verify_data是加密的,我就没有在截图了,上述的字段以及说明可以查看协议文档 7.4.9. Finished

8.1. Server New Session Ticket

  • 如果服务端想使用Ticket方式存储session状态,在Server Change Cipher Spec之前就需要发送New Session Ticket消息。

  • New Session Ticket方式与Session ID方式对比:

    • SessionID方式,客户端在ClientHello的时候带着上一次SessionID过来,服务端从自己内存中查找SessionID对应的session状态,并读取session状态快速恢复。

    • SessionTicket方式,则是将session状态加密后,发送给客户端存储。客户端在ClientHello时将SessionTicket带上,服务端就将其解密,读取出里面存储的session状态信息,SessionTicket存储的信息如下:

      struct {
          ProtocolVersion protocol_version; //协议版本
          CipherSuite cipher_suite; //加密套件类型
          CompressionMethod compression_method;    //压缩方法
          opaque master_secret[48]; //对称密钥
          ClientIdentity client_identity; //客户端ID
          uint32 timestamp;//ticket有效期
      } StatePlaintext;
      

9. Server Change Cipher Spec

  • 告诉客户端,我已经准备好进行加密传输了。

10. Server Finished

  • 与8. Client Finished的情况一样,使用对称密钥加密,最后做一次验证,确定双方是否都准备好进行数据传输了。只是这里加密的数据还不是真正的网站内容数据,而是握手过程的数据。

13.jpg

11. Application Data

  • 真正的网站数据传输,但是这里的数据就是经过握手时协商好的对称密钥进行加密的了。
  • 现在我们有KeyBlock(对称密钥块),也知道对称加密算法是AES-128-GCM 5.1. AEAD_AES_128_GCM

伪随机数函数:

PRF 是一个“伪随机数函数”,这个函数很聪明,在规约中也有定义。它使用基于哈希的消息验证码(HMAC)的MD5SHA-1两种哈希函数将密钥,ASCII 字符以及我们给的种子结合起来。对每个哈希函数发送一半的输入。说它聪明的原因是即使面对MD5和 SHA-1 的弱点,它的防攻击能力还很强。这个过程可以自我反馈并不停地循环,而且我们要多少字节就能生成多少。

依照这个过程,我们获得以下 48 字节的“master secret”:

4C AF 20 30 8F 4C AA C5 66 4A 02 90 F2 AC 10 00 39 DB 1D E0 1F CB E0 E0 9D D7 E6 BE 62 A4 6C 18 06 AD 79 21 DB 82 1D 53 84 DB 35 A7 1F C1 01 19

多个密钥的生成

现在双方都有了“master secrets”,规约描述了我们如何生成会话所需的所有的密钥,我们需要使用 PRF 函数来创建一个“key block”,然后从这个块中提取所需的密钥:

key_block = PRF(SecurityParameters.master_secret, "key expansion", SecurityParameters.server_random + SecurityParameters.client_random);

“key_block”被用来提取以下密钥:

client_write_MAC_secret[SecurityParameters.hash_size]

server_write_MAC_secret[SecurityParameters.hash_size]

client_write_key[SecurityParameters.key_material_length]

server_write_key[SecurityParameters.key_material_length]

client_write_IV[SecurityParameters.IV_size]

server_write_IV[SecurityParameters.IV_size]

1 -- client_write_MAC_secret 客户端MAC密钥,生成消息的认证码,对方用其验证消息 2 -- server_write_MAC_secret 服务器MAC密钥,生成消息的认证码,对方用其验证消息 3 -- client_write_key 客户端加密密钥,加密客户端发送的消息,对方用其解密 4 -- server_write_key 服务器加密密钥,服务器加密发送的消息,对方用其解密 5 -- client_write_IV 客户端IV,与客户端加密密钥配合使用(分组密码算法) 6 -- server_write_IV 服务器IV,与服务器加密密钥配合使用(分组密码算法)

由于这里使用的是序列密码而非分组密码(如高级加密标准AES),所以不需要初始向量(Initialization Vectors IV),而只是双方各需要一个 16 字节(128 比特)的消息验证码(Message Authentication Code MAC),这是因为指定的 MD5 哈希摘要大小是 16 字节。另外,RC4 加密算法使用的 16 字节的密码也是双方都需要的。最后,我们需要 key block 中的 216 + 216 = 64 个字节:

运行 PRF,我们得到:

client_write_MAC_secret = 80 B8 F6 09 51 74 EA DB 29 28 EF 6F 9A B8 81 B0

server_write_MAC_secret = 67 7C 96 7B 70 C5 BC 62 9D 1D 1F 4A A6 79 81 61

client_write_key = 32 13 2C DD 1B 39 36 40 84 4A DE E5 6C 52 46 72

server_write_key = 58 36 C4 0D 8C 7C 74 DA 6D B7 34 0A 91 B6 8F A7

准备加密!

小结:

上面的实例描述了TLS握手协议的流程,内容比较多。其中有几处关键的加密过程这里再总结一下。

公钥和私钥: 加密算法分为两种,对称加密和非对称加密。

对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。

非对称加密为数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。

使用公钥和私钥的加密方式是非对称加密。公钥和私钥的名称区别是已秘钥提供者来做区分的。不管服务器还是客户端,向申请者提供的密钥都是公钥,自己保存的私钥。也就是说服务器和客户端都是可以充当密钥提供方的角色的,私钥只能保存在秘钥提供方的手里,而公钥是可以公开的。如果需要和密钥提供方进行交互,就需要使用对应的密钥提供发提供的公钥对数据加密,加密后的数据只有密钥提供方来使用自己的私钥来解密。总结来说就是:公钥加密,私钥解密;客户端和服务器都可能有自己对应的公钥和私钥

三个随机数: 握手过程中产生了三个随机数

第一个随机数是客户端发送Client Hello请求时,在客户端生成,发送给服务器的。

第二个随机数是服务器发送Server Hello请求时,在服务器生成,发送给客户端的。

第三个随机数是客户端校验证书通过后,在客户端生成的。这个随机数会通过证书里面的公钥进行加密,然后再发给服务器,这个随机数称为PreMasterSecret。(这是使用RSA算法实现的,其他的密钥交换算法还有DHE_RSA、ECDHE_RSA和ECDHE_ECDSA 后面的这三种算法实现起来都RSA复杂,如果不是做这方面的业务或者数学功底比较强的,建议不要去研究)。

三个随机数用来生成MasterSecret

img

参考文献

《HTTPS权威指南》

HTTP和TCP的区别

TLS握手协议分析与理解——某HTTPS请求流量包分析

HTTPS 连接最初的若干毫秒

安全协议系列(四)----SSL与TLS

图解SSL/TLS协议

www.cnblogs.com/-9-8/p/7985…

wenku.baidu.com/view/15b658…

www.ruanyifeng.com/blog/2014/0…

www.infoq.cn/article/HTT…

www.cnblogs.com/efzju/p/367…