DH 算法是非对称加密算法, 因此它可以用于密钥交换,该算法的核心数学思想是离散对数。
对数运算: i = l o g a b i = log_{a}b i=logab
离散对数是在对数运算的基础上加了「模运算」,也就说取余数,对应编程语言的操作符是「%」,也可以用 mod 表示。离散对数的概念如下图:
上图的,底数 a 和模数 p 是离散对数的公共参数,也就说是公开的,b 是真数,i 是对数。知道了对数,就可以用上面的公式计算出真数。但反过来,知道真数却很难推算出对数。
特别是当模数 p 是一个很大的质数,即使知道底数 a 和真数 b ,在现有的计算机的计算水平是几乎无法算出离散对数的,这就是 DH 算法的数学基础。
现假设小红和小明约定使用 DH 算法来交换密钥,那么基于离散对数,小红和小明需要先确定模数和底数作为算法的参数,这两个参数是公开的,用 P 和 G 来代称。
然后小红和小明各自生成一个随机整数作为私钥,双方的私钥要各自严格保管,不能泄漏,小红的私钥用 a 代称,小明的私钥用 b 代称。
现在小红和小明双方都有了 P 和 G 以及各自的私钥,于是就可以计算出公钥:
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 ( m o d P ) A ^ b ( mod P ) Ab(modP),得到的结果也是 K。
这个 K 就是小红和小明之间用的对称加密密钥,可以作为会话密钥使用。
可以看到,整个密钥协商过程中,小红和小明公开了 4 个信息:P、G、A、B,其中 P、G 是算法的参数,A 和 B 是公钥,而 a、b 是双方各自保管的私钥,黑客无法获取这 2 个私钥,因此黑客只能从公开的 P、G、A、B 入手,计算出离散对数(私钥)。
前面也多次强调, 根据离散对数的原理,如果 P 是一个大数,在现有的计算机的计算能力是很难破解出 私钥 a、b 的,破解不出私钥,也就无法计算出会话密钥,因此 DH 密钥交换是安全的。
根据私钥生成的方式,DH 算法分为两种实现:
static DH 算法里有一方的私钥是静态的,也就说每次密钥协商的时候有一方的私钥都是一样的,一般是服务器方固定,即 a 不变,客户端的私钥则是随机生成的。
于是,DH 交换密钥时就只有客户端的公钥是变化,而服务端公钥是不变的,那么随着时间延长,黑客就会截获海量的密钥协商过程的数据,因为密钥协商的过程有些数据是公开的,黑客就可以依据这些数据暴力破解出服务器的私钥,然后就可以计算出会话密钥了,于是之前截获的加密数据会被破解,所以 static DH 算法不具备前向安全性。
既然固定一方的私钥有被破解的风险,那么干脆就让双方的私钥在每次密钥交换通信时,都是随机生成的、临时的,这个方式也就是 DHE 算法,E 全称是 ephemeral(临时性的)。
所以,即使有个牛逼的黑客破解了某一次通信过程的私钥,其他通信过程的私钥仍然是安全的,因为每个通信过程的私钥都是没有任何关系的,都是独立的,这样就保证了「前向安全」。
DHE 算法由于计算性能不佳,因为需要做大量的乘法,为了提升 DHE 算法的性能,所以就出现了现在广泛用于密钥交换算法 —— ECDHE 算法。
ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量计算出公钥,以及最终的会话密钥。
小红和小明使用 ECDHE 密钥交换算法的过程:
这个过程中,双方的私钥都是随机、临时生成的,都是不公开的,即使根据公开的信息(椭圆曲线、公钥、基点 G)也是很难计算出椭圆曲线上的离散对数(私钥)。