3.4HTTPS ECDHE握手解析
RSA是比较传统的密钥交换算法,它不具备前向安全的性质,因此现在很少服务器使用,而ECDHE算法具有前向安全,所以被广泛使用。
离散对数
ECDHE密钥协商算法是由DH算法演进过来的,DH算法是非对称加密算法,因此它可以用于密钥交换,算法核心是离散对数。
离散对数是在对数运算的基础上加了[模运算],也就是取余数(%,mod).
上图中,底数a和模数p是离散对数的公共参数,b是真数,i是对数,直到了对数i就可以用上面的公式计算出真数b。但反过来,知道真数b却很难推算出对数。
特别是当模数p是一个很大的质数,即使知道底数a和真数b,在现有的计算机的计算水平是几乎无法算出离散对数的,这就是DH算法的数学基础。
DH算法
先假设小红和小明约定使用DH算法来交换密钥,那么基于离散对数,小红和小明需要先确定模数和底数作为算法的参数,这两个参数是公开的,用P和G来代称。
然后小红和小明各自生成一个随机整数作为私钥,双方的私钥要各自严格保管,不能泄漏,小红的私钥用a代称,小明的私钥用b代称。
现在小红和小明双方都有了P和G以及各自的私钥,于是计算出公钥:
- 小红的公钥记为A,A=G^a(mod P);
- 小明的公钥记为B,A=G^b(mod P);
A和B也是公开的,因为根据离散对数的原理,从真数(A和B)反向计算对数a和b是非常困难的。
双方交换各自DH公钥,小红手里共有五个数:P、G、a、A、B,小明手上也同样共有5个数:P、G、b、A、B。
然后小红执行运算,B^a(mod P),其结果为K,因为离散对数的幂运算有交换律,
所以小明执行运算:A^b(mod P),得到的结果也是K
这个K就是小红和小明之间用的对称加密密钥,可以作为会话密钥使用。
整个密钥协商过程中,小红和小明公开了4个信息,P、G、A、B,其中P、G是算法的参数,A和B是公钥,而a和b是双方各自保管的私钥,黑客无法获取这两个私钥,因此黑客只能从公开的P、G、A、B入手,计算出离散对数(私钥)。根据离散对数的原理,如果P是一个大数,在现有的计算机能力是很难破解私钥a和b的,破解不出私钥,也就无法计算出会话密钥,因此DH密钥交换是安全的。
DHE算法
根据私钥生成的方式,DH算法分为两种实现:
(1)static DH算法
有一方的私钥是静态的,也就是说每次密钥协商的时候有一方的私钥都是一样的,一般是服务器方固定,即a不变,客户端的私钥则是随机生成的。
于是,DH交换密钥就只有客户端的公钥是变化的,而服务端公钥是不变的,那么随着时间延长,黑客就会截获海量的密钥协商过程的数据,因为密钥协商的过程有些数据是公开的,黑客就可以依据这些数据暴力破解出服务器的私钥,然后就可以计算出会话密钥,于是之前截获的加密数据会被破解,所以static DH算法不具备前向安全性,这个方法已经被废弃了。
这个方法已经被废弃了。
(2)DHE算法
既然固定一方的私钥有被破解的风险,那么干脆就让双方的私钥在每次密钥交换通信时,都是随机生成的、临时的,即DHE算法,E(ephemeral,临时性的)
即使有个厉害的黑客破解了某一次通信过程的私钥,其他通信过程的私钥仍然是安全的,因为每个通信过程的私钥都是没有任何关系的,独立的,保证了前向安全。
ECDHE算法
DHE算法计算性能不佳,需要做大量的乘法,为了提升DHE算法的性能,出现了现在广泛用于密钥交换的算法-ECDHE算法。
ECDHE算法是在DHE算法的基础上利用了ECC椭圆曲线特性,可以用更少的计算量计算出公钥,以及最终的会话密钥。
小红和小明使用ECDHE密钥交换算法的过程:
(1)双方事先确定好使用哪种椭圆曲线,和曲线上的基点G,这两个参数都是公开的;
(2)双方各自随机生成一个随机数作为私钥d,并与基点G相乘得到公钥Q(Q=dG),此时小红的公钥私钥分别为Q1和d1,小明的公钥私钥分别为Q2和d2;
(3)双方交换各自的公钥,最后小红计算点(x1,y1)=d1Q2,小明计算点(x2,y2)=d2Q1,由于椭圆曲线上可以满足乘法交换和结合律,所以d1Q2=d1d2G=d2d1G=d2Q1,因此,双方的x坐标是一样的,所以它是共享密钥,也就是会话密钥。
这个过程中,双方的私钥都是随机、临时生成的,都是不公开的,即使根据公开的信息(椭圆曲线、公钥、基点)也是很难计算出椭圆曲线上的离散对数(私钥)。
ECDHE握手过程
使用ECDHE,在TLS第四次握手前,客户端就已经发送了加密的HTTP数据,而对于RSA握手过程,必须要完成TLS四次握手,才能传输应用数据。
所以,ECDHE相比RSA握手过程省去了一个消息往返的时间【TLS False Start】,跟【TCP Fast Open】有点像,都是在还没连接完全建立前,就发送了应用数据,这样提高了传输效率。
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]消息,会把证书也发给客户端
因为服务器选择了ECDHE密钥协商算法,所以会在发送完证书后,发送[Server Key Exchange]==消息
这个过程服务器做了三件事: - 选择了名为x25519的椭圆曲线,选好了椭圆曲线相当于椭圆曲线基点G也定好了,这些都会公开给客户端
- 生成随机数作为服务端椭圆曲线的私钥,保留到本地
- 根据基点G和私钥计算出服务端的椭圆曲线公钥,公钥会公开给客户端
随后,就是[Server Hello Done]消息,服务端跟客户端表明:“这些就是我提供的信息,打招呼完毕”。
至此,TLS两次握手就已经完成,目前客户端和服务端通过明文共享:Client Random、Server Random、使用的椭圆曲线、椭圆曲线基点G、服务端椭圆曲线的公钥,这些是后续生成会话密钥的材料。
TLS第三次握手
客户端收到了服务端的证书后,验证证书是否合法,如果证书合法,那么服务端的身份就是没问题的。校验证书的过程会走证书链逐级验证,确认证书的真实性,再用证书的公钥验证签名,这样就能确认服务端的身份,确认无误后,就可以继续往下走。
客户端会生成一个随机数作为客户端椭圆曲线的私钥,然后再根据服务端前面的信息,生成客户端的椭圆曲线公钥,然后用==[Client Key Exchange]消息发给服务端
至此,双方都有对方对方的椭圆曲线公钥,自己的椭圆曲线私钥、椭圆曲线基点G。于是,双方就计算出点(x,y),其中,x坐标值双方是一样的,前面ECDHE算法中x是会话密钥,但实际应用中,x还不是最终的会话密钥。
最终的会话密钥,就是用【客户端随机数+服务端随机数+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,在第2次握手中,会出现服务端发出[Server Key Exchange]消息,而RSA握手过程没有该消息。