核心特点

WireGuard 是现代 VPN 协议,设计理念是简单、高效、安全

  • 代码量:约 4,000 行(对比 OpenVPN 100,000+ 行)
  • 加密套件:固定,无协商(ChaCha20-Poly1305 + Curve25519)
  • 性能:内核态实现,延迟 <1ms,吞吐 10Gbps+
  • 设计哲学:最小化攻击面,无协商 = 无降级攻击

1. 协议概述

1.1 设计目标

WireGuard 设计目标:

┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│  1. 简单                                                        │
│     ├─ 代码量小,易于审计                                       │
│     ├─ 配置简单,一个配置文件                                   │
│     └─ 无复杂状态机                                             │
│                                                                 │
│  2. 高效                                                        │
│     ├─ 内核态实现                                               │
│     ├─ 单 UDP 端口                                              │
│     └─ 零拷贝设计                                               │
│                                                                 │
│  3. 安全                                                        │
│     ├─ 现代加密算法                                             │
│     ├─ 固定加密套件(无协商)                                   │
│     ├─ 完美前向保密                                             │
│     └─ 防重放攻击                                               │
│                                                                 │
│  4. 无状态                                                      │
│     ├─ 无连接概念                                               │
│     ├─ 类似 UDP 的无状态设计                                    │
│     └─ 按需建立隧道                                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.2 与其他 VPN 协议对比

特性WireGuardIPsecOpenVPN
代码量~4,000 行~400,000 行~100,000 行
加密算法固定(无协商)可协商可协商
实现位置内核态内核态用户态
协议UDPESP/UDPTCP/UDP
握手时间~100ms1-3s1-5s
连接状态无状态有状态有状态
配置复杂度简单复杂中等
NAT 穿透原生支持需要额外配置支持

2. 加密算法

2.1 加密套件(固定,无协商)

┌─────────────────────────────────────────────────────────────────┐
│                    WireGuard 加密套件                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  用途              │ 算法                    │ 密钥长度  │   │
│  ├─────────────────────────────────────────────────────────┤   │
│  │  身份认证/密钥交换 │ Curve25519 (ECDH)      │ 256 bits  │   │
│  │  对称加密          │ ChaCha20               │ 256 bits  │   │
│  │  消息认证          │ Poly1305               │ 128 bits  │   │
│  │  哈希函数          │ BLAKE2s                │ 256 bits  │   │
│  │  密钥派生          │ HKDF (基于 BLAKE2s)    │ -         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  为什么固定不协商?                                             │
│  ├─ 防止降级攻击                                               │
│  ├─ 简化实现                                                   │
│  ├─ 减少攻击面                                                 │
│  └─ 确保最高安全性                                             │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.2 Curve25519(密钥交换)

Curve25519 特点:

1. 椭圆曲线 Diffie-Hellman (ECDH)
   ├─ 私钥:32 字节随机数
   ├─ 公钥:32 字节(从私钥派生)
   └─ 共享密钥:32 字节(双方各自计算)

2. 计算过程:
   Alice                          Bob
   ┌──────────────┐              ┌──────────────┐
   │ 私钥 a        │              │ 私钥 b        │
   │ 公钥 A = a*G  │              │ 公钥 B = b*G  │
   └───────┬──────┘              └───────┬──────┘
           │                             │
           │  交换公钥                    │
           │──────── A ─────────────────▶│
           │◀──────────────────── B ─────│
           │                             │
           ▼                             ▼
   ┌──────────────┐              ┌──────────────┐
   │ 共享密钥      │              │ 共享密钥      │
   │ S = a*B      │   = 相同 =   │ S = b*A      │
   │ = a*(b*G)    │              │ = b*(a*G)    │
   └──────────────┘              └──────────────┘

3. 优势:
   ├─ 常数时间实现(防时序攻击)
   ├─ 无需验证(自动处理无效输入)
   └─ 32 字节公钥(传输效率高)

2.3 ChaCha20-Poly1305(加密 + 认证)

ChaCha20-Poly1305 是 AEAD(Authenticated Encryption with Associated Data):

