Go 语言标准库 —— crypto/ecdh 包(椭圆曲线 Diffie-Hellman)
🔹 概述
crypto/ecdh 包实现了椭圆曲线 Diffie-Hellman(ECDH)密钥交换协议,支持 NIST 曲线和 Curve25519。
主要功能:
- ECDH 密钥交换协议实现
- 支持 NIST P-256、P-384、P-521 曲线
- 支持 Curve25519(X25519)
- 用于安全地建立共享密钥
重要说明:
- ✅ ECDH 是现代密钥交换的标准
- 🔒 用于 TLS、SSH 等安全协议
- 🔑 允许双方在不安全的通道上建立共享密钥
- ⚠️ 需要配合认证机制防止中间人攻击
- 📦 Go 1.20+ 引入的新包(推荐使用)
支持的曲线:
- P-256 (secp256r1, prime256v1) - 常用,安全性高
- P-384 (secp384r1) - 更高安全性
- P-521 (secp521r1) - 最高安全性
- X25519 (Curve25519) - 现代推荐,性能最优
核心概念:
- 私钥(PrivateKey) - 保密的密钥
- 公钥(PublicKey) - 可以公开分享的密钥
- 密钥交换(ECDH) - 使用私钥和对方公钥计算共享密钥
- 曲线(Curve) - 椭圆曲线参数
🔹 核心类型
Curve 接口
type Curve interface {
GenerateKey(rand io.Reader) (*PrivateKey, error)
NewPrivateKey(key []byte) (*PrivateKey, error)
NewPublicKey(key []byte) (*PublicKey, error)
}
-
说明:
- 表示椭圆曲线
- 提供密钥生成和解析功能
-
方法:
GenerateKey(rand io.Reader)- 生成随机密钥对NewPrivateKey(key []byte)- 从字节创建私钥NewPublicKey(key []byte)- 从字节创建公钥
-
实现:
P256()- NIST P-256 曲线P384()- NIST P-384 曲线P521()- NIST P-521 曲线X25519()- Curve25519
PrivateKey 类型
type PrivateKey struct {
// 未导出字段
}
-
说明:
- ECDH 私钥,通常保密
- 可用于密钥交换操作
- 实现
KeyExchanger接口
-
方法:
Bytes() []byte- 返回私钥的字节编码Curve() Curve- 返回使用的曲线ECDH(remote *PublicKey) ([]byte, error)- 执行密钥交换PublicKey() *PublicKey- 返回对应的公钥Public() crypto.PublicKey- 实现标准接口Equal(x crypto.PrivateKey) bool- 比较私钥
-
注意事项:
- ⚠️ 私钥必须保密
- ✅ 可安全存储和传输(需加密)
- ✅ 可与 X.509 证书互操作
PublicKey 类型
type PublicKey struct {
// 未导出字段
}
-
说明:
- ECDH 公钥,通常通过网络传输
- 可与私钥配合进行密钥交换
-
方法:
Bytes() []byte- 返回公钥的字节编码Curve() Curve- 返回使用的曲线Equal(x crypto.PublicKey) bool- 比较公钥
-
注意事项:
- ✅ 公钥可以公开分享
- ⚠️ 需要验证公钥的真实性(防止中间人攻击)
- ✅ 可编码为 PEM 或 DER 格式
KeyExchanger 接口
type KeyExchanger interface {
PublicKey() *PublicKey
Curve() Curve
ECDH(*PublicKey) ([]byte, error)
}
- 说明:
- 用于密钥交换操作的接口
PrivateKey实现了此接口- 可用于硬件模块等不透明密钥
🔹 曲线函数
P256 曲线
ecdh.P256() Curve
-
说明:
- NIST P-256 曲线(FIPS 186-3, section D.2.3)
- 也称为 secp256r1 或 prime256v1
- 256 位安全性
- ✅ 最常用的 NIST 曲线
-
特点:
- 安全性相当于 AES-128
- 性能好,广泛支持
- 政府和企业标准
-
示例:
package main import ( "crypto/ecdh" "fmt" ) func main() { // 获取 P-256 曲线 curve := ecdh.P256() fmt.Printf("曲线:%v\n", curve) // 生成密钥对 privateKey, _ := curve.GenerateKey(rand.Reader) publicKey := privateKey.PublicKey() fmt.Printf("私钥长度:%d 字节\n", len(privateKey.Bytes())) fmt.Printf("公钥长度:%d 字节\n", len(publicKey.Bytes())) }
P384 曲线
ecdh.P384() Curve
- 说明:
- NIST P-384 曲线(FIPS 186-3, section D.2.4)
- 也称为 secp384r1
- 384 位安全性
- 特点:
- 安全性相当于 AES-192
- 比 P-256 更安全,但性能稍差
- 适用于高安全需求场景
P521 曲线
ecdh.P521() Curve
- 说明:
- NIST P-521 曲线(FIPS 186-3, section D.2.5)
- 也称为 secp521r1
- 521 位安全性
- 特点:
- 安全性相当于 AES-256
- 最高安全级别
- 性能较差,密钥较大
X25519 曲线(推荐)
ecdh.X25519() Curve
-
说明:
- Curve25519(RFC 7748, Section 5)
- ✅ 现代推荐使用的曲线
-
特点:
- 性能最优
- 设计更现代,安全性高
- 抗侧信道攻击
- WireGuard、Signal 等使用
-
示例:
package main import ( "crypto/ecdh" "fmt" ) func main() { // 获取 X25519 曲线 curve := ecdh.X25519() // 生成密钥对 privateKey, _ := curve.GenerateKey(rand.Reader) publicKey := privateKey.PublicKey() fmt.Printf("X25519 私钥长度:%d 字节\n", len(privateKey.Bytes())) fmt.Printf("X25519 公钥长度:%d 字节\n", len(publicKey.Bytes())) }
🔹 核心方法详解
GenerateKey - 生成密钥对
curve.GenerateKey(rand io.Reader) (*PrivateKey, error)
-
说明:
- 生成随机的 ECDH 密钥对
- 使用加密安全的随机数生成器
-
参数:
rand io.Reader- 随机数源(使用crypto/rand.Reader)
-
返回值:
*PrivateKey- 私钥error- 错误信息
-
示例(完整):
package main import ( "crypto/ecdh" "crypto/rand" "encoding/hex" "fmt" ) func main() { // 使用 X25519 曲线 curve := ecdh.X25519() // 生成密钥对 privateKey, err := curve.GenerateKey(rand.Reader) if err != nil { fmt.Println("错误:", err) return } // 获取公钥 publicKey := privateKey.PublicKey() // 输出密钥信息 fmt.Printf("曲线:%v\n", curve) fmt.Printf("私钥:%s\n", hex.EncodeToString(privateKey.Bytes())) fmt.Printf("公钥:%s\n", hex.EncodeToString(publicKey.Bytes())) } -
注意事项:
- ✅ 必须使用
crypto/rand.Reader - ❌ 不要使用
math/rand - ✅ 每次调用生成不同的密钥对
- ✅ 必须使用
ECDH - 密钥交换
privateKey.ECDH(remote *PublicKey) ([]byte, error)
-
说明:
- 执行 ECDH 密钥交换
- 计算共享密钥
- ⚠️ 双方必须使用相同的曲线
-
参数:
remote *PublicKey- 对方的公钥
-
返回值:
[]byte- 共享密钥(字节)error- 错误信息
-
错误情况:
- 曲线不匹配
- 公钥无效
- 计算结果为零(X25519)
-
示例(完整密钥交换):
package main import ( "crypto/ecdh" "crypto/rand" "encoding/hex" "fmt" ) func main() { // Alice 生成密钥对 aliceCurve := ecdh.X25519() alicePrivate, _ := aliceCurve.GenerateKey(rand.Reader) alicePublic := alicePrivate.PublicKey() // Bob 生成密钥对 bobCurve := ecdh.X25519() bobPrivate, _ := bobCurve.GenerateKey(rand.Reader) bobPublic := bobPrivate.PublicKey() // Alice 计算共享密钥 aliceShared, err := alicePrivate.ECDH(bobPublic) if err != nil { fmt.Println("Alice 计算失败:", err) return } // Bob 计算共享密钥 bobShared, err := bobPrivate.ECDH(alicePublic) if err != nil { fmt.Println("Bob 计算失败:", err) return } // 验证共享密钥相同 fmt.Printf("Alice 共享密钥:%s\n", hex.EncodeToString(aliceShared)) fmt.Printf("Bob 共享密钥:%s\n", hex.EncodeToString(bobShared)) fmt.Printf("密钥匹配:%v\n", string(aliceShared) == string(bobShared)) } -
注意事项:
- ⚠️ 必须验证曲线匹配
- ✅ 共享密钥需要进一步派生(如 HKDF)
- ⚠️ 需要认证机制防止中间人攻击
Bytes - 获取密钥字节
privateKey.Bytes() []byte
publicKey.Bytes() []byte
-
说明:
- 返回密钥的字节编码
- 返回副本(安全)
-
返回值:
[]byte- 密钥字节
-
示例:
package main import ( "crypto/ecdh" "crypto/rand" "encoding/hex" "fmt" ) func main() { curve := ecdh.X25519() privateKey, _ := curve.GenerateKey(rand.Reader) publicKey := privateKey.PublicKey() // 获取字节编码 privateBytes := privateKey.Bytes() publicBytes := publicKey.Bytes() fmt.Printf("私钥字节:%s\n", hex.EncodeToString(privateBytes)) fmt.Printf("公钥字节:%s\n", hex.EncodeToString(publicBytes)) // 注意:返回的是副本,修改不影响原密钥 privateBytes[0] = 0x00 fmt.Printf("修改后原私钥:%s\n", hex.EncodeToString(privateKey.Bytes())) }
Equal - 比较密钥
privateKey.Equal(x crypto.PrivateKey) bool
publicKey.Equal(x crypto.PublicKey) bool
-
说明:
- 常量时间比较密钥
- 防止时序攻击
-
返回值:
bool- 是否相等
-
示例:
package main import ( "crypto/ecdh" "crypto/rand" "fmt" ) func main() { curve := ecdh.X25519() private1, _ := curve.GenerateKey(rand.Reader) private2, _ := curve.GenerateKey(rand.Reader) // 比较私钥 fmt.Printf("私钥相同:%v\n", private1.Equal(private2)) fmt.Printf("私钥与自身相同:%v\n", private1.Equal(private1)) // 比较公钥 public1 := private1.PublicKey() public2 := private2.PublicKey() fmt.Printf("公钥相同:%v\n", public1.Equal(public2)) fmt.Printf("公钥与自身相同:%v\n", public1.Equal(public1)) }
🔹 完整示例
1. 基本密钥交换
package main
import (
"crypto/ecdh"
"crypto/rand"
"encoding/hex"
"fmt"
)
func main() {
// 选择曲线(推荐 X25519)
curve := ecdh.X25519()
// Alice 生成密钥对
alicePrivate, err := curve.GenerateKey(rand.Reader)
if err != nil {
fmt.Println("Alice 生成密钥失败:", err)
return
}
alicePublic := alicePrivate.PublicKey()
// Bob 生成密钥对
bobPrivate, err := curve.GenerateKey(rand.Reader)
if err != nil {
fmt.Println("Bob 生成密钥失败:", err)
return
}
bobPublic := bobPrivate.PublicKey()
// 交换公钥并计算共享密钥
aliceShared, err := alicePrivate.ECDH(bobPublic)
if err != nil {
fmt.Println("Alice 计算共享密钥失败:", err)
return
}
bobShared, err := bobPrivate.ECDH(alicePublic)
if err != nil {
fmt.Println("Bob 计算共享密钥失败:", err)
return
}
// 验证共享密钥
fmt.Printf("Alice 共享密钥:%s\n", hex.EncodeToString(aliceShared))
fmt.Printf("Bob 共享密钥:%s\n", hex.EncodeToString(bobShared))
fmt.Printf("密钥匹配:%v\n", string(aliceShared) == string(bobShared))
}
2. 使用不同曲线
package main
import (
"crypto/ecdh"
"crypto/rand"
"fmt"
)
func demonstrateCurve(curve ecdh.Curve, name string) {
fmt.Printf("\n=== %s ===\n", name)
// 生成密钥对
privateKey, err := curve.GenerateKey(rand.Reader)
if err != nil {
fmt.Println("错误:", err)
return
}
publicKey := privateKey.PublicKey()
fmt.Printf("私钥长度:%d 字节\n", len(privateKey.Bytes()))
fmt.Printf("公钥长度:%d 字节\n", len(publicKey.Bytes()))
// 密钥交换测试
privateKey2, _ := curve.GenerateKey(rand.Reader)
publicKey2 := privateKey2.PublicKey()
shared, err := privateKey.ECDH(publicKey2)
if err != nil {
fmt.Println("密钥交换失败:", err)
return
}
fmt.Printf("共享密钥长度:%d 字节\n", len(shared))
}
func main() {
// 演示所有支持的曲线
demonstrateCurve(ecdh.P256(), "NIST P-256")
demonstrateCurve(ecdh.P384(), "NIST P-384")
demonstrateCurve(ecdh.P521(), "NIST P-521")
demonstrateCurve(ecdh.X25519(), "Curve25519")
fmt.Println("\n推荐:使用 Curve25519(X25519)")
}
3. 密钥序列化与反序列化
package main
import (
"crypto/ecdh"
"crypto/rand"
"encoding/hex"
"fmt"
)
// 保存私钥
func savePrivateKey(privateKey *ecdh.PrivateKey) []byte {
return privateKey.Bytes()
}
// 加载私钥
func loadPrivateKey(curve ecdh.Curve, keyBytes []byte) (*ecdh.PrivateKey, error) {
return curve.NewPrivateKey(keyBytes)
}
// 保存公钥
func savePublicKey(publicKey *ecdh.PublicKey) []byte {
return publicKey.Bytes()
}
// 加载公钥
func loadPublicKey(curve ecdh.Curve, keyBytes []byte) (*ecdh.PublicKey, error) {
return curve.NewPublicKey(keyBytes)
}
func main() {
curve := ecdh.X25519()
// 生成密钥对
privateKey, _ := curve.GenerateKey(rand.Reader)
publicKey := privateKey.PublicKey()
// 序列化
privateBytes := savePrivateKey(privateKey)
publicBytes := savePublicKey(publicKey)
fmt.Printf("序列化私钥:%s\n", hex.EncodeToString(privateBytes))
fmt.Printf("序列化公钥:%s\n", hex.EncodeToString(publicBytes))
// 反序列化
loadedPrivate, err := loadPrivateKey(curve, privateBytes)
if err != nil {
fmt.Println("加载私钥失败:", err)
return
}
loadedPublic, err := loadPublicKey(curve, publicBytes)
if err != nil {
fmt.Println("加载公钥失败:", err)
return
}
// 验证
fmt.Printf("私钥匹配:%v\n", privateKey.Equal(loadedPrivate))
fmt.Printf("公钥匹配:%v\n", publicKey.Equal(loadedPublic))
// 测试密钥交换
shared1, _ := privateKey.ECDH(loadedPublic)
shared2, _ := loadedPrivate.ECDH(publicKey)
fmt.Printf("密钥交换成功:%v\n", string(shared1) == string(shared2))
}
4. 安全的密钥派生(配合 HKDF)
package main
import (
"crypto/ecdh"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"golang.org/x/crypto/hkdf"
)
// 从共享密钥派生多个密钥
func deriveKeys(sharedSecret []byte, info []byte, lengths ...int) ([][]byte, error) {
// 使用 HKDF 派生密钥
hkdf := hkdf.New(sha256.New, sharedSecret, nil, info)
keys := make([][]byte, len(lengths))
for i, length := range lengths {
keys[i] = make([]byte, length)
if _, err := io.ReadFull(hkdf, keys[i]); err != nil {
return nil, err
}
}
return keys, nil
}
func main() {
// ECDH 密钥交换
curve := ecdh.X25519()
alicePrivate, _ := curve.GenerateKey(rand.Reader)
bobPrivate, _ := curve.GenerateKey(rand.Reader)
aliceShared, _ := alicePrivate.ECDH(bobPrivate.PublicKey())
bobShared, _ := bobPrivate.ECDH(alicePrivate.PublicKey())
// 从共享密钥派生多个密钥
// 例如:加密密钥 32 字节 + MAC 密钥 32 字节 + IV 16 字节
keys, err := deriveKeys(aliceShared, []byte("ECDH key derivation"), 32, 32, 16)
if err != nil {
fmt.Println("密钥派生失败:", err)
return
}
fmt.Printf("加密密钥:%s\n", hex.EncodeToString(keys[0]))
fmt.Printf("MAC 密钥:%s\n", hex.EncodeToString(keys[1]))
fmt.Printf("IV: %s\n", hex.EncodeToString(keys[2]))
// Bob 派生相同的密钥
bobKeys, _ := deriveKeys(bobShared, []byte("ECDH key derivation"), 32, 32, 16)
fmt.Printf("\nBob 的加密密钥:%s\n", hex.EncodeToString(bobKeys[0]))
fmt.Printf("密钥匹配:%v\n", string(keys[0]) == string(bobKeys[0]))
}
5. 实际应用场景 - 安全通信建立
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/ecdh"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"golang.org/x/crypto/hkdf"
)
type SecureChannel struct {
encryptKey []byte
decryptKey []byte
}
// 创建安全通道
func NewSecureChannel(localPrivate *ecdh.PrivateKey, remotePublic *ecdh.PublicKey) (*SecureChannel, error) {
// ECDH 密钥交换
sharedSecret, err := localPrivate.ECDH(remotePublic)
if err != nil {
return nil, err
}
// 派生密钥
hkdf := hkdf.New(sha256.New, sharedSecret, nil, []byte("secure channel"))
encryptKey := make([]byte, 32) // AES-256
decryptKey := make([]byte, 32)
io.ReadFull(hkdf, encryptKey)
io.ReadFull(hkdf, decryptKey)
return &SecureChannel{
encryptKey: encryptKey,
decryptKey: decryptKey,
}, nil
}
// 加密消息
func (sc *SecureChannel) Encrypt(plaintext []byte) (string, error) {
block, err := aes.NewCipher(sc.encryptKey)
if err != nil {
return "", err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonce := make([]byte, gcm.NonceSize())
io.ReadFull(rand.Reader, nonce)
ciphertext := gcm.Seal(nonce, nonce, plaintext, nil)
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
// 解密消息
func (sc *SecureChannel) Decrypt(encoded string) ([]byte, error) {
ciphertext, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, err
}
block, err := aes.NewCipher(sc.decryptKey)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
return gcm.Open(nil, nonce, ciphertext, nil)
}
func main() {
// Alice 和 Bob 建立安全通道
curve := ecdh.X25519()
alicePrivate, _ := curve.GenerateKey(rand.Reader)
bobPrivate, _ := curve.GenerateKey(rand.Reader)
// Alice 创建通道(使用 Bob 的公钥加密,自己的私钥解密)
aliceChannel, _ := NewSecureChannel(alicePrivate, bobPrivate.PublicKey())
// Bob 创建通道(使用 Alice 的公钥加密,自己的私钥解密)
bobChannel, _ := NewSecureChannel(bobPrivate, alicePrivate.PublicKey())
// Alice 发送加密消息给 Bob
message := []byte("Hello, Bob!")
encrypted, _ := aliceChannel.Encrypt(message)
fmt.Printf("加密消息:%s\n", encrypted)
// Bob 解密消息
decrypted, _ := bobChannel.Decrypt(encrypted)
fmt.Printf("解密消息:%s\n", string(decrypted))
}
🔹 注意事项和最佳实践
1. 曲线选择
-
✅ 推荐使用 X25519(Curve25519)
- 性能最优
- 现代设计
- 抗侧信道攻击
-
⚠️ NIST 曲线(P-256、P-384、P-521)
- 广泛支持
- 符合标准
- 性能稍差
// 推荐
curve := ecdh.X25519()
// 也可用(兼容性好)
curve := ecdh.P256()
// 高安全需求
curve := ecdh.P384()
2. 随机数生成
- ✅ 必须使用
crypto/rand.Reader - ❌ 不要使用
math/rand - ⚠️ 确保系统熵源充足
// 正确
privateKey, _ := curve.GenerateKey(crypto/rand.Reader)
// 错误 - 不安全
privateKey, _ := curve.GenerateKey(mathRand.New(mathRand.NewSource(1)))
3. 密钥派生
- ✅ 使用 HKDF 从共享密钥派生
- ✅ 添加上下文信息(info)
- ✅ 派生足够长度的密钥
// 正确 - 使用 HKDF
hkdf := hkdf.New(sha256.New, sharedSecret, salt, info)
key := make([]byte, 32)
io.ReadFull(hkdf, key)
// 错误 - 直接使用共享密钥
key := sharedSecret // 不安全
4. 公钥验证
- ⚠️ 验证公钥的真实性
- ✅ 使用证书或指纹验证
- ❌ 防止中间人攻击
// 验证公钥指纹
expectedFingerprint := "..."
actualFingerprint := sha256.Sum256(publicKey.Bytes())
if expectedFingerprint != hex.EncodeToString(actualFingerprint[:]) {
return fmt.Errorf("公钥指纹不匹配")
}
5. 错误处理
- ✅ 检查所有错误
- ✅ 曲线必须匹配
- ✅ 处理无效公钥
shared, err := privateKey.ECDH(remotePublicKey)
if err != nil {
// 可能是曲线不匹配或公钥无效
return nil, err
}
// 检查共享密钥(X25519 可能返回全零)
if len(shared) == 0 {
return nil, fmt.Errorf("无效的共享密钥")
}
6. 密钥存储
- ✅ 私钥必须加密存储
- ✅ 使用安全的密钥管理服务
- ❌ 不要硬编码私钥
// 错误 - 硬编码私钥
privateKeyBytes, _ := hex.DecodeString("deadbeef...")
// 正确 - 从安全存储加载
privateKeyBytes := loadFromSecureStorage()
privateKey, _ := curve.NewPrivateKey(privateKeyBytes)
🔥 总结
核心类型
| 类型 | 说明 | 用途 |
|---|---|---|
| Curve | 椭圆曲线接口 | 生成和管理密钥 |
| PrivateKey | 私钥类型 | 保密,用于密钥交换 |
| PublicKey | 公钥类型 | 公开分享 |
| KeyExchanger | 密钥交换接口 | 抽象密钥交换操作 |
支持的曲线
| 曲线 | 安全性 | 性能 | 推荐度 | 使用场景 |
|---|---|---|---|---|
| X25519 | 高 | 最优 | ✅ 强烈推荐 | 现代应用、高性能 |
| P-256 | 高 | 好 | ✅ 推荐 | 通用、标准兼容 |
| P-384 | 很高 | 中 | ⚠️ 高安全需求 | 政府、金融 |
| P-521 | 极高 | 差 | ⚠️ 特殊需求 | 最高安全要求 |
主要方法
| 方法 | 说明 | 返回值 |
|---|---|---|
| GenerateKey() | 生成密钥对 | (*PrivateKey, error) |
| ECDH(remote) | 密钥交换 | ([]byte, error) |
| Bytes() | 获取字节编码 | []byte |
| PublicKey() | 获取公钥 | *PublicKey |
| Equal() | 比较密钥 | bool |
主要特点
- 密钥交换 👉 安全地建立共享密钥
- 多种曲线 👉 X25519、P-256、P-384、P-521
- 现代设计 👉 Go 1.20+ 推荐使用
- 常量时间 👉 抗时序攻击
- 标准兼容 👉 符合 FIPS、RFC 标准
使用场景
- TLS/SSL 👉 握手阶段的密钥交换
- SSH 👉 安全 shell 连接
- 即时通讯 👉 Signal、WhatsApp 等
- VPN 👉 WireGuard 使用 X25519
- 区块链 👉 加密货币密钥派生
最佳实践
- ✅ 优先使用 X25519 曲线
- ✅ 使用
crypto/rand.Reader生成密钥 - ✅ 使用 HKDF 派生密钥
- ✅ 验证公钥真实性
- ✅ 检查所有错误
- ✅ 加密存储私钥
- ⚠️ 防止中间人攻击
- ⚠️ 定期轮换密钥
安全建议
- 🔒 使用认证机制(证书、指纹)
- 🔒 实施密钥轮换策略
- 🔒 记录密钥交换日志
- 🔒 进行安全审计
- 🔒 使用硬件安全模块(HSM)
🔹 与 crypto/ecdsa 的区别
| 特性 | ECDH | ECDSA |
|---|---|---|
| 用途 | 密钥交换 | 数字签名 |
| 操作 | 计算共享密钥 | 签名和验证 |
| 可逆性 | 不可逆 | 不可逆 |
| 典型应用 | TLS 握手 | 证书签名 |
crypto/ecdh 包提供了现代、安全的 ECDH 密钥交换实现,推荐使用 X25519 曲线!