Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 的区别

特性ECDHECDSA
用途密钥交换数字签名
操作计算共享密钥签名和验证
可逆性不可逆不可逆
典型应用TLS 握手证书签名

crypto/ecdh 包提供了现代、安全的 ECDH 密钥交换实现,推荐使用 X25519 曲线!