┌─────────────────────────────────────────────────────────────────┐
│                    ChaCha20-Poly1305 加密                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  输入:                                                         │
│  ├─ 明文 (Plaintext)                                           │
│  ├─ 密钥 (256 bits)                                            │
│  ├─ Nonce (96 bits)                                            │
│  └─ AAD (Additional Authenticated Data, 可选)                  │
│                                                                 │
│  输出:                                                         │
│  ├─ 密文 (Ciphertext)                                          │
│  └─ 认证标签 (Auth Tag, 128 bits)                              │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐ │
│  │                                                           │ │
│  │   ChaCha20 Stream Cipher                                  │ │
│  │   ┌─────────────────────────────────────────────────┐    │ │
│  │   │  明文 ── XOR ──▶ 密文                           │    │ │
│  │   │         ▲                                       │    │ │
│  │   │         │                                       │    │ │
│  │   │   Keystream                                    │    │ │
│  │   │   (由密钥 + Nonce 生成)                         │    │ │
│  │   └─────────────────────────────────────────────────┘    │ │
│  │                         │                                 │ │
│  │                         ▼                                 │ │
│  │   Poly1305 MAC                                           │ │
│  │   ┌─────────────────────────────────────────────────┐    │ │
│  │   │  密文 + AAD ──▶ 128-bit 认证标签               │    │ │
│  │   └─────────────────────────────────────────────────┘    │ │
│  │                                                           │ │
│  └───────────────────────────────────────────────────────────┘ │
│                                                                 │
│  最终数据包:                                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  密文 │ 认证标签 (16 bytes)                              │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  优势:                                                         │
│  ├─ 软件实现快(无 AES-NI 依赖)                               │
│  ├─ 常数时间(安全)                                          │
│  ├─ 同时提供加密和认证                                        │
│  └─ 128-bit 认证标签(防篡改)                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

2.4 BLAKE2s(哈希函数)

BLAKE2s 特点:

┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│  用途:                                                         │
│  ├─ 握手消息哈希                                               │
│  ├─ 密钥派生 (HKDF)                                            │
│  └─ 链式密钥计算                                               │
│                                                                 │
│  特点:                                                         │
│  ├─ 输出:256 bits (32 bytes)                                  │
│  ├─ 速度:比 SHA-256 快 3-5 倍                                │
│  ├─ 安全:与 SHA-3 同级别                                     │
│  └─ 针对软件实现优化                                           │
│                                                                 │
│  在 WireGuard 中的使用:                                        │
│                                                                 │
│  HASH(data) = BLAKE2s-256(data)                                │
│                                                                 │
│  MAC(key, data) = BLAKE2s-256(key || data)                     │
│                                                                 │
│  KDF(key, input) = HKDF-BLAKE2s(key, input)                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3. 握手协议

3.1 握手概述

WireGuard 使用 Noise Protocol Framework 的 IK 模式:

特点:
├─ 1-RTT 握手(一个往返)
├─ 双向身份认证
├─ 完美前向保密 (PFS)
├─ 身份隐藏(可选)
└─ 抗重放攻击

密钥层级:
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│  静态密钥 (长期)                                                │
│  ├─ 静态私钥:保存在配置文件中                                  │
│  └─ 静态公钥:与对端共享                                        │
│                                                                 │
│  临时密钥 (短期,每次握手生成)                                   │
│  ├─ 临时私钥:握手后销毁                                        │
│  └─ 临时公钥:在握手消息中传输                                  │
│                                                                 │
│  会话密钥 (由握手派生)                                          │
│  ├─ 发送密钥:用于加密发送的数据                               │
│  └─ 接收密钥:用于解密接收的数据                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3.2 握手流程

