部分内容来源:小林coding
DHE 算法由于计算性能不佳,因为需要做大量的乘法,为了提升 DHE 算法的性能,所以就出现了现在广泛用于密钥交换算法 —— ECDHE 算法。
ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量计算出公钥,以及最终的会话密钥。
小红和小明使用 ECDHE 密钥交换算法的过程:
这个过程中,双方的私钥都是随机、临时生成的,都是不公开的,即使根据公开的信息(椭圆曲线、公钥、基点 G)也是很难计算出椭圆曲线上的离散对数(私钥)
RSA 和 ECDHE 握手过程的区别:
1.RSA 密钥协商算法「不支持」前向保密,ECDHE 密钥协商算法「支持」前向保密;
2.使用了 RSA 密钥协商算法,TLS 完成四次握手后,才能进行应用数据传输 而对于 ECDHE 算法,客户端可以不用等服务端的最后一次 TLS 握手,就可以提前发出加密的 HTTP 数据,节省了一个消息的往返时间(这个是 RFC 文档规定的,具体原因文档没有说明,所以这点我也不太明白);
3.使用 ECDHE,在 TLS 第 2 次握手中,会出现服务器端发出的「Server Key Exchange」消息,而 RSA 握手过程没有该消息
使用了 ECDHE,在 TLS 第四次握手前,客户端就已经发送了加密的 HTTP 数据
而对于 RSA 握手过程,必须要完成 TLS 四次握手,才能传输应用数据。
ECDHE 相比 RSA 握手过程省去了一个消息往返的时间,这个有点「抢跑」的意思,它被称为是「TLS False Start」,跟「TCP Fast Open」有点像,都是在还没连接完全建立前,就发送了应用数据,这样便提高了传输的效率。
客户端向服务端发送【Client Hello】
消息里面有
TLS版本号
支持密码套件
生成的随机数(Clinet Random)
服务端向客户端发送【Server Hello】消息
消息内容有
确认TLS版本号
随机数(Server Random)
选择一个合适的密码套件
上面的操作都和RSA算法的TLS握手相同,但是选择的密码套件有点不同
不过,这次选择的密码套件就和 RSA 不一样了,我们来分析一下这次的密码套件的意思。
「TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384」
因为服务端选择了 ECDHE 密钥协商算法,所以会在发送完证书后,发送「Server Key Exchange」消息
这个过程服务器做了三件事:
此公钥以明文形式传输。这是因为椭圆曲线密码学的特性保证了即使公钥被截获,攻击者也无法从公钥反推出私钥
为了保证这个椭圆曲线的公钥不被第三方篡改
服务端会用 RSA 签名算法给服务端的椭圆曲线公钥做个签名
客户端拿到这个椭圆曲线公钥后再用RSA算法签名做运算
随后,就是「Server Hello Done」消息,服务端跟客户端表明:“这些就是我提供的信息,打招呼完毕
至此,TLS 两次握手就已经完成了,目前客户端和服务端通过明文共享了这几个信息:
Client Random、Server Random 、使用的椭圆曲线、椭圆曲线基点 G、服务端椭圆曲线的公钥,这几个信息很重要,是后续生成会话密钥的材料
在说校验数字证书是否可信的过程前,我们先来看看数字证书是什么,一个数字证书通常包含了:
那数字证书的目的是用来认证公钥持有者的身份,以防止第三方进行冒充。说简单些,证书就是用来告诉客户端,该服务端是否是合法的,因为只有证书合法才代表服务端身份是可信的。
我们用证书来认证公钥持有者的身份(服务端的身份),那证书又是怎么来的?又该怎么认证证书呢?
为了让服务端的公钥被大家信任,服务端的证书都是由 CA(Certificate Authority,证书认证机构)签名的,CA 就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名,信任的一方签发的证书,那必然证书也是被信任的。
之所以要签名,是因为签名的作用可以避免中间人在获取证书时对证书内容的篡改
如上图左边部分:
1.首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
2.然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书 做了签名;
3.最后将 Certificate Signature 添加在文件证书上,形成数字证书;
如上图右边部分:
1.首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
2.通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密证书 Certificate Signature的内容,得到一个 Hash 值 H2 ;
3.最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信
客户端会生成一个随机数作为客户端椭圆曲线的私钥,
然后再根据服务端前面给的信息,生成客户端的椭圆曲线公钥,然后用「Client Key Exchange」消息发给服务端
此公钥以明文形式传输。这是因为椭圆曲线密码学的特性保证了即使公钥被截获,攻击者也无法从公钥反推出私钥
至此,双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G
于是,双方都就计算出点 (x, y) ,其中 x 坐标值双方都是一样的
前面说 ECDHE 算法时候,说 x 是会话密钥,但实际应用中,x 还不是最终的会话密钥。
还记得 TLS 握手阶段,客户端和服务端都会生成了一个随机数传递给对方吗?
最终的会话密钥,就是用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」三个材料生成的。
之所以这么麻烦,是因为 TLS 设计者不信任客户端或服务器「伪随机」的可靠性,为了保证真正的完全随机,把三个不可靠的随机数混合起来,那么「随机」的程度就非常高了
足够让黑客计算不出最终的会话密钥,安全性更高
算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通信
接着,客户端会发「Encrypted Handshake Message」消息,对整个握手过程的完整性进行验证明
再用对称密钥加密一下数据
同时把之前发送的数据做一个摘要,然后把摘要加密发送给服务器让服务端做个验证,验证消息是否有被篡改
服务端验证消息没被篡改,然后解密我们的数据,如果解密成功就是没问题
最后,服务端也会有一个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
于是,就可以正常收发加密的 HTTP 请求和响应了
客户端:
向服务端发送【Client Hello】
消息里面有
TLS版本号
支持密码套件
生成的随机数(Clinet Random)
服务端:
向客户端发送【Server Hello】消息
消息内容有
确认TLS版本号
随机数(Server Random)
选择一个合适的密码套件
发送「Certificate」消息,会把证书也发给客户端
因为服务端选择了 ECDHE 密钥协商算法,所以会在发送完证书后,发送「Server Key Exchange」消息
选择使用的椭圆曲线,选定椭圆曲线的G点
生成随机数作为椭圆曲线的私钥,
根据G点+私钥服务端椭圆曲线的公钥
服务端会用 RSA 签名算法给服务端的椭圆曲线公钥做个签名
此公钥以明文形式传输。这是因为椭圆曲线密码学的特性保证了即使公钥被截获,攻击者也无法从公钥反推出私钥
ps:客户端拿到这个椭圆曲线公钥后再用RSA算法签名做运算(保证公钥不被篡改)
目前客户端和服务端通过明文共享了这几个信息:
Client Random、Server Random 、使用的椭圆曲线、椭圆曲线基点 G、服务端椭圆曲线的公钥,这几个信息很重要,是后续生成会话密钥的材料
客户端:
会生成一个随机数作为客户端椭圆曲线的私钥,
然后再根据服务端前面给的信息,生成客户端的椭圆曲线公钥,然后用「Client Key Exchange」消息发给服务端
此公钥以明文形式传输。这是因为椭圆曲线密码学的特性保证了即使公钥被截获,攻击者也无法从公钥反推出私钥
至此,双方都有对方的椭圆曲线公钥、自己的椭圆曲线私钥、椭圆曲线基点 G
于是,双方都就计算出点 (x, y) ,其中 x 坐标值双方都是一样的
前面说 ECDHE 算法时候,说 x 是会话密钥,但实际应用中,x 还不是最终的会话密钥
最终的会话密钥:用「客户端随机数 + 服务端随机数 + x(ECDHE 算法算出的共享密钥) 」三个材料生成的
算好会话密钥后,客户端会发一个「Change Cipher Spec」消息,告诉服务端后续改用对称算法加密通信
接着,客户端会发「Encrypted Handshake Message」消息,对整个握手过程的完整性进行验证明
再用对称密钥加密一下数据
同时把之前发送的数据做一个摘要,然后把摘要加密发送给服务器让服务端做个验证,验证消息是否有被篡改
服务端验证消息没被篡改,然后解密我们的数据,如果解密成功就是没问题
最后,服务端也会有一个同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息
如果双方都验证加密和解密没问题,那么握手正式完成
于是,就可以正常收发加密的 HTTP 请求和响应了
RSA的最终密钥:
三个随机数
Clinet Random,Server Random,Pre Master
用这三个生成最终会话密钥
ECDHE的最终密钥:
Clinet Random,Server Random,算出来的椭圆的X坐标
用这三个生成最终会话密钥