Diffie-Hellman密钥交换协议
这个更确切说是学习思想不是实际代码,这个代码实现起来其实很简单
算法理论
想象一下,你要和一位从未见过面的朋友共用一个密码本,但所有通信都被中间人监控。这听起来是个不可能的任务?然而,Diffie-Hellman密钥交换算法正是解决这个难题的魔法。
颜色的魔术
理解这个算法最经典的比喻是“颜色混合”:
- 首先,Alice和Bob公开约定一种起始颜色(比如黄色)
- 然后,各自秘密选择一种私人颜色(Alice选红色,Bob选蓝色)
- 他们将私人颜色与公共黄色混合,得到新颜色(Alice得到橙红,Bob得到青绿),然后公开交换混合后的颜色
- 最关键的一步:他们各自将自己的私人颜色再次混入对方发来的颜色中,奇迹发生了——双方最终得到了完全相同的颜色!
这个最终颜色就是他们的共享密钥,而窃听者虽然看到了所有公开交换的颜色,却无法推导出最终结果。
数学的魔法
现实中,我们用的不是颜色,而是数学。算法依赖“模幂运算”的单向性——正向计算容易,反向求解极其困难
具体步骤十分优雅:
- 双方公开约定两个数:一个大质数p和一个生成元g
- Alice选择一个私密数字a作为私钥,计算并发送她的公钥 A = gᵃ mod p
- Bob选择一个私密数字b作为私钥,计算并发送他的公钥 B = gᵇ mod p
- Alice用Bob的公钥计算共享密钥 s = Bᵃ mod p
- Bob用Alice的公钥计算共享密钥 s = Aᵇ mod p
这个算法的精妙在于:双方通过交换“半成品”,结合自己的秘密原料,各自独立生产出了相同的“成品”。这是一种巧妙的协作——任何一方单独都无法完成,但合作时又无需泄露核心秘密
总结
如今,Diffie-Hellman算法已成为TLS/HTTPS等安全协议的基石,守护着我们的每一次网络通信。它告诉我们:即使在最不安全的环境下,通过巧妙的数学设计,仍然能够建立可靠的信任
简略代码实现
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
// DHKey 包含 Diffie-Hellman 的密钥对
type DHKey struct {
PrivateKey *big.Int
PublicKey *big.Int
}
// GenerateDHKey 生成 Diffie-Hellman 密钥对
// p: 大质数, g: 生成元
func GenerateDHKey(p, g *big.Int) (*DHKey, error) {
// 生成私钥:一个随机的大整数,范围 [1, p-2]
// p-2 是因为私钥不能为0,且应该小于 p-1 以确保安全性
privateKey, err := rand.Int(rand.Reader, new(big.Int).Sub(p, big.NewInt(2)))
if err != nil {
return nil, err
}
// 私钥至少为1
privateKey.Add(privateKey, big.NewInt(1))
// 计算公钥:g^privateKey mod p
publicKey := new(big.Int).Exp(g, privateKey, p)
return &DHKey{
PrivateKey: privateKey,
PublicKey: publicKey,
}, nil
}
// ComputeSharedSecret 计算共享密钥
// 使用自己的私钥和对方的公钥
func ComputeSharedSecret(privateKey, otherPublicKey, p *big.Int) *big.Int {
// sharedSecret = otherPublicKey^privateKey mod p
return new(big.Int).Exp(otherPublicKey, privateKey, p)
}
func main() {
// 1. 双方约定公共参数
// 在实际应用中,这些参数通常是标准化的(如 RFC 3526 中定义)
// 这里我们使用一个相对较小的质数作为示例(实际应用要用2048位或更大的质数)
// p: 一个大质数
p := big.NewInt(23) // 示例使用小质数,实际要用非常大的质数
// g: 生成元,通常是2或者5
g := big.NewInt(5)
fmt.Printf("公共参数:\n")
fmt.Printf(" 质数 p = %s\n", p.String())
fmt.Printf(" 生成元 g = %s\n", g.String())
fmt.Println()
// 2. Alice 生成密钥对
aliceKey, err := GenerateDHKey(p, g)
if err != nil {
fmt.Printf("Alice 密钥生成失败: %v\n", err)
return
}
fmt.Printf("Alice:\n")
fmt.Printf(" 私钥 a = %s (保密)\n", aliceKey.PrivateKey.String())
fmt.Printf(" 公钥 A = g^a mod p = %s (公开)\n", aliceKey.PublicKey.String())
fmt.Println()
// 3. Bob 生成密钥对
bobKey, err := GenerateDHKey(p, g)
if err != nil {
fmt.Printf("Bob 密钥生成失败: %v\n", err)
return
}
fmt.Printf("Bob:\n")
fmt.Printf(" 私钥 b = %s (保密)\n", bobKey.PrivateKey.String())
fmt.Printf(" 公钥 B = g^b mod p = %s (公开)\n", bobKey.PublicKey.String())
fmt.Println()
// 4. 双方交换公钥后计算共享密钥
// Alice 使用自己的私钥和 Bob 的公钥计算共享密钥
aliceSharedSecret := ComputeSharedSecret(aliceKey.PrivateKey, bobKey.PublicKey, p)
fmt.Printf("Alice 计算的共享密钥:\n")
fmt.Printf(" s = B^a mod p = %s\n", aliceSharedSecret.String())
fmt.Println()
// Bob 使用自己的私钥和 Alice 的公钥计算共享密钥
bobSharedSecret := ComputeSharedSecret(bobKey.PrivateKey, aliceKey.PublicKey, p)
fmt.Printf("Bob 计算的共享密钥:\n")
fmt.Printf(" s = A^b mod p = %s\n", bobSharedSecret.String())
fmt.Println()
// 5. 验证双方计算的共享密钥是否相同
if aliceSharedSecret.Cmp(bobSharedSecret) == 0 {
fmt.Printf("✅ 成功!双方建立了相同的共享密钥: %s\n", aliceSharedSecret.String())
fmt.Printf(" 这个密钥可以用于 AES 等对称加密\n")
} else {
fmt.Printf("❌ 错误!共享密钥不匹配\n")
}
// 6. 演示窃听者看到的信息
fmt.Println("\n--- 窃听者视角 ---")
fmt.Printf("能看到的信息: p=%s, g=%s\n", p.String(), g.String())
fmt.Printf(" Alice公钥 A=%s\n", aliceKey.PublicKey.String())
fmt.Printf(" Bob公钥 B=%s\n", bobKey.PublicKey.String())
fmt.Printf("无法得知: Alice私钥(a), Bob私钥(b), 共享密钥(s)\n")
}