┌─────────────────────────────────────────────────────────────────────────┐
│                        WireGuard 握手流程                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Initiator (发起方)                        Responder (响应方)           │
│  ┌─────────────────────┐                   ┌─────────────────────┐     │
│  │ 静态密钥对          │                   │ 静态密钥对          │     │
│  │  私钥: i            │                   │  私钥: r            │     │
│  │  公钥: I = i*G      │                   │  公钥: R = r*G      │     │
│  │                     │                   │                     │     │
│  │ 临时密钥对 (新生成)  │                   │                     │     │
│  │  私钥: e_i          │                   │                     │     │
│  │  公钥: E_i = e_i*G  │                   │                     │     │
│  └──────────┬──────────┘                   └──────────▲──────────┘     │
│             │                                         │                 │
│             │  Message 1 (Initiation)                 │                 │
│             │  ┌─────────────────────────────────────┐│                 │
│             │  │ 类型: 1                             ││                 │
│             │  │ 发送方索引: 12345 (随机)            ││                 │
│             │  │ 临时公钥: E_i (32 bytes)            ││                 │
│             │  │ 加密的静态公钥: Enc(I, ...)         ││                 │
│             │  │ 时间戳: T (12 bytes)                ││                 │
│             │  │ MAC1: ... (16 bytes)                ││                 │
│             │  │ MAC2: ... (16 bytes)                ││                 │
│             │  └─────────────────────────────────────┘│                 │
│             │────────────────────────────────────────▶│                 │
│             │                                         │                 │
│             │                    ┌────────────────────┤                 │
│             │                    │ 生成临时密钥对      │                 │
│             │                    │  私钥: e_r          │                 │
│             │                    │  公钥: E_r          │                 │
│             │                    │                     │                 │
│             │                    │ 派生会话密钥:       │                 │
│             │                    │  使用 E_i, I, R, E_r│                 │
│             │                    └────────────────────┘                 │
│             │                                         │                 │
│             │  Message 2 (Response)                   │                 │
│             │  ┌─────────────────────────────────────┐│                 │
│             │  │ 类型: 2                             ││                 │
│             │  │ 发送方索引: 67890 (随机)            ││                 │
│             │  │ 接收方索引: 12345 (来自消息1)       ││                 │
│             │  │ 临时公钥: E_r (32 bytes)            ││                 │
│             │  │ 加密数据: Enc(..., 会话密钥)        ││                 │
│             │  │ MAC1: ... (16 bytes)                ││                 │
│             │  │ MAC2: ... (16 bytes)                ││                 │
│             │  └─────────────────────────────────────┘│                 │
│             │◀────────────────────────────────────────│                 │
│             │                                         │                 │
│  ┌──────────┴──────────┐                              │                 │
│  │ 派生会话密钥:        │                              │                 │
│  │  使用 E_i, I, R, E_r │                              │                 │
│  │  与 Responder 相同   │                              │                 │
│  └─────────────────────┘                              │                 │
│             │                                         │                 │
│             │  ========== 握手完成,开始数据传输 ==========            │
│             │                                         │                 │
│             │  Data Messages (双向)                   │                 │
│             │  ┌─────────────────────────────────────┐│                 │
│             │  │ 类型: 4                             ││                 │
│             │  │ 接收方索引                          ││                 │
│             │  │ 计数器 (防重放)                     ││                 │
│             │  │ 加密数据                            ││                 │
│             │  └─────────────────────────────────────┘│                 │
│             │◀═══════════════════════════════════════▶│                 │
│             │             双向加密通信                 │                 │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

3.3 握手消息格式

┌─────────────────────────────────────────────────────────────────────────┐
│                     Message 1: Initiation (148 bytes)                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────┬─────────┬─────────────────────────────────────────────┐   │
│  │ Offset  │ Size    │ 字段                                         │   │
│  ├─────────┼─────────┼─────────────────────────────────────────────┤   │
│  │ 0       │ 1 byte  │ 消息类型 (0x01)                              │   │
│  │ 1       │ 3 bytes │ 保留 (全 0)                                  │   │
│  │ 4       │ 4 bytes │ 发送方索引 (Sender Index, 随机)             │   │
│  │ 8       │ 32 bytes│ 临时公钥 E_i (Ephemeral Public Key)         │   │
│  │ 40      │ 48 bytes│ 加密的静态公钥 (Encrypted Static PubKey)    │   │
│  │ 88      │ 28 bytes│ 加密时间戳或其他数据                         │   │
│  │ 116     │ 16 bytes│ MAC1 (对整个消息的认证)                     │   │
│  │ 132     │ 16 bytes│ MAC2 (可选,用于cookie验证)                 │   │
│  └─────────┴─────────┴─────────────────────────────────────────────┘   │
│                                                                         │
│  总大小:148 bytes                                                       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                     Message 2: Response (92 bytes)                       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────┬─────────┬─────────────────────────────────────────────┐   │
│  │ Offset  │ Size    │ 字段                                         │   │
│  ├─────────┼─────────┼─────────────────────────────────────────────┤   │
│  │ 0       │ 1 byte  │ 消息类型 (0x02)                              │   │
│  │ 1       │ 3 bytes │ 保留 (全 0)                                  │   │
│  │ 4       │ 4 bytes │ 发送方索引 (Sender Index)                   │   │
│  │ 8       │ 4 bytes │ 接收方索引 (Receiver Index, 来自消息1)      │   │
│  │ 12      │ 32 bytes│ 临时公钥 E_r (Ephemeral Public Key)         │   │
│  │ 44      │ 16 bytes│ 加密数据 (Empty, 仅用于密钥确认)            │   │
│  │ 60      │ 16 bytes│ MAC1                                         │   │
│  │ 76      │ 16 bytes│ MAC2                                         │   │
│  └─────────┴─────────┴─────────────────────────────────────────────┘   │
│                                                                         │
│  总大小:92 bytes                                                        │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────┐
│                     Message 4: Data (变长)                               │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────┬─────────┬─────────────────────────────────────────────┐   │
│  │ Offset  │ Size    │ 字段                                         │   │
│  ├─────────┼─────────┼─────────────────────────────────────────────┤   │
│  │ 0       │ 1 byte  │ 消息类型 (0x04)                              │   │
│  │ 1       │ 3 bytes │ 保留 (全 0)                                  │   │
│  │ 4       │ 4 bytes │ 接收方索引 (Receiver Index)                 │   │
│  │ 8       │ 8 bytes │ 计数器 (Counter, 防重放)                    │   │
│  │ 16      │ N bytes │ 加密数据 (Encrypted Payload)                │   │
│  └─────────┴─────────┴─────────────────────────────────────────────┘   │
│                                                                         │
│  最小大小:32 bytes (16 bytes 头部 + 16 bytes Poly1305 tag)             │
│  最大大小:65535 bytes (UDP 限制)                                       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

