You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
6.9 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 42 | DHE/ECDHE算法的原理
你好我是Chrono。
在[第26讲](https://time.geekbang.org/column/article/110354)里我介绍了TLS 1.2的握手过程在Client Hello和Server Hello里用到了ECDHE算法做密钥交换参数完全公开但却能够防止黑客攻击算出只有通信双方才能知道的秘密Pre-Master。
这是TLS握手的关键步骤也让很多同学不太理解“为什么数据都是不保密的但中间人却无法破解呢
解答这个问题必须要涉及密码学,我原本觉得有点太深了,不想展开细讲,但后来发现大家都对这个很关心,有点“打破砂锅问到底”的精神。所以,这次我就试着从底层来解释一下。不过你要有点心理准备,这不是那么好懂的。
先从ECDHE算法的名字说起。ECDHE就是“短暂-椭圆曲线-迪菲-赫尔曼”算法ephemeral Elliptic Curve DiffieHellman里面的关键字是“短暂”“椭圆曲线”和“迪菲-赫尔曼”,我先来讲“迪菲-赫尔曼”也就是DH算法。
## 离散对数
DH算法是一种非对称加密算法只能用于密钥交换它的数学基础是“**离散对数**”Discrete logarithm
那么,什么是离散对数呢?
上中学的时候我们都学过初等代数,知道指数和对数,指数就是幂运算,对数是指数的逆运算,是已知底数和真数(幂结果),反推出指数。
例如如果以10作为底数那么指数运算是y=10^x对数运算是y=logx100的对数是210^2=100log100=22的对数是0.301log2≈0.301)。
对数运算的域是实数,取值是连续的,而“离散对数”顾名思义,取值是不连续的,数值都是整数,但运算具有与实数对数相似的性质。
离散对数里的一个核心操作是模运算也就是取余数mod在C、Java、Lua等语言里的操作符是“%”)。
假设有模数17底数5那么“5的3次方再对17取余数得6”5 ^ 3 % 17 = 6就是在离散整数域上的一次指数运算5 ^ 3 (mod 17) = 6。反过来以5为底17为模数6的离散对数就是3Ind(5, 6) = 3 ( mod 17))。
这里的175是离散对数的公共参数6是真数3是对数。知道了对数就可以用幂运算很容易地得到真数但反过来知道真数却很难推断出对数于是就形成了一个“**单向函数**”。
在这个例子里选择的模数17很小使用穷举法从1到17暴力破解也能够计算得到6的离散对数是3。
但如果我们选择的是一个非常非常大的数比如说是有1024位的超大素数那么暴力破解的成本就非常高了几乎没有什么有效的方法能够快速计算出离散对数这就是DH算法的数学基础。
## DH算法
知道了离散对数我们来看DH算法假设Alice和Bob约定使用DH算法来交换密钥。
基于离散对数Alice和Bob需要首先确定模数和底数作为算法的参数这两个参数是公开的用P和G来代称简单起见我们还是用17和5P=17G=5
然后Alice和Bob各自选择一个随机整数作为**私钥**必须在1和P-2之间严格保密。比如Alice选择a=10Bob选择b=5。
有了DH的私钥Alice和Bob再计算幂作为**公钥**也就是A = (G ^ a % P) = 9B = (G ^ b % P) = 14这里的A和B完全可以公开因为根据离散对数的原理从真数反向计算对数a和b是非常困难的。
交换DH公钥之后Alice手里有五个数P=17G=5a=10A=9B=14然后执行一个运算(B ^ a % P)= 8。
因为离散对数的幂运算有交换律B ^ a = (G ^ b ) ^ a = (G ^ a) ^ b = A ^ b所以Bob计算A ^ b % P也会得到同样的结果8这个就是Alice和Bob之间的共享秘密可以作为会话密钥使用也就是TLS里的Pre-Master。
![](https://static001.geekbang.org/resource/image/4f/ef/4fd1b613d46334827b53a1f31fa4b3ef.png)
那么黑客在这个密钥交换的通信过程中能否实现攻击呢?
整个通信过程中Alice和Bob公开了4个信息P、G、A、B其中P、G是算法的参数A和B是公钥而a、b是各自秘密保管的私钥无法获取所以黑客只能从已知的P、G、A、B下手计算9或14的离散对数。
由离散对数的性质就可以知道如果P非常大那么他很难在短时间里破解出私钥a、b所以Alice和Bob的通信是安全的但在本例中数字小计算难度很低
实验环境的URI“/42-1”演示了这个简单DH密钥交换过程可以用浏览器直接访问命令行下也可以用“resty www/lua/42-1.lua”直接运行。
## DHE算法
DH算法有两种实现形式一种是已经被废弃的DH算法也叫static DH算法另一种是现在常用的DHE算法有时候也叫EDH
static DH算法里有一方的私钥是静态的通常是服务器方固定即a不变。而另一方也就是客户端随机选择私钥即b采用随机数。
于是DH交换密钥时就只有客户端的公钥会变而服务器公钥不变在长期通信时就增加了被破解的风险使得拥有海量计算资源的攻击者获得了足够的时间最终能够暴力破解出服务器私钥然后计算得到所有的共享秘密Pre-Master不具有“前向安全”。
而DHE算法的关键在于“E”表示的临时性上ephemeral每次交换密钥时双方的私钥都是随机选择、临时生成的用完就扔掉下次通信不会再使用相当于“一次一密”。
所以,即使攻击者破解了某一次的私钥,其他通信过程的私钥仍然是安全的,不会被解密,实现了“前向安全”。
## ECDHE算法
现在如果你理解了DHE那么理解ECDHE也就不那么困难了。
ECDHE算法就是把DHE算法里整数域的离散对数替换成了椭圆曲线上的离散对数。
![](https://static001.geekbang.org/resource/image/b4/ba/b452ceb3cbfc5c644a3053f2054b1aba.jpg)
原来DHE算法里的是任意整数而ECDHE则是把连续的椭圆曲线给“离散化”成整数用椭圆曲线上的“**倍运算**”替换了DHE里的幂运算。
在ECDHE里算法的公开参数是椭圆曲线C、基点G和模数P私钥是倍数x公钥是倍点xG已知倍点xG要想计算出离散对数x是非常困难的。
在通信时Alice和Bob各自随机选择两个数字a和b作为私钥计算A=aG、B=bG作为公钥然后互相交换用与DHE相同的算法计算得到aB=abG=Ab就是共享秘密Pre-Master。
因为椭圆曲线离散对数的计算难度比普通的离散对数更大所以ECDHE的安全性比DHE还要高更能够抵御黑客的攻击。
## 思考题
最后留一个思考题吧为什么DH算法只能用于密钥交换不能用于数字签名如果你理解了DH算法的原理应该不难回答出来。
![](https://static001.geekbang.org/resource/image/07/af/0773f7b9a098a64cdbe1bf2a666f87af.png)