简介(百度百科)
Whitfield Diffie与Martin Hellman在1976年提出了一个奇妙的密钥交换协议,称为Diffie-Hellman密钥交换协议/算法(Diffie-Hellman Key Exchange/Agreement Algorithm)。这个机制的巧妙在于需要安全通信的双方可以用这个方法确定对称密钥。然后可以用这个密钥进行加密和解密。但是注意,这个密钥交换协议/算法只能用于密钥的交换,而不能进行消息的加密和解密。双方确定要用的密钥后,要使用其他对称密钥操作加密算法实现加密和解密消息。
实现
DH算法解决了密钥在双方不直接传递密钥的情况下完成密钥交换,这个神奇的交换原理完全由数学理论支持。我们来看DH算法交换密钥的步骤。假设甲乙双方需要传递密钥,他们之间可以这么做:
- 甲首选选择一个素数
p
,例如509,底数g
,任选,例如5,随机数a
,例如123,然后计算A=g^a mod p
,结果是215,然后,甲发送p=509
,g=5
,A=215
给乙; - 乙方收到后,也选择一个随机数
b
,例如,456,然后计算B=g^b mod p
,结果是181,乙再同时计算SA=A^b mod p
,结果是121; - 乙把计算的
B=181
发给甲,甲计算SB=B^a mod p
的余数,计算结果与乙算出的结果一样,都是121。
所以最终双方协商出的密钥SA=SB是121。注意到这个密钥SA或SB并没有在网络上传输。而通过网络传输的p
,g
,A
和B
是无法推算出SA、SB的,因为实际算法选择的素数是非常大的例如(7000487615661733、5925845745820835 等)。所以,更确切地说,DH算法是一个密钥协商算法,双方最终协商出一个共同的密钥,而这个密钥不会通过网络传输。
图例
设想这样一个场景,Alice(A)和Bob(B),他们想在不见面的情况下秘密约定出一种颜色,但他们互相沟通的信息都会被公开,应该怎么办呢?
Alice | Bob | ||||
---|---|---|---|---|---|
私密信息 | 公开信息 | 公开信息 | 私密信息 | ||
A和B首先约定好公开的一种颜色,比如黄色 | |||||
A,B各自挑选出一种私密的颜色,比如橙色和兰色 | |||||
A,B各自将两种颜色混合起来 | |||||
双方交换混合后的颜色 | |||||
A,B各自将自己的私密颜色再次混入得到的颜色中 | |||||
现在A,B得到了一种相同的颜色,这种颜色是由一份黄色、一份橙色、一份兰色混合而来,但外界无法得知 |
go示例
go
package game
import (
"fmt"
"math/big"
"testing"
)
// DH密钥协商算法
func TestDh(t *testing.T) {
// p为16位质数
p := big.NewInt(7000487615661733)
g := big.NewInt(5925845745820835)
// EXP(a, b, c) = (a ** b) % c
// 服务器生成A发给客户端
a := big.NewInt(123)
A := big.NewInt(0).Exp(g, a, p)
fmt.Println("A ", A)
// 客户端生成B发给服务器
b := big.NewInt(456)
B := big.NewInt(0).Exp(g, b, p)
fmt.Println("B ", B)
// 如果收到的客户端B为一个任意数,则双方协商的密钥将不一致,双方也将无法解密出正确数据
//B.SetString("123", 0)
// 服务器拿到客户端的B,生成密钥SA
SA := big.NewInt(0).Exp(B, a, p)
fmt.Println("SA", SA)
// 客户端拿到服务器的A,生成密钥SB
SB := big.NewInt(0).Exp(A, b, p)
fmt.Println("SB", SB)
if SA.String() != SB.String() {
fmt.Println("SA != SB, 密钥协商失败!")
return
}
// 最终SA=SB,完成密钥协商
key := []byte(SA.String())
// 将16位key拼接成32位key
key = append(key, key...)
// 先AES加密
encrypt,_ := AesEncrypt([]byte("123456"), key)
// 再异或运算加密
for i,item := range encrypt {
encrypt[i] = item ^ 28
}
fmt.Println("encrypt:", encrypt)
// 先异或运算解密
for i,item := range encrypt {
encrypt[i] = item ^ 28
}
// 再AES解密
decrypt,_ := AesDecrypt(encrypt, key)
fmt.Println("decrypt:", string(decrypt))
}
秘密在于,颜色混合是一种“不可逆”的操作,当双方交换颜色时,尽管我们知道他们交换的颜色都是由一份黄色和另一份其他颜色混合得到的,但我们还是无法或者很难得到他们的私密颜色。而DH秘钥交换的原理非常相似,也是利用了数学上的一个“不可逆”的运算,就是离散对数(Discrete logarithm)
首先说明:RSA和DH实际上根本不是一回事
RSA是公钥加密算法,也就是非对称密码算法,一般情况下的使用流程是这样的:
- A通过B公开的公钥加密信息,加密信息,发送加密后的信息给B,B通过自己的私钥进行解密;
- B如果想给A发送消息,就先获取A公开的密钥,加密信息,发送加密后的信息给A,A通过自己的私钥进行解密。
DH是密钥交换协议,一般情况下的使用流程是这样的:
- A和B通过DH协议获得了同一个密钥;
- A然后用这个密钥采用其他的对称密码算法如DES AES对通信进行加密解密,传递给B;
- B使用同样的密钥采用其他的对称密码算法如DES AES对通信进行加密解密,传递给A。
总结一下,区别主要是:
- RSA是用来加密解密的,DH是用来协商创造密钥的,
- RSA可以用来传递信息,DH是用来传递密钥的,想要传递信息还需要借助别的加密方式。
- 使用RSA进行信息传输是非对称密码体系,使用DH进行密钥交换的下一步使用的一般是对称的密码体系
- 使用RSA加密和解密所使用的密钥是不一样的,前者叫公钥后者叫私钥,公钥用于加密私钥用于解密,并且不可逆向,也就是不能用私钥加密公钥解密。如果A和B想进行通信的话,需要两套(4个)密钥。而DH交换得到的密钥则一般是用于对称加密的,也就是加密和加密使用的是同一个密码,进行通信只需要一个密钥即可。
然后解释一下,如何用RSA做密钥协商(密钥交换)
实际上可以模拟成下面的情况:A想和B进行密钥交换,获得一个新的密钥,于是A就通过B的公钥加密了一个密钥K(此处的密钥相当于原文),然后将生成的密文发给B。B接到了这个密文之后使用自己的私钥解密获得密钥K。于是双方就可以愉快的使用这个K来进行后面的加密了~
这就是最简单的RSA密钥交换模型了。实际上考虑到前面提到的中间人攻击的问题,因此A往往需要同时加上自己的身份认证信息。同时有些复杂点儿的情况下可能还需要B通过A的公钥发送一系列的确认信息。
因此RSA做密钥协商(密钥交换)时和DH的从原理上而言是有着非常大的差距的。