3.4 密钥派生详解

┌─────────────────────────────────────────────────────────────────────────┐
│                        密钥派生过程                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  初始状态:                                                              │
│  ├─ Initiator: 静态密钥 (i, I), 临时密钥 (e_i, E_i)                     │
│  ├─ Responder: 静态密钥 (r, R)                                          │
│  └─ Initiator 知道 Responder 的静态公钥 R                               │
│                                                                         │
│  Step 1: Initiator 发送 Message 1                                       │
│  ─────────────────────────────────────                                  │
│  计算:                                                                  │
│    DH1 = DH(e_i, R)           = e_i * R        # 临时-静态 DH           │
│    DH2 = DH(i, R)             = i * R          # 静态-静态 DH           │
│                                                                         │
│  派生中间密钥:                                                          │
│    C_i = KDF(DH1, DH2)                                                  │
│                                                                         │
│  使用 C_i 加密静态公钥 I 和时间戳                                        │
│                                                                         │
│                                                                         │
│  Step 2: Responder 收到 Message 1,发送 Message 2                       │
│  ───────────────────────────────────────────────────────────            │
│  计算:                                                                  │
│    DH1 = DH(r, E_i)           = r * E_i        # 对应 e_i * R           │
│    DH2 = DH(r, I)             = r * I          # 对应 i * R             │
│                                                                         │
│  生成临时密钥对 (e_r, E_r)                                               │
│                                                                         │
│  计算:                                                                  │
│    DH3 = DH(e_r, E_i)         = e_r * E_i      # 临时-临时 DH           │
│    DH4 = DH(e_r, I)           = e_r * I        # 临时-静态 DH           │
│                                                                         │
│  派生最终会话密钥:                                                      │
│    T_i = KDF(DH1, DH2, DH3, DH4)                                        │
│                                                                         │
│    (发送密钥, 接收密钥) = Split(T_i)                                     │
│                                                                         │
│                                                                         │
│  Step 3: Initiator 收到 Message 2                                       │
│  ─────────────────────────────────────                                  │
│  计算:                                                                  │
│    DH3 = DH(e_i, E_r)         = e_i * E_r      # 对应 e_r * E_i         │
│    DH4 = DH(i, E_r)           = i * E_r        # 对应 e_r * I           │
│                                                                         │
│  派生最终会话密钥:                                                      │
│    T_i = KDF(DH1, DH2, DH3, DH4)  # 与 Responder 相同                  │
│                                                                         │
│    (发送密钥, 接收密钥) = Split(T_i)                                     │
│                                                                         │
│                                                                         │
│  最终结果:                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ Initiator                     Responder                          │   │
│  │ ├─ 发送密钥: K_send           ├─ 发送密钥: K_recv                │   │
│  │ └─ 接收密钥: K_recv           └─ 接收密钥: K_send                │   │
│  │                                  (互为相反)                        │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

4. 数据传输

4.1 数据包结构

┌─────────────────────────────────────────────────────────────────────────┐
│                        WireGuard 数据包                                  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  外层 (UDP/IP):                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ IP 头 │ UDP 头 │ WireGuard 载荷                                  │   │
│  │ 20 B  │ 8 B    │ 变长                                             │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  WireGuard 载荷 (Message Type 4):                                       │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 类型   │ 保留  │ 接收方索引 │ 计数器  │ 加密数据 + Poly1305 Tag │   │
│  │ 1 byte │ 3 B   │ 4 bytes    │ 8 bytes │ 变长 (最少 16 B)        │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  加密数据内部 (解密后):                                                  │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 原始 IP 数据包                                                   │   │
│  │ ├─ IP 头 (20+ bytes)                                            │   │
│  │ ├─ TCP/UDP 头                                                   │   │
│  │ └─ 应用数据                                                     │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  完整封装示例:                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 外层 IP │ UDP │ WG 头 │ 加密的内层 IP │ TCP │ HTTP 数据 │ Tag   │   │
│  │ 20 B    │ 8 B │ 16 B  │ 20 B          │ 20 B│ 变长      │ 16 B  │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  总开销:20 + 8 + 16 + 16 = 60 bytes (不含内层 IP)                       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

