图解 ECDHE 密钥交换算法

HTTPS 经常使用的密钥交换算法有两种,分别是 RSA 和 ECDHE 算法。算法

其中,RSA 是比较传统的密钥交换算法,它不具有前向安全的性质,所以如今不多服务器使用的。而 ECDHE 算法具备前向安全,因此被普遍使用。编程

我在上一篇已经介绍了 RSA 握手的过程,今天这一篇就「从理论再到实战抓包」介绍 ECDHE 算法安全


离散对数

ECDHE 密钥协商算法是 DH 算法演进过来的,因此咱们先从 DH 算法提及。服务器

DH 算法是非对称加密算法, 所以它能够用于密钥交换,该算法的核心数学思想是离散对数app

是否是听到这个数学概念就怂了?不怕,此次不会说离散对数推到的过程,只简单提一下它的数学公式。dom

离散对数是「离散 + 对数」的两个数学概念的组合,因此咱们先来复习一遍对数。编程语言

要提及对数,必然要说指数,由于它们是互为反函数,指数就是幂运算,对数是指数的逆运算。函数

举个栗子,若是以 2 做为底数,那么指数和对数运算公式,以下图所示:工具

那么对于底数为 2 的时候, 32 的对数是 5,64 的对数是 6,计算过程以下:性能

对数运算的取值是能够连续的,而离散对数的取值是不能连续的,所以也以「离散」得名,

离散对数是在对数运算的基础上加了「模运算」,也就说取余数,对应编程语言的操做符是「%」,也能够用 mod 表示。离散对数的概念以下图:

上图的,底数 a 和模数 p 是离散对数的公共参数,也就说是公开的,b 是真数,i 是对数。知道了对数,就能够用上面的公式计算出真数。但反过来,知道真数却很难推算出对数。

特别是当模数 p 是一个很大的质数,即便知道底数 a 和真数 b ,在现有的计算机的计算水平是几乎没法算出离散对数的,这就是 DH 算法的数学基础。


DH 算法

认识了离散对数,咱们来看看 DH 算法是如何密钥交换的。

现假设小红和小明约定使用 DH 算法来交换密钥,那么基于离散对数,小红和小明须要先肯定模数和底数做为算法的参数,这两个参数是公开的,用 P 和 G 来代称。

而后小红和小明各自生成一个随机整数做为私钥,双方的私钥要各自严格保管,不能泄漏,小红的私钥用 a 代称,小明的私钥用 b 代称。

如今小红和小明双方都有了 P 和 G 以及各自的私钥,因而就能够计算出公钥

  • 小红的公钥记做 A,A = G ^ a ( mod P );
  • 小明的公钥记做 B,B = G ^ b ( mod P );

A 和 B 也是公开的,由于根据离散对数的原理,从真数(A 和 B)反向计算对数 a 和 b 是很是困难的,至少在现有计算机的计算能力是没法破解的,若是量子计算机出来了,那就有可能被破解,固然若是量子计算机真的出来了,那么密钥协商算法就要作大的升级了。

双方交换各自 DH 公钥后,小红手上共有 5 个数:P、G、a、A、B,小明手上也一样共有 5 个数:P、G、b、B、A。

而后小红执行运算: B ^ a ( mod P ),其结果为 K,由于离散对数的幂运算有交换律,因此小明执行运算: A ^ b ( mod P ),获得的结果也是 K。

这个 K 就是小红和小明之间用的对称加密密钥,能够做为会话密钥使用。

能够看到,整个密钥协商过程当中,小红和小明公开了 4 个信息:P、G、A、B,其中 P、G 是算法的参数,A 和 B 是公钥,而 a、b 是双方各自保管的私钥,黑客没法获取这 2 个私钥,所以黑客只能从公开的 P、G、A、B 入手,计算出离散对数(私钥)。

前面也屡次强调, 根据离散对数的原理,若是 P 是一个大数,在现有的计算机的计算能力是很难破解出 私钥 a、b 的,破解不出私钥,也就没法计算出会话密钥,所以 DH 密钥交换是安全的。


DHE 算法

根据私钥生成的方式,DH 算法分为两种实现:

  • static DH 算法,这个是已经被废弃了;
  • DHE 算法,如今经常使用的;

static DH 算法里有一方的私钥是静态的,也就说每次密钥协商的时候有一方的私钥都是同样的,通常是服务器方固定,即 a 不变,客户端的私钥则是随机生成的。

因而,DH 交换密钥时就只有客户端的公钥是变化,而服务端公钥是不变的,那么随着时间延长,黑客就会截获海量的密钥协商过程的数据,由于密钥协商的过程有些数据是公开的,黑客就能够依据这些数据暴力破解出服务器的私钥,而后就能够计算出会话密钥了,因而以前截获的加密数据会被破解,因此 static DH 算法不具有前向安全性

