基本原理

VPN的基本原理是通过加密和隧道技术在公共网络(如互联网)上创建一个虚拟的专用网络。这些技术确保了数据的保密性、完整性和真实性。

  • 加密:VPN加密传输的数据,使其在公共网络上不可读。
  • 隧道:VPN将数据打包,通过一个称为隧道的加密通道传输,保护数据免受窥探和篡改。

工作流程

以下是VPN的基本工作流程:

  1. 客户端与服务器连接:VPN客户端通过互联网与VPN服务器建立连接。
  2. 身份验证:客户端向服务器验证身份。常见的身份验证方法包括用户名和密码、数字证书、双因素认证等。
  3. 隧道建立:在身份验证通过后,客户端和服务器之间建立安全的隧道。隧道协议和加密算法在此阶段确定。
  4. 数据传输:数据在隧道中进行加密和解密传输。客户端和服务器负责对数据进行加密和解密,以确保安全。
  5. 数据解包和转发:VPN服务器解包数据包并将其转发到目标网络,或者从目标网络接收数据包并返回给客户端。

主要组件

  1. 隧道协议

VPN使用各种隧道协议来建立和管理隧道连接。常见的隧道协议包括:

  • PPTP(Point-to-Point Tunneling Protocol):一种早期的VPN协议,易于配置,但安全性较弱。
  • L2TP/IPsec(Layer 2 Tunneling Protocol with IPsec):结合了L2TP的隧道功能和IPsec的加密功能,安全性较高。
  • OpenVPN:一个开源的VPN协议,高度可配置,支持多种加密算法和验证机制。
  • IKEv2/IPsec(Internet Key Exchange version 2 with IPsec):快速、可靠,尤其在移动设备上表现优秀,支持断线重连。
  • WireGuard:一个现代、高效的VPN协议,设计简洁,性能和安全性良好。
  1. 加密算法

VPN使用加密算法来保护数据。常见的加密算法有:

  • AES(Advanced Encryption Standard):广泛使用的对称加密算法,安全性高,性能良好。
  • 3DES(Triple Data Encryption Standard):一种对称加密算法,较AES慢且不推荐在现代应用中使用。
  • RSA:一种用于密钥交换的非对称加密算法。
  • DH(Diffie-Hellman):一种密钥交换协议,用于安全地生成会话密钥。

WireGuard 协议

主要数据包类型包括:

  1. Handshake Initiation data packet(握手初始数据包)
  2. Handshake Response data packet(握手响应数据包)
  3. Cookie Reply data packet(Cookie 回复数据包)
  4. Data Transmission data packet(数据传输数据包)
1. Handshake Initiation Data Packet (类型 1)
该数据包用于初始化握手过程。其格式如下:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Type = 1          |         Reserved = 0          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Sender's Index                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                        Sender's Ephemeral Public Key        +
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                       Encrypted Static Key                  |
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                       Encrypted Timestamp                   |
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type (0-15 bits, 共16位):表示数据包的类型。对Handshake Initiation数据包而言,这个值固定为1。Reserved(16-31位,共16位):保留字段,固定为0。

Sender's Index(32-63位,共32位):一个随机生成的32位无符号整数,用于标识当前会话。这是发送者生成和使用的本地标识。

Sender's Ephemeral Public Key(64-319位,共256位):发送者的临时公钥,采用 Curve25519 加密算法。这个公钥是临时的,每次握手时重新生成。

Encrypted Static Key(320-575位,共256位):发送者的静态公钥,经过加密后发送。接收者使用临时公钥对其解密来验证发送者的身份。

Encrypted Timestamp(576-831位,共256位):一个时间戳,经过加密后发送,用于防止重放攻击。接收者使用临时公钥对其解密。


Handshake Response Data Packet (类型 2)
Handshake Response 数据包用于响应握手初始数据包,格式如下:
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Type = 2          |         Reserved = 0          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Receiver's Index                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Sender's Index                         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                    Sender's Ephemeral Public Key            +
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                       Encrypted Timestamp                   |
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                       MAC for Handshake                     |
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type (0-15 bits, 共16位):表示数据包的类型,对握手响应数据包类型而言,这个值固定为2。
Reserved(16-31位,共16位):保留字段,固定为0。

Receiver's Index(32-63位,共32位):接收者用于标识会话的32位无符号整数。与发送者的索引不同,这是接收者生成和使用的标识。

Sender's Index(64-95位,共32位):发送握手请求者的会话标识,与握手初始数据包的会话标识一致。

Sender's Ephemeral Public Key(96-351位,共256位):握手响应请求者的临时公钥,使用 Curve25519 加密算法。

Encrypted Timestamp(352-607位,共256位):一个时间戳,使用临时公钥加密,用于防止重放攻击。

MAC for Handshake(608-863位,共256位):消息验证码,用于确保数据完整性和身份验证,使用发送者和接收者之间共享的密钥生成。