4.2 防重放机制

┌─────────────────────────────────────────────────────────────────────────┐
│                        防重放机制                                        │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  WireGuard 使用 64 位计数器 + 滑动窗口                                   │
│                                                                         │
│  计数器:                                                                │
│  ├─ 每个数据包有唯一的 64 位计数器                                       │
│  ├─ 从 0 开始递增                                                       │
│  └─ 计数器不连续的数据包被丢弃                                           │
│                                                                         │
│  滑动窗口:                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  接收窗口 (2048 位位图)                                         │   │
│  │  ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐    │   │
│  │  │ 0 │ 0 │ 1 │ 1 │ 0 │ 1 │ 1 │ 1 │ 0 │ 0 │ 0 │ 0 │ 0 │ 0 │...│    │   │
│  │  └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘    │   │
│  │          ▲                               ▲                      │   │
│  │          │                               │                      │   │
│  │       最低位                         最高位                     │   │
│  │     (窗口起点)                      (窗口终点)                  │   │
│  │                                                                 │   │
│  │  窗口大小:2048 个包                                             │   │
│  │  1 = 已接收, 0 = 未接收/可接收                                   │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  判断逻辑:                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  收到计数器 = C 的数据包:                                       │   │
│  │                                                                 │   │
│  │  if C > 最高位:                                                 │   │
│  │      # 新包,更新窗口                                           │   │
│  │      窗口右移 (C - 最高位) 位                                    │   │
│  │      标记 C 为已接收                                            │   │
│  │      接受数据包                                                 │   │
│  │                                                                 │   │
│  │  elif C < 最低位:                                               │   │
│  │      # 太旧,在窗口之外                                         │   │
│  │      丢弃数据包 (可能是重放)                                    │   │
│  │                                                                 │   │
│  │  else:                                                          │   │
│  │      # 在窗口内                                                 │   │
│  │      if 位图[C - 最低位] == 1:                                  │   │
│  │          # 已经接收过                                           │   │
│  │          丢弃数据包 (重放攻击)                                  │   │
│  │      else:                                                      │   │
│  │          # 新包                                                 │   │
│  │          标记 C 为已接收                                        │   │
│  │          接受数据包                                             │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  64 位计数器容量:                                                       │
│  ├─ 2^64 = 1.8 × 10^19 个包                                             │
│  ├─ 即使每秒 100 万包,可运行 584,000 年                               │
│  └─ 实际上永不溢出                                                      │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

4.3 密钥轮换

┌─────────────────────────────────────────────────────────────────────────┐
│                        密钥轮换机制                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  WireGuard 自动进行密钥轮换,确保完美前向保密                             │
│                                                                         │
│  触发条件:                                                              │
│  ├─ 时间:2-3 分钟无数据传输后                                           │
│  ├─ 数据量:发送约 2^64 字节后(实际上不会触发)                          │
│  └─ 或者:一方主动发起重握手                                            │
│                                                                         │
│  轮换流程:                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  时间线:                                                        │   │
│  │  ─────────────────────────────────────────────────────────────│   │
│  │  T=0         T=2min        T=4min        T=6min                │   │
│  │    │           │             │             │                    │   │
│  │    ▼           ▼             ▼             ▼                    │   │
│  │  握手1      握手2         握手3         握手4                   │   │
│  │  密钥K1     密钥K2        密钥K3        密钥K4                  │   │
│  │    │           │             │             │                    │   │
│  │    │  2分钟     │  2分钟      │  2分钟      │                    │   │
│  │    └───────────┴─────────────┴─────────────┘                    │   │
│  │                                                                 │   │
│  │  密钥独立性:                                                    │   │
│  │  ├─ K2 无法从 K1 派生                                           │   │
│  │  ├─ 知道 K1 不能解密 K2 时期的流量                              │   │
│  │  └─ 完美前向保密 (Perfect Forward Secrecy)                      │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  轮换过程(无感知):                                                    │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  1. 发送方检测到需要重新握手                                     │   │
│  │     └─ 距上次握手超过 2 分钟                                    │   │
│  │                                                                 │   │
│  │  2. 发送方发送新的握手消息 (Message 1)                          │   │
│  │     └─ 生成新的临时密钥对                                       │   │
│  │                                                                 │   │
│  │  3. 完成新的握手                                                 │   │
│  │     └─ 派生新的会话密钥                                         │   │
│  │                                                                 │   │
│  │  4. 切换到新密钥                                                 │   │
│  │     ├─ 旧密钥销毁                                               │   │
│  │     └─ 使用新密钥加密后续数据                                   │   │
│  │                                                                 │   │
│  │  5. 应用层完全无感知                                             │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

