matthiaskonrath/PQC-WireGuard
GitHub: matthiaskonrath/PQC-WireGuard
基于 Go 的后量子增强型 WireGuard 实现,采用 NIST 标准化的 ML-KEM-768 混合密钥交换和 ML-DSA-65 身份认证,为 VPN 隧道提供抵御量子计算威胁的加密通信能力。
Stars: 0 | Forks: 0
# PQC-WireGuard
基于 Go 语言实现的后量子增强型 WireGuard。
PQC-WireGuard 使用混合后量子密钥交换 (ML-KEM-768) 和可选的后量子身份验证 (ML-DSA-65) 扩展了 WireGuard 协议,同时保持与标准 WireGuard 的完全向后兼容性。
## 工作原理
### 架构
PQC-WireGuard 将 [wireguard-go](https://git.zx2c4.com/wireguard-go) 作为库嵌入,并在单个进程中与其一起运行 PQC sidecar。该 sidecar 执行后量子密钥交换,并将生成的秘密注入到 WireGuard 的预共享密钥字段中。
```
┌─────────────────────────────────────────────────────────┐
│ pqc-wg (single binary) │
│ │
│ ┌───────────────────┐ ┌───────────────────────┐ │
│ │ wireguard-go │ │ PQC Sidecar │ │
│ │ (embedded) │ UAPI │ │ │
│ │ │◄──────┤ ML-KEM-768 exchange │ │
│ │ TUN device │ PSK │ ML-DSA-65 auth │ │
│ │ UDP transport │ set │ 120s rekey cycle │ │
│ │ Noise handshake │ │ │ │
│ │ Packet routing │ │ UDP :ListenPort+1 │ │
│ └─────────┬─────────┘ └───────────┬───────────┘ │
│ │ │ │
└────────────┼─────────────────────────────┼──────────────┘
│ │
┌───────▼───────┐ ┌────────▼────────┐
│ UDP :51820 │ │ UDP :51821 │
│ WireGuard │ │ PQC handshake │
│ tunnel data │ │ key exchange │
└───────────────┘ └─────────────────┘
```
### 握手模式
| 模式 | 配置 | 类型 | 算法 | 兼容性 |
|------|--------|-------|------------|---------------|
| Legacy | `pqc=off` | 1/2 | X25519 | 标准 WireGuard |
| Hybrid KEM | `pqc=required` | 5/6 | X25519 + ML-KEM-768 | 仅限 PQC-WireGuard 对等点 |
| Full PQC | `pqc_auth=required` | 7/8 | X25519 + ML-KEM-768 + ML-DSA-65 | 仅限 PQC-WireGuard 对等点 |
### PQC 密钥交换流程 (Hybrid KEM)
```
Initiator (Client) Responder (Server)
────────────────── ──────────────────
1. Generate ephemeral X25519 keypair
Generate ephemeral ML-KEM-768 keypair
── Type 5: Initiation ──────────────►
│ X25519 ephemeral public key
│ ML-KEM-768 ephemeral public key
│ Encrypted static key
│ Encrypted timestamp
2. Verify initiation
DH(static, ephemeral)
KEM encapsulate against
initiator's ML-KEM PK
◄── Type 6: Response ───────────────
│ X25519 ephemeral public key
│ ML-KEM-768 ciphertext
│ Encrypted empty payload
3. DH(ephemeral, ephemeral)
KEM decapsulate using
ephemeral ML-KEM SK 4. DH(ephemeral, ephemeral)
┌────────── Both sides derive: ───────────────┐
│ │
│ chainKey = KDF(chainKey, DH_ee) │
│ chainKey = KDF(chainKey, KEM_shared_secret)│
│ chainKey = KDF(chainKey, DH_se) │
│ chainKey = KDF(chainKey, PSK) │
│ │
│ sessionKey = KDF(chainKey) │
│ │
└──── Inject as WireGuard PSK via UAPI ───────┘
│
▼
WireGuard handshake completes
using the PQC-derived PSK
│
▼
Encrypted tunnel traffic
(ChaCha20-Poly1305, unchanged)
```
### 混合密钥推导
混合方法确保仅破解经典或后量子密码术不会危及会话安全:
```
X25519 DH(ephemeral, ephemeral) ML-KEM-768 Encapsulate
│ │
▼ ▼
DH shared secret KEM shared secret
(32 bytes) (32 bytes)
│ │
└──────────┐ ┌────────────────────┘
▼ ▼
┌─────────────┐
│ HKDF-BLAKE2s│
│ (KDF chain) │
└──────┬──────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
DH(static, PSK mixing Session key
ephemeral) derivation
│ │ │
└────────────┴────────────┘
│
Combined session
keys (send/recv)
Security guarantee:
┌─────────────────────────────────────────────┐
│ If X25519 broken → ML-KEM still protects │
│ If ML-KEM broken → X25519 still protects │
│ Both must be broken to compromise session │
└─────────────────────────────────────────────┘
```
### 策略决策树
```
Peer config
│
├── pqc = off, pqc_auth = off
│ └── Standard WireGuard (types 1/2)
│ Full legacy compatibility
│
├── pqc = opportunistic, pqc_auth = off
│ └── Try PQC (type 5), fall back to
│ classical (type 1) if peer rejects
│
├── pqc = required, pqc_auth = off
│ └── Hybrid KEM required (types 5/6)
│ Quantum-safe confidentiality
│ Classical authentication
│
├── pqc = required, pqc_auth = required
│ └── Full PQC (types 7/8)
│ Quantum-safe confidentiality
│ Quantum-safe authentication
│ Requires ML-DSA-65 keys
│
└── pqc = off, pqc_auth = required
└── INVALID — rejected at startup
```
## 构建
### 要求
- Go 1.21 或更高版本
### 编译
```
# 为当前平台构建
go build -o pqc-wg .
# 交叉编译
GOOS=linux GOARCH=amd64 go build -o pqc-wg-linux-amd64 .
GOOS=linux GOARCH=arm64 go build -o pqc-wg-linux-arm64 .
GOOS=darwin GOARCH=arm64 go build -o pqc-wg-darwin-arm64 .
GOOS=darwin GOARCH=amd64 go build -o pqc-wg-darwin-amd64 .
GOOS=windows GOARCH=amd64 go build -o pqc-wg-windows-amd64.exe .
```
单个静态二进制文件,无外部依赖。所有密码学均为通过 [Cloudflare CIRCL](https://github.com/cloudflare/circl) 实现的纯 Go 语言——无需 CGo、liboqs 或系统库。
### 运行测试
```
go test ./... -v
```
### 运行基准测试
```
go test ./... -bench=.
```
## 平台支持
| 平台 | 架构 | 状态 |
|----------|-------------|--------|
| macOS | arm64 (Apple Silicon) | 支持 |
| macOS | amd64 (Intel) | 支持 |
| Linux | amd64 | 支持 |
| Linux | arm64 | 支持 |
| Windows | amd64 | 支持 |
## 使用方法
### 启动隧道
```
# 在前台启动(Ctrl-C 停止)
sudo pqc-wg up wg0 --config /path/to/config.conf
# 作为 daemon 启动(后台)
sudo pqc-wg up wg0 --config /path/to/config.conf --daemon
# 附带详细日志
sudo LOG_LEVEL=verbose pqc-wg up wg0 --config /path/to/config.conf
# 停止运行中的 tunnel
sudo pqc-wg down wg0
# 显示 tunnel 状态
sudo pqc-wg show wg0
```
### Systemd (Linux)
```
# 安装
sudo cp pqc-wg /usr/local/bin/
sudo cp dist/pqc-wg@.service /etc/systemd/system/
sudo mkdir -p /etc/pqc-wg
sudo cp wg0.conf /etc/pqc-wg/wg0.conf
# 启用并启动
sudo systemctl enable --now pqc-wg@wg0
```
### 生成密钥
```
# 生成 X25519 keypair(以 config 格式输出 PrivateKey 和 PublicKey)
pqc-wg genkey
# 从 private key 推导 public key(自动检测 X25519 或 ML-DSA-65)
echo "" | pqc-wg pubkey
# 生成 ML-DSA-65 认证 keypair(用于 pqc_auth=required 模式)
pqc-wg genkey --pqc-auth
```
### 其他命令
```
pqc-wg validate myconfig.conf # Validate a configuration file
pqc-wg show-config myconfig.conf # Show parsed config (secrets redacted)
pqc-wg info # Show PQC algorithm information
```
## 配置
PQC-WireGuard 使用带有 PQC 扩展的标准 WireGuard INI 配置格式。
### Hybrid KEM(推荐起点)
```
[Interface]
PrivateKey =
Address = 10.0.0.1/24
ListenPort = 51820
PQCDefaultPolicy = required
[Peer]
PublicKey =
AllowedIPs = 10.0.0.2/32
Endpoint = 203.0.113.2:51820
```
### Full PQC(最大抗量子性)
```
[Interface]
PrivateKey =
Address = 10.0.0.1/24
ListenPort = 51820
PQCDefaultPolicy = required
PQCAuthDefaultPolicy = required
PQCAuthPrivateKey =
[Peer]
PublicKey =
AllowedIPs = 10.0.0.2/32
Endpoint = 203.0.113.2:51820
PQCAuth = required
PQCAuthPublicKey =
```
### Legacy 模式(标准 WireGuard 兼容性)
```
[Interface]
PrivateKey =
ListenPort = 51820
PQCDefaultPolicy = off
[Peer]
PublicKey =
AllowedIPs = 10.0.0.2/32
Endpoint = 203.0.113.2:51820
```
### 配置参考
#### 接口 (Interface) 部分
| 键 | 值 | 默认值 | 描述 |
|-----|--------|---------|-------------|
| `PrivateKey` | base64 | (必需) | X25519 私钥 |
| `Address` | CIDR | | 隧道地址 |
| `ListenPort` | 0-65535 | | UDP 监听端口 |
| `DNS` | IP 列表 | | DNS 服务器(逗号分隔) |
| `MTU` | 576-65535 | 1420 | 隧道 MTU |
| `PostUp` | 命令 | | 接口启动后运行的 Shell 命令(`%i` = 接口) |
| `PostDown` | 命令 | | 接口关闭后运行的 Shell 命令(`%i` = 接口) |
| `PQCDefaultPolicy` | `off`、`opportunistic`、`required` | `required` | 对等点的默认 PQC KEM 策略 |
| `PQCAuthDefaultPolicy` | `off`、`required` | `off` | 对等点的默认 PQC 身份验证策略 |
| `PQCSidecarPort` | 0-65535 | ListenPort+1 | 用于 PQC 密钥交换的 UDP 端口 |
| `PQCAuthPrivateKey` | base64 | | ML-DSA-65 私钥(用于 pqc_auth) |
| `PQCAuthPublicKey` | base64 | (自动派生) | ML-DSA-65 公钥 —— 如省略则从私钥自动派生 |
#### 对等点 (Peer) 部分
| 键 | 值 | 默认值 | 描述 |
|-----|--------|---------|-------------|
| `PublicKey` | base64 | (必需) | 对等点的 X25519 公钥 |
| `PresharedKey` | base64 | | 可选预共享密钥(附加熵) |
| `Endpoint` | host:port | | 对等点的端点 |
| `AllowedIPs` | CIDR 列表 | | 允许的 IP 范围 |
| `PQCPolicy` | `off`、`opportunistic`、`required` | (来自默认值) | 此对等点的 PQC KEM 策略 |
| `PQCAuth` | `off`、`required` | (来自默认值) | 此对等点的 PQC 身份验证 |
| `PQCAuthPublicKey` | base64 | | 对等点的 ML-DSA-65 公钥 |
| `PersistentKeepalive` | 秒 | | Keepalive 间隔 |
## 密码算法
### 经典(与 WireGuard 保持不变)
- **密钥交换**: X25519 (Curve25519)
- **AEAD**: ChaCha20-Poly1305
- **哈希**: BLAKE2s
### 后量子 KEM (FIPS 203)
- **算法**: ML-KEM-768(原 Kyber-768)
- **安全级别**: NIST Level 3(约等于 192 位经典安全性)
- **公钥**: 1184 字节
- **密文**: 1088 字节
- **共享密钥**: 32 字节
- **密钥生命周期**: 临时(每次握手重新生成)
### 后量子身份验证 (FIPS 204)
- **算法**: ML-DSA-65(原 Dilithium-3)
- **安全级别**: NIST Level 3(约等于 192 位经典安全性)
- **公钥**: 1952 字节
- **签名**: 3309 字节
- **密钥生命周期**: 长期身份(通过带外交换)
## 项目结构
```
pqc-wg/
├── main.go # CLI entrypoint (up, down, genkey, validate, info)
├── pqc/ # Post-quantum cryptographic primitives
│ ├── kem.go # ML-KEM-768 (FIPS 203) via CIRCL
│ ├── sig.go # ML-DSA-65 (FIPS 204) via CIRCL
│ └── hybrid.go # Hybrid secret combiner (HMAC-BLAKE2s)
├── device/ # WireGuard device and Noise protocol
│ ├── noise-protocol.go # Handshake: standard, hybrid KEM, full PQC auth
│ ├── noise-types.go # Key types, policy enums, message constants
│ ├── noise-helpers.go # KDF, HMAC-BLAKE2s, Curve25519 helpers
│ ├── device.go # Device struct and peer management
│ ├── peer.go # Peer struct with PQC state
│ └── receive.go # Message type dispatch and policy checks
├── config/ # Configuration parser
│ └── config.go # WireGuard INI format with PQC extensions
├── tunnel/ # Tunnel runtime (embedded wireguard-go)
│ ├── orchestrator.go # TUN creation, wireguard-go Device, OS interface config
│ ├── sidecar.go # PQC key exchange over UDP, PSK injection
│ └── uapi.go # In-process UAPI client for wireguard-go Device
├── dist/
│ └── pqc-wg@.service # Systemd unit file for Linux
└── docs/
├── PROTOCOL.md # Wire format specification
├── THREAT-MODEL.md # Security analysis
└── MIGRATION.md # Migration guide from standard WireGuard
```
## 与其他 PQC WireGuard 实现的比较
```
PQC-WireGuard Rosenpass PQ-WireGuard OQS-WireGuard
────── ───────── ──────────── ─────────────
Language Go Rust Go C (kernel)
Architecture Single binary Separate daemon Forked protocol Kernel patch
WireGuard mod None (embedded) None (sidecar) Forked Patched
PQC KEM ML-KEM-768 Kyber-512 + Kyber-768 Various (liboqs)
(FIPS 203) Classic McEliece (pre-FIPS) (pre-FIPS)
PQC Auth ML-DSA-65 None Research None
(FIPS 204)
Standards NIST FIPS Pre-standard Pre-standard Pre-standard
finalized algorithms algorithms algorithms
Legacy compat Yes (pqc=off) Yes (alongside) No No
Cross-platform Linux/macOS/ Linux/macOS Linux Linux only
Windows
Formal verify No ProVerif No No
(peer-reviewed)
Production ready No (experimental) Yes No (research) No (research)
```
**PQC-WireGuard 的独特之处:**
- **FIPS 标准化算法** —— 使用最终的 NIST 标准 (ML-KEM-768 FIPS 203、ML-DSA-65 FIPS 204),而不是与最终规范不同的标准化前草案
- **可选的 PQC 身份验证** —— 唯一提供基于 ML-DSA-65 签名的身份验证(类型 7/8)的实现。其他实现仅保护机密性 —— 恢复了 X25519 密钥的量子攻击者仍然可以冒充对等点
- **单一二进制文件** —— 将 wireguard-go 作为库嵌入。无需安装或协调外部依赖
- **三层策略模型** —— 每个对等点支持 `pqc=off` / `pqc=required` / `pqc_auth=required`,允许在迁移期间进行混合部署
- **纯 Go,无 CGo** —— 使用 Cloudflare CIRCL(生产级,用于 Cloudflare 的 TLS 栈中)。不依赖 liboqs(仅标记为研究用途)
**Rosenpass 的优势:**
- 使用 ProVerif 进行了经过同行评审的形式化验证
- 拥有生产环境部署经验
- 在 Kyber 之外使用 Classic McEliece(基于编码的,非常保守)进行身份验证
- 较低的 ProVerif 验证成本(没有 DH 方程 —— 而是使用两个 KEM)
## 安全性
有关完整的安全分析,请参阅 [docs/THREAT-MODEL.md](docs/THREAT-MODEL.md)。
**关键属性**:
- **混合保证**:仅攻破 X25519 或 ML-KEM 之一不会破坏会话机密性
- **前向保密**:所有 ML-KEM 密钥对都是临时的;泄露长期密钥不会暴露过去的会话
- **协议隔离**:每种握手模式使用不同的 Noise 协议标识符,防止跨协议攻击
- **转录绑定**:KEM 密文和 ML-DSA 签名被混合到握手转录哈希中
- **防 TOFU**:PQC 身份验证需要预先配置的对等点公钥;未知密钥将被拒绝
## 迁移
有关从标准 WireGuard 迁移的分步指南,请参阅 [docs/MIGRATION.md](docs/MIGRATION.md)。
## 许可证
[MIT](LICENSE) —— 有关第三方声明,请参阅 LICENSE 文件(wireguard-go MIT,CIRCL BSD-3-Clause,Go stdlib BSD-3-Clause)。
标签:EVTX分析, Go语言, ML-DSA-65, ML-KEM-768, VPN, WireGuard, X25519, 加密通信, 单文件部署, 后量子密码学, 安全协议, 抗量子计算, 数据传输安全, 日志审计, 本体建模, 混合密钥交换, 点对点加密, 程序破解, 网络安全, 网络安全, 网络隧道, 隐私保护, 隐私保护, 零依赖