Cookie Reply Data Packet(类型 3)
Cookie Reply 数据包用于防止DoS攻击,具体格式如下:
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Type = 3          |         Reserved = 0          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Receiver's Index                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|               Encrypted Cookie for DoS Mitigation           |
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type (0-15 bits, 共16位):表示数据包的类型,对Cookie回复数据包类型而言,这个值固定为3。
Reserved(16-31位,共16位):保留字段,固定为0。

Receiver's Index(32-63位,共32位):接收者用于标识会话的32位无符号整数。

Encrypted Cookie for DoS Mitigation(64-319位,共256位):用于防止DoS攻击的加密Cookie,接收者可以验证此Cookie从而判断请求的合法性。


Data Transmission Data Packet(类型 4)
数据传输数据包用于传递实际的数据,具体格式如下:

0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Type = 4          |         Receiver's Index      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                     Counter (64 bits)                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                             |
+                                                             +
|                                                             |
+                      Encrypted Payload                      +
|                                                             |
+                                                             +
|                                                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type (0-15 bits, 共16位):表示数据包的类型,对数据传输数据包类型而言,这个值固定为4。

Receiver's Index(16-47位,共32位):接收方使用的会话标识符。用于在接收方识别属于哪一个会话。

Counter(48-111位,共64位):一个64位的计数器,每个会话内的每个数据包都有一个唯一的计数器值。用于防止重放攻击并确保数据完整性。

Encrypted Payload(112位起):加密后的实际数据负载,使用会话密钥加密。


这里以boringtun 为例来说明: (https://github.com/cloudflare/boringtun.git)
类别定义:

type MessageType = u32;
const HANDSHAKE_INIT: MessageType = 1;
const HANDSHAKE_RESP: MessageType = 2;
const COOKIE_REPLY: MessageType = 3;
const DATA: MessageType = 4;

Handshake Initiation Data Packet (类型 1)

#[derive(Debug)]
pub struct HandshakeInit<'a> {
    sender_idx: u32,
    unencrypted_ephemeral: &'a [u8; 32],
    encrypted_static: &'a [u8],
    encrypted_timestamp: &'a [u8],
}

Handshake Response data packet(握手响应数据包)

#[derive(Debug)]
pub struct HandshakeResponse<'a> {
    sender_idx: u32,
    pub receiver_idx: u32,
    unencrypted_ephemeral: &'a [u8; 32],
    encrypted_nothing: &'a [u8],
}
  1. Cookie Reply data packet(Cookie 回复数据包)
#[derive(Debug)]
pub struct PacketCookieReply<'a> {
    pub receiver_idx: u32,
    nonce: &'a [u8],
    encrypted_cookie: &'a [u8],
}

Data Transmission data packet(数据传输数据包)

#[derive(Debug)]
pub struct PacketData<'a> {
    pub receiver_idx: u32,
    counter: u64,
    encrypted_encapsulated_packet: &'a [u8],
}

协议处理过程:

  #[inline(always)]
    pub fn parse_incoming_packet(src: &[u8]) -> Result<Packet, WireGuardError> {
        if src.len() < 4 {
            return Err(WireGuardError::InvalidPacket);
        }

        // Checks the type, as well as the reserved zero fields
        let packet_type = u32::from_le_bytes(src[0..4].try_into().unwrap());

        Ok(match (packet_type, src.len()) {
            (HANDSHAKE_INIT, HANDSHAKE_INIT_SZ) => Packet::HandshakeInit(HandshakeInit {
                sender_idx: u32::from_le_bytes(src[4..8].try_into().unwrap()),
                unencrypted_ephemeral: <&[u8; 32] as TryFrom<&[u8]>>::try_from(&src[8..40])
                    .expect("length already checked above"),
                encrypted_static: &src[40..88],
                encrypted_timestamp: &src[88..116],
            }),
            (HANDSHAKE_RESP, HANDSHAKE_RESP_SZ) => Packet::HandshakeResponse(HandshakeResponse {
                sender_idx: u32::from_le_bytes(src[4..8].try_into().unwrap()),
                receiver_idx: u32::from_le_bytes(src[8..12].try_into().unwrap()),
                unencrypted_ephemeral: <&[u8; 32] as TryFrom<&[u8]>>::try_from(&src[12..44])
                    .expect("length already checked above"),
                encrypted_nothing: &src[44..60],
            }),
            (COOKIE_REPLY, COOKIE_REPLY_SZ) => Packet::PacketCookieReply(PacketCookieReply {
                receiver_idx: u32::from_le_bytes(src[4..8].try_into().unwrap()),
                nonce: &src[8..32],
                encrypted_cookie: &src[32..64],
            }),
            (DATA, DATA_OVERHEAD_SZ..=std::usize::MAX) => Packet::PacketData(PacketData {
                receiver_idx: u32::from_le_bytes(src[4..8].try_into().unwrap()),
                counter: u64::from_le_bytes(src[8..16].try_into().unwrap()),
                encrypted_encapsulated_packet: &src[16..],
            }),
            _ => return Err(WireGuardError::InvalidPacket),
        })
    }

putao
8 声望1 粉丝

推动世界向前发展,改善民生。