5.1 DoS 防护

┌─────────────────────────────────────────────────────────────────────────┐
│                        Cookie 机制(防 DoS)                             │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  问题:攻击者可能发送大量伪造的握手消息                                   │
│  ├─ 消耗 CPU 进行加密计算                                              │
│  └─ 消耗内存存储会话状态                                               │
│                                                                         │
│  解决方案:Cookie 验证机制                                              │
│  ├─ 类似 SYN Cookie                                                    │
│  ├─ 在负载高时要求客户端证明其 IP 可达                                  │
│  └─ 无状态验证                                                         │
│                                                                         │
│  流程:                                                                  │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  正常情况:                                                      │   │
│  │  Client ──── Message 1 ────▶ Server                            │   │
│  │  Client ◀─── Message 2 ───── Server                            │   │
│  │                      (正常响应)                                  │   │
│  │                                                                 │   │
│  │  负载高时:                                                      │   │
│  │  Client ──── Message 1 ────▶ Server                            │   │
│  │  Client ◀─── Cookie Reply ── Server                            │   │
│  │            (MAC2 = 空,要求 Cookie)                             │   │
│  │                                                                 │   │
│  │  Client ──── Message 1 ────▶ Server                            │   │
│  │            (带上 MAC2 = Cookie)                                 │   │
│  │  Client ◀─── Message 2 ───── Server                            │   │
│  │                      (验证 Cookie 后正常响应)                    │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Cookie 计算:                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  Cookie = MAC(服务器密钥, 客户端IP || 时间戳)                    │   │
│  │                                                                 │   │
│  │  服务器密钥:每 2 分钟轮换                                       │   │
│  │  时间戳:2 分钟粒度                                              │   │
│  │  结果:Cookie 在 2 分钟内有效                                    │   │
│  │                                                                 │   │
│  │  验证:                                                          │   │
│  │  Cookie' = MAC(当前密钥, 客户端IP || 当前时间)                   │   │
│  │  Cookie'' = MAC(上一密钥, 客户端IP || 上一时间)  // 2分钟重叠   │   │
│  │  if Cookie == Cookie' || Cookie == Cookie'':                    │   │
│  │      验证通过                                                    │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

6. NAT 穿透

6.1 NAT 穿透机制

┌─────────────────────────────────────────────────────────────────────────┐
│                        NAT 穿透机制                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  WireGuard 原生支持 NAT 穿透:                                          │
│  ├─ 使用 UDP 协议                                                       │
│  ├─ Keepalive 机制维持 NAT 映射                                        │
│  └─ 无需 STUN/TURN 等额外协议                                          │
│                                                                         │
│  NAT 类型处理:                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  1. Full Cone NAT (最简单)                                      │   │
│  │     └─ 任何外部地址都可以向映射端口发送数据                      │   │
│  │                                                                 │   │
│  │  2. Restricted Cone NAT                                         │   │
│  │     └─ 只有内部曾发送过数据的 IP 才能发送                        │   │
│  │                                                                 │   │
│  │  3. Port Restricted Cone NAT                                    │   │
│  │     └─ 只有内部曾发送过数据的 IP:Port 才能发送                   │   │
│  │                                                                 │   │
│  │  4. Symmetric NAT (最难)                                        │   │
│  │     └─ 每个目标 IP:Port 映射到不同端口                          │   │
│  │     └─ 需要双方同时发送数据                                     │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Keepalive 机制:                                                        │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  默认:每 25 秒发送一个保活包                                    │   │
│  │  ├─ 维持 NAT 映射有效                                           │   │
│  │  ├─ 检测连接状态                                                │   │
│  │  └─ 包大小:一个空的数据包(32 bytes)                          │   │
│  │                                                                 │   │
│  │  配置:PersistentKeepalive = 25 (秒)                           │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  双向打洞:                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  场景:双方都在 NAT 后面                                        │   │
│  │                                                                 │   │
│  │  Peer A (NAT-A)              Peer B (NAT-B)                    │   │
│  │       │                           │                             │   │
│  │       │──── UDP to B's public ───▶│ (创建 NAT-A 映射)          │   │
│  │       │                           │                             │   │
│  │       │◀─── UDP to A's public ────│ (创建 NAT-B 映射)          │   │
│  │       │                           │                             │   │
│  │       │◀═════════════════════════▶│                            │   │
│  │       │      双向通信建立         │                             │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

7. 性能特性

7.1 性能数据

