文章目录
- 1. RSA算法
- RSA握手过程
- RSA秘钥协商算法最大的缺陷
- 2. DH算法
- 3. DHE算法
- 4. ECDHE算法
- ECDHE秘钥协商算法的TSL握手
1. RSA算法
传统的 TLS 握⼿基本都是使⽤ RSA 算法来实现密钥交换的。在 RSA 密钥协商算法中客户端会⽣成随机密钥并使⽤服务端的公钥加密后再传给服务端。根据⾮对称加密算法公钥加密的消息仅能通过私钥解密这样服务端解密后双⽅就得到了相同的密钥再⽤它加密应⽤消息。
RSA握手过程
TLS第一次握手
客户端⾸先会发⼀个「Client Hello」消息消息⾥⾯有客户端使⽤的 TLS 版本号、⽀持的密码套件列表以及⽣成的随机数Client Random这个随机数会被服务端保留它是⽣成对称加密密钥的材料之⼀。
TLS第二次握手
当服务端收到客户端的「Client Hello」消息后会确认 TLS 版本号是否⽀持和从密码套件列表中选择⼀个密码套件以及⽣成随机数Server Random。
接着返回「Server Hello」消息消息⾥⾯有服务器确认的 TLS 版本号也给出了随机数Server Random然后从客户端的密码套件列表选择了⼀个合适的密码套件。
可以看到服务端选择的密码套件是 “Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256”。
这个密码套件看起来真让⼈头晕好⼀⼤串但是其实它是有固定格式和规范的。基本的形式是「密钥交换算法 签名算法 对称加密算法 摘要算法」 ⼀般 WITH 单词前⾯有两个单词第⼀个单词是约定密钥交换的算法第⼆个单词是约定证书的验证算法。 ⽐如刚才的密码套件的意思就是由于 WITH 单词只有⼀个 RSA则说明握⼿时密钥交换算法和签名算法都是使⽤ RSA握⼿后的通信使⽤ AES 对称算法密钥⻓度 128 位分组模式是 GCM摘要算法 SHA384 ⽤于消息认证和产⽣随机数就前⾯这两个客户端和服务端相互「打招呼」的过程客户端和服务端就已确认了 TLS 版本和使⽤的密码套件⽽且你可能发现客户端和服务端都会各⾃⽣成⼀个随机数并且还会把随机数传递给对⽅。
然后服务端为了证明⾃⼰的身份会发送「Server Certificate」给客户端这个消息⾥含有数字证书。
随后服务端发了「Server Hello Done」消息⽬的是告诉客户端我已经把该给你的东⻄都给你了本次打招呼完毕。
【补充】
CA 签发证书的过程
-
⾸先 CA 会把持有者的公钥、⽤途、颁发者、有效时间等信息打成⼀个包然后对这些信息进行 Hash 计算得到⼀个 Hash 值
-
然后 CA 会使⽤自己的私钥将该 Hash 值加密⽣成 Certificate Signature也就是 CA 对证书做了签名
-
最后将 Certificate Signature 添加在⽂件证书上形成数字证书
客户端校验服务端的数字证书的过程
-
⾸先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1(数字摘要)
-
通常浏览器和操作系统中集成了 CA 的公钥信息浏览器收到证书后可以使⽤ CA 的公钥解密 Certificate
Signature 内容得到⼀个 Hash 值 H2(数字摘要)。
-
最后⽐较 H1 和 H2如果值相同则为可信赖的证书否则则认为证书不可信。
TLS第三次握手
客户端验证完证书后认为可信则继续往下⾛。接着客户端就会⽣成⼀个新的随机数 (pre-master预主秘钥)⽤服务器的 RSA 公钥加密该随机数通过「Change Cipher Key Exchange」消息传给服务端。
服务端收到后⽤ RSA 私钥解密得到客户端发来的随机数 (pre-master)。
⾄此客户端和服务端双⽅都共享了三个随机数分别是 Client Random、Server Random、pre-master。
于是双⽅根据已经得到的三个随机数⽣成会话密钥Master Secret它是对称密钥⽤于对后续的 HTTP请求/响应的数据加解密。
⽣成完会话密钥后然后客户端发⼀个「Change Cipher Spec」告诉服务端开始使⽤加密⽅式发送消息。
然后客户端再发⼀个「Encrypted Handshake MessageFinishd」消息把之前所有发送的数据做个摘要再⽤会话密钥master secret加密⼀下让服务器做个验证验证加密通信是否可⽤和之前握⼿信息是否有被中途篡改过。
可以发现「Change Cipher Spec」之前传输的 TLS 握⼿数据都是明⽂之后都是对称密钥加密的密⽂。
TLS第四次握手
服务器也是同样的操作发「Change Cipher Spec」和「Encrypted Handshake Message」消息如果双⽅都验证加密和解密没问题那么握⼿正式完成。
最后就⽤「会话密钥」加解密 HTTP 请求和响应了。
RSA秘钥协商算法最大的缺陷
使用 RSA 密钥协商算法的最⼤问题是不⽀持前向保密。因为客户端传递随机数⽤于⽣成对称加密密钥的条件之⼀给服务端时使⽤的是公钥加密的服务端收到到后会⽤私钥解密得到随机数。所以⼀旦服务端的私钥泄漏了过去被第三⽅截获的所有 TLS 通讯密⽂都会被破解。
为了解决这⼀问题于是就有了 DH 密钥协商算法这⾥简单介绍它的⼯作流程。
客户端和服务端各⾃会⽣成随机数并以此作为私钥然后根据公开的 DH 计算公示算出各⾃的公钥通过 TLS握⼿双⽅交换各⾃的公钥这样双⽅都有⾃⼰的私钥和对⽅的公钥然后双⽅根据各⾃持有的材料算出⼀个随机数这个随机数的值双⽅都是⼀样的这就可以作为后续对称加密时使⽤的密钥。
DH 密钥交换过程中即使第三⽅截获了 TLS 握⼿阶段传递的公钥在不知道的私钥的情况下也是⽆法计算出密钥的而且每⼀次对称加密密钥都是实时生成的实现前向保密。
但因为 DH 算法的计算效率问题后⾯出现了 ECDHE 密钥协商算法我们现在⼤多数⽹站使⽤的正是 ECDHE 密钥协商算法。
2. DH算法离散对数应用于DH算法
解析小红、小明各自生成自己的私钥(a、b)通过公开公共参数(G、P)算出各自的公钥(A、B)随之双方交换公钥后⼩红手上共有 5 个数P、G、a、A、B小明手上也同样共有 5 个数P、G、b、B、 A。
然后小红执行运算 B ^ a ( mod P )其结果为 K因为离散对数的幂运算有交换律所以小明执行运算 A ^ b (mod P )得到的结果也是 K。
这个 K 就是小红和小明之间⽤的对称加密密钥可以作为会话密钥使⽤。
因为在DH密钥协商算法中服务器的公私密钥是固定的只有客户端的公钥是会话时当即随机生成所以安全隐患很大也就被废弃了
3. DHE算法根据私钥生成的方式DH 算法分为两种实现
-
static DH 算法这个是已经被废弃了(服务器方公钥固定所以 static DH 算法不具备前向安全性
-
DHE 算法现在常用的
DHEE全程为ephemeral临时性的
既然固定⼀⽅的私钥有被破解的⻛险那么⼲脆就让双⽅的私钥在每次密钥交换通信时都是随机⽣成的、临时的这个⽅式也就是 DHE 算法。所以即使有个⽜逼的⿊客破解了某⼀次通信过程的私钥其他通信过程的私钥仍然是安全的因为每个通信过程的私钥都是没有任何关系的都是独⽴的这样就保证了「前向安全」。
4. ECDHE算法DHE 算法由于计算性能不佳因为需要做⼤量的乘法为了提升 DHE 算法的性能所以就出现了现在⼴泛⽤于密钥交换算法 —— ECDHE 算法。
ECDHE 算法是在 DHE 算法的基础上利⽤了 ECC 椭圆曲线特性可以⽤更少的计算量计算出公钥以及最终的会话密钥。
下面通过一个故事来叙述一下ECDHE密钥协商算法的原理
小红和小明使用 ECDHE 密钥交换算法的过程
-
双⽅事先确定好使⽤哪种椭圆曲线和曲线上的基点 G这两个参数都是公开的
-
双⽅各⾃随机⽣成⼀个随机数作为私钥d并与基点 G相乘得到公钥QQ dG此时⼩红的公私钥为 Q1和 d1⼩明的公私钥为 Q2 和 d2
-
双⽅交换各⾃的公钥最后⼩红计算点x1y1 d1Q2⼩明计算点x2y2 d2Q1由于椭圆曲线上是可以满⾜乘法交换和结合律所以 d1Q2 d1d2G d2d1G d2Q1 因此双方的 x 坐标是⼀样的所以它是共享密钥也就是会话密钥。
这个过程中双方的私钥都是随机、临时⽣成的都是不公开的即使根据公开的信息椭圆曲线、公钥、基点G也是很难计算出椭圆曲线上的离散对数私钥。
ECDHE秘钥协商算法的TSL握手
TLS第一次握手
客户端⾸先会发⼀个「Client Hello」消息消息⾥⾯有客户端使⽤的 TLS 版本号、⽀持的密码套件列表以及生成的随机数Client Random。
TLS第二次握手
服务端收到客户端的「打招呼」同样也要回礼会返回「Server Hello」消息消息⾯有服务器确认的 TLS 版本号也给出了⼀个随机数Server Random然后从客户端的密码套件列表选择了⼀个合适的密码套件。
不过这次选择的密码套件就和 RSA 不⼀样了我们来分析⼀下这次的密码套件的意思。
「 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384」
密钥协商算法使⽤ ECDHE
签名算法使⽤ RSA
握⼿后的通信使⽤ AES 对称算法密钥⻓度 256 位分组模式是 GCM
摘要算法使⽤ SHA384
接着服务端为了证明自己的身份发送「Certificate」消息会把证书也发给客户端。
这⼀步就和 RSA 握⼿过程有很⼤到区别了因为服务端选择了 ECDHE 密钥协商算法所以会在发送完证书后发送「Server Key Exchange」消息。
这个过程服务器做了三件事
-
选择了名为 named_curve 的椭圆曲线选好了椭圆曲线相当于椭圆曲线基点 G 也定好了这些都会公开给客户端
-
⽣成随机数作为服务端椭圆曲线的私钥保留到本地
-
根据基点 G 和私钥计算出服务端的椭圆曲线公钥这个会公开给客户端。
为了保证这个椭圆曲线的公钥不被第三⽅篡改服务端会⽤ RSA 签名算法给服务端的椭圆曲线公钥做个签名。
随后就是「Server Hello Done」消息服务端跟客户端表明“这些就是我提供的信息打招呼完毕”。
⾄此TLS 两次握⼿就已经完成了⽬前客户端和服务端通过明⽂共享了这⼏个信息Client Random、Server Random 、使用的椭圆曲线、椭圆曲线基点 G、服务端椭圆曲线的公钥这⼏个信息很重要是后续⽣成会话密钥的材料。
TLS第三次握手
客户端收到了服务端的证书后⾃然要校验证书是否合法如果证书合法那么服务端到身份就是没问题的。校验证书到过程会⾛证书链逐级验证确认证书的真实性再⽤证书的公钥验证签名这样就能确认服务端的身份了确认⽆误后就可以继续往下⾛。
客户端会⽣成⼀个随机数作为客户端椭圆曲线的私钥然后再根据服务端前⾯给的信息⽣成客户端的椭圆曲线公钥然后⽤「Client Key Exchange」消息发给服务端。
⾄此双⽅都有对⽅的椭圆曲线公钥、⾃⼰的椭圆曲线私钥、椭圆曲线基点 G。于是双⽅都就计算出点xy其中 x 坐标值双⽅都是⼀样的前⾯说 ECDHE 算法时候说 x 是会话密钥但实际应⽤中x 还不是最终的会话密钥。
还记得 TLS 握⼿阶段客户端和服务端都会⽣成了⼀个随机数传递给对⽅吗
最终的会话密钥就是⽤「客户端随机数 服务端随机数 xECDHE 算法算出的共享密钥 」三个材料生成的。
之所以这么麻烦是因为 TLS 设计者不信任客户端或服务器「伪随机数」的可靠性为了保证真正的完全随机把三个不可靠的随机数混合起来那么「随机」的程度就⾮常⾼了⾜够让⿊客计算出最终的会话密钥安全性更⾼。
算好会话密钥后客户端会发⼀个「Change Cipher Spec」消息告诉服务端后续改⽤对称算法加密通信。
接着客户端会发「Encrypted Handshake Message」消息把之前发送的数据做⼀个摘要再⽤对称密钥加密⼀下让服务端做个验证验证下本次⽣成的对称密钥是否可以正常使⽤。
TLS第四次握手
最后服务端也会有⼀个同样的操作发「Change Cipher Spec」和「Encrypted Handshake Message」消息如果双⽅都验证加密和解密没问题那么握⼿正式完成。于是就可以正常收发加密的 HTTP 请求和响应了。