X25519密钥交换

X25519密钥交换

bg 这个密钥交换是非常的轻量简洁了,现代安全加密套件也都在使用这个(TLS1.3、ssh、Noise、WireGuard)

它的核心就是

shared_secret = X25519(private_key_A, public_key_B)

其中内部是

shared = a * B   (在 Curve25519 上)
  • a:32 字节的私钥,经过 clamp 处理
  • B:对方的 32 字节公钥(Montgomery x 坐标)
  • 运算:Montgomery ladder,保证常数时间,不被侧信道攻击

Clamp 规则(RFC 7748):

k[0] &= 248  清掉最低 3 位(让 k 可被 8 整除)
k[31] &= 127 清掉最高 1 位
k[31] |= 64  设置第二高位

目的:确保私钥落在安全子群里,避免小子群攻击

公钥生成 给定私钥 k,公钥就是:

public = X25519(k, basepoint)

basepoint 是固定的:9

Curve25519 的 Montgomery x 坐标上的生成元

双方 Alice 和 Bob:

  1. Alice:

    • 生成 32 字节随机数 → clamp → 得到私钥 a
    • pubA = X25519(a, 9)
  2. Bob:

    • 生成 32 字节随机数 → clamp → 得到私钥 b
    • pubB = X25519(b, 9)
  3. 互换公钥后:

    • Alice 计算:

    • sharedA = X25519(a, pubB)

    • Bob 计算:

    • sharedB = X25519(b, pubA)

  4. 最终:

    • sharedA == sharedB 共享密钥一致,后面开始进行通信

代码

这个代码不涉及到任何的底层,我对这个底层的数学曲线函数是完全不理解,所以只能实际写一个使用的代码不能给各位写从0开始的代码

package main

import (
	"crypto/rand"
	"crypto/ecdh"
	"fmt"
)

func main() {
	// 使用 Curve25519(X25519)
	curve := ecdh.X25519()

	// Alice
	alicePriv, _ := curve.GenerateKey(rand.Reader)
	alicePub := alicePriv.PublicKey()

	// Bob
	bobPriv, _ := curve.GenerateKey(rand.Reader)
	bobPub := bobPriv.PublicKey()

	// 密钥交换
	sharedA, _ := alicePriv.ECDH(bobPub)
	sharedB, _ := bobPriv.ECDH(alicePub)

	fmt.Printf("Alice: %x\n", sharedA)
	fmt.Printf("Bob:   %x\n", sharedB)
	fmt.Println("是否一致:", string(sharedA) == string(sharedB))
}