┌─────────────────────────────────────────────────────────────────────────┐
│                        性能基准                                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  测试环境:Intel i7-8700 (6 核), 10 Gbps NIC                            │
│                                                                         │
│  吞吐量:                                                                │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 场景                    │ 吞吐量        │ CPU 使用率            │   │
│  ├─────────────────────────────────────────────────────────────────┤   │
│  │ 明文 (无加密)           │ 9.5 Gbps      │ 15%                   │   │
│  │ WireGuard (ChaCha20)    │ 8.8 Gbps      │ 35%                   │   │
│  │ WireGuard (AES-NI)      │ 9.2 Gbps      │ 25%                   │   │
│  │ OpenVPN (AES-256-GCM)   │ 1.2 Gbps      │ 100% (单核)           │   │
│  │ IPsec (AES-256-GCM)     │ 7.5 Gbps      │ 45%                   │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  延迟:                                                                  │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 场景                    │ 延迟增加                              │   │
│  ├─────────────────────────────────────────────────────────────────┤   │
│  │ 本地 (同机)             │ +0.1 - 0.3 ms                         │   │
│  │ 同数据中心              │ +0.2 - 0.5 ms                         │   │
│  │ 跨区域                  │ +0.5 - 1.0 ms                         │   │
│  │ 对比 OpenVPN            │ WireGuard 快 5-10×                    │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  握手时间:                                                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ VPN 协议        │ 握手时间        │ 连接数限制                   │   │
│  ├─────────────────────────────────────────────────────────────────┤   │
│  │ WireGuard       │ ~100 ms         │ 无限制                       │   │
│  │ OpenVPN         │ 1-3 s           │ 受限于 TLS                   │   │
│  │ IPsec (IKEv2)   │ 500-1000 ms     │ 受限于 SA                    │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

7.2 内核态实现优势

┌─────────────────────────────────────────────────────────────────────────┐
│                        内核态实现优势                                    │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  对比用户态实现:                                                        │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  用户态 VPN (如 OpenVPN):                                       │   │
│  │  ┌─────────┐     ┌─────────┐     ┌─────────┐                   │   │
│  │  │ 网卡    │ ──▶ │ 内核    │ ──▶ │ 用户态  │                   │   │
│  │  │         │     │         │     │ VPN程序 │                   │   │
│  │  └─────────┘     └─────────┘     └────┬────┘                   │   │
│  │                                       │                         │   │
│  │       拷贝1         拷贝2            ▼                         │   │
│  │                                  ┌─────────┐                   │   │
│  │                                  │ 加密    │                   │   │
│  │                                  └────┬────┘                   │   │
│  │                                       │                         │   │
│  │       拷贝3         拷贝4            ▼                         │   │
│  │  ┌─────────┐     ┌─────────┐     ┌─────────┐                   │   │
│  │  │ 网卡    │ ◀── │ 内核    │ ◀── │ 用户态  │                   │   │
│  │  │ (发送)  │     │         │     │ VPN程序 │                   │   │
│  │  └─────────┘     └─────────┘     └─────────┘                   │   │
│  │                                                                 │   │
│  │  总计:4 次数据拷贝 + 4 次上下文切换                            │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  WireGuard (内核态):                                            │   │
│  │  ┌─────────┐     ┌─────────────────────────────────────────┐   │   │
│  │  │ 网卡    │ ──▶ │ 内核                                    │   │   │
│  │  │         │     │ ┌─────────────────────────────────────┐ │   │   │
│  │  └─────────┘     │ │ WireGuard 模块                      │ │   │   │
│  │                  │ │  - 直接访问 skb                      │ │   │   │
│  │                  │ │  - 内核态加密                        │ │   │   │
│  │                  │ │  - 零拷贝                            │ │   │   │
│  │                  │ └─────────────────────────────────────┘ │   │   │
│  │                  └─────────────────────────────────────────┘   │   │
│  │                                                                 │   │
│  │  总计:0 次数据拷贝 + 0 次上下文切换(相对于网络栈)            │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

8. 安全分析

8.1 安全特性