既然固定一方的私钥有被破解的风险,那么干脆就让双方的私钥在每次密钥交换通讯时,都是随机生成的、临时的,这个方式也就是 DHE 算法,E 全称是 ephemeral(临时性的)。

因此,即便有个牛逼的黑客破解了某一次通讯过程的私钥,其余通讯过程的私钥仍然是安全的,由于每一个通讯过程的私钥都是没有任何关系的,都是独立的,这样就保证了「前向安全」


ECDHE 算法

DHE 算法因为计算性能不佳,由于须要作大量的乘法,为了提高 DHE 算法的性能,因此就出现了如今普遍用于密钥交换算法 —— ECDHE 算法

ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,能够用更少的计算量计算出公钥,以及最终的会话密钥。

小红和小明使用 ECDHE 密钥交换算法的过程:

  • 双方事先肯定好使用哪一种椭圆曲线,和曲线上的基点 G,这两个参数都是公开的;
  • 双方各自随机生成一个随机数做为私钥d,并与基点 G相乘获得公钥Q(Q = dG),此时小红的公私钥为 Q1 和 d1,小明的公私钥为 Q2 和 d2;
  • 双方交换各自的公钥,最后小红计算点(x1,y1) = d1Q2,小明计算点(x2,y2) = d2Q1,因为椭圆曲线上是能够知足乘法交换和结合律,因此 d1Q2 = d1d2G = d2d1G = d2Q1 ,所以双方的 x 坐标是同样的,因此它是共享密钥,也就是会话密钥

这个过程当中,双方的私钥都是随机、临时生成的,都是不公开的,即便根据公开的信息(椭圆曲线、公钥、基点 G)也是很难计算出椭圆曲线上的离散对数(私钥)。


ECDHE 握手过程

知道了 ECDHE 算法基本原理后,咱们就结合实际的状况来看看。

我用 Wireshark 工具抓了用 ECDHE 密钥协商算法的 TSL 握手过程,能够看到是四次握手:

细心的小伙伴应该发现了,使用了 ECDHE,在 TLS 第四次握手前,客户端就已经发送了加密的 HTTP 数据,而对于 RSA 握手过程,必需要完成 TLS 四次握手,才能传输应用数据。

因此,ECDHE 相比 RSA 握手过程省去了一个消息往返的时间,这个有点「抢跑」的意思,它被称为是「TLS False Start」,跟「TCP Fast Open」有点像,都是在还没链接彻底创建前,就发送了应用数据,这样便提升了传输的效率。

接下来,分析每个 ECDHE 握手过程。

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。因而,双方都就计算出点(x,y),其中 x 坐标值双方都是同样的,前面说 ECDHE 算法时候,说 x 是会话密钥,但实际应用中,x 还不是最终的会话密钥

还记得 TLS 握手阶段,客户端和服务端都会生成了一个随机数传递给对方吗?

最终的会话密钥,就是用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」三个材料生成的

之因此这么麻烦,是由于 TLS 设计者不信任客户端或服务器「伪随机数」的可靠性,为了保证真正的彻底随机,把三个不可靠的随机数混合起来,那么「随机」的程度就很是高了,足够让黑客计算出最终的会话密钥,安全性更高。

算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通讯。

接着,客户端会发「Encrypted Handshake Message」消息,把以前发送的数据作一个摘要,再用对称密钥加密一下,让服务端作个验证,验证下本次生成的对称密钥是否能够正常使用。

TLS 第四次握手

最后,服务端也会有一个一样的操做,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,若是双方都验证加密和解密没问题,那么握手正式完成。因而,就能够正常收发加密的 HTTP 请求和响应了。


总结

RSA 和 ECDHE 握手过程的区别:

  • RSA 密钥协商算法「不支持」前向保密,ECDHE 密钥协商算法「支持」前向保密;
  • 使用了 RSA 密钥协商算法,TLS 完成四次握手后,才能进行应用数据传输,而对于 ECDHE 算法,客户端能够不用等服务端的最后一次 TLS 握手,就能够提早发出加密的 HTTP 数据,节省了一个消息的往返时间;
  • 使用 ECDHE, 在 TLS 第 2 次握手中,会出现服务器端发出的「Server Key Exchange」消息,而 RSA 握手过程没有该消息;

巨人的肩膀
  1. https://zh.wikipedia.org/wiki/橢圓曲線迪菲-赫爾曼金鑰交換
  2. https://zh.wikipedia.org/wiki/椭圆曲线
  3. https://zh.wikipedia.org/wiki/迪菲-赫爾曼密鑰交換
  4. https://time.geekbang.org/column/article/148188
  5. https://zhuanlan.zhihu.com/p/106967180
相关文章
相关标签/搜索