┌─────────────────────────────────────────────────────────────────────────┐
│                        安全特性总结                                      │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ✅ 完美前向保密 (Perfect Forward Secrecy)                              │
│     └─ 定期重新握手,每次生成新的会话密钥                                │
│     └─ 即使长期私钥泄露,历史流量仍安全                                  │
│                                                                         │
│  ✅ 身份隐藏                                                            │
│     └─ 静态公钥在握手时加密传输                                         │
│     └─ 被动攻击者无法识别参与者                                         │
│                                                                         │
│  ✅ 防重放攻击                                                          │
│     └─ 64 位计数器 + 2048 包滑动窗口                                    │
│     └─ 重放的数据包被丢弃                                               │
│                                                                         │
│  ✅ 防降级攻击                                                          │
│     └─ 加密套件固定,无协商                                             │
│     └─ 无法强制使用弱算法                                               │
│                                                                         │
│  ✅ 常数时间实现                                                        │
│     └─ 所有加密操作在常数时间内完成                                     │
│     └─ 防止时序攻击                                                     │
│                                                                         │
│  ✅ 防 DoS                                                              │
│     └─ Cookie 机制                                                      │
│     └─ 负载高时要求 IP 验证                                             │
│                                                                         │
│  ✅ 密钥隔离                                                            │
│     └─ 发送和接收使用不同的密钥                                         │
│     └─ 密钥独立,互不影响                                               │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

8.2 已知限制

┌─────────────────────────────────────────────────────────────────────────┐
│                        已知限制                                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  1. 后量子安全                                                          │
│     ├─ 当前:Curve25519 不抗量子计算                                    │
│     ├─ 影响:量子计算机可破解密钥交换                                   │
│     └─ 未来:可能需要迁移到后量子算法                                   │
│                                                                         │
│  2. 元数据泄露                                                          │
│     ├─ 攻击者可以看到:                                                 │
│     │   ├─ 源/目的 IP 地址                                              │
│     │   ├─ 时间和流量模式                                               │
│     │   └─ 数据包大小                                                   │
│     └─ 无法看到:加密内容                                               │
│                                                                         │
│  3. 静态对端配置                                                        │
│     ├─ 需要预先知道对端的公钥                                           │
│     └─ 不支持动态发现(需要额外的配置管理)                             │
│                                                                         │
│  4. 无内置用户认证                                                      │
│     ├─ 只验证密钥,不验证用户身份                                       │
│     └─ 需要额外的身份管理层(如 SPIFFE)                                │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

9. 配置示例

9.1 基本配置

# /etc/wireguard/wg0.conf
 
[Interface]
# 本地配置
PrivateKey = ABCD...  # 32 字节 base64 编码私钥
Address = 10.0.0.1/24 # VPN 内部 IP
ListenPort = 51871    # UDP 监听端口
DNS = 1.1.1.1         # 可选:DNS 服务器
 
# MTU 设置(WireGuard 开销 60 bytes)
# MTU = 1420  # 默认 1500 - 60 = 1440,保守设为 1420
 
[Peer]
# 对端配置
PublicKey = EFGH...   # 对端 32 字节 base64 编码公钥
Endpoint = 203.0.113.2:51871  # 对端公网 IP:Port
AllowedIPs = 10.0.0.2/32, 192.168.1.0/24  # 允许通过隧道的 IP
 
# 可选配置
PersistentKeepalive = 25  # 保活间隔(秒),用于 NAT 穿透

9.2 Cilium 配置

# Cilium 使用 WireGuard
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  encryption: "wireguard"
  encryption-node-network: "true"

10. 总结

10.1 WireGuard 的核心优势

┌─────────────────────────────────────────────────────────────────────────┐
│                        WireGuard 核心优势                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  1. 简单性                                                              │
│     ├─ 代码量小(4,000 行)                                             │
│     ├─ 配置简单                                                         │
│     └─ 易于审计和验证                                                   │
│                                                                         │
│  2. 高性能                                                              │
│     ├─ 内核态实现                                                       │
│     ├─ 低延迟(<1ms)                                                   │
│     └─ 高吞吐(10Gbps+)                                                │
│                                                                         │
│  3. 现代加密                                                            │
│     ├─ ChaCha20-Poly1305                                                │
│     ├─ Curve25519                                                       │
│     └─ BLAKE2s                                                          │
│                                                                         │
│  4. 安全设计                                                            │
│     ├─ 完美前向保密                                                     │
│     ├─ 防重放攻击                                                       │
│     ├─ 防降级攻击                                                       │
│     └─ 身份隐藏                                                         │
│                                                                         │
│  5. 网络友好                                                            │
│     ├─ NAT 穿透                                                         │
│     ├─ 漫游支持                                                         │
│     └─ 无连接状态                                                       │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

10.2 适用场景

场景推荐 WireGuard
站点到站点 VPN
远程访问 VPN
云间互联
容器网络加密 (Cilium)
移动设备 VPN
需要复杂认证⚠️ 需要额外层

10.3 一句话总结

WireGuard 是一个简单、高效、安全的现代 VPN 协议,使用固定的现代加密套件(ChaCha20-Poly1305 + Curve25519),内核态实现,提供完美前向保密和防重放攻击,适合各种 VPN 场景。


外部参考