基本原理
VPN的基本原理是通过加密和隧道技术在公共网络(如互联网)上创建一个虚拟的专用网络。这些技术确保了数据的保密性、完整性和真实性。
- 加密:VPN加密传输的数据,使其在公共网络上不可读。
- 隧道:VPN将数据打包,通过一个称为隧道的加密通道传输,保护数据免受窥探和篡改。
工作流程
以下是VPN的基本工作流程:
- 客户端与服务器连接:VPN客户端通过互联网与VPN服务器建立连接。
- 身份验证:客户端向服务器验证身份。常见的身份验证方法包括用户名和密码、数字证书、双因素认证等。
- 隧道建立:在身份验证通过后,客户端和服务器之间建立安全的隧道。隧道协议和加密算法在此阶段确定。
- 数据传输:数据在隧道中进行加密和解密传输。客户端和服务器负责对数据进行加密和解密,以确保安全。
- 数据解包和转发:VPN服务器解包数据包并将其转发到目标网络,或者从目标网络接收数据包并返回给客户端。
主要组件
- 隧道协议
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协议,设计简洁,性能和安全性良好。
- 加密算法
VPN使用加密算法来保护数据。常见的加密算法有:
- AES(Advanced Encryption Standard):广泛使用的对称加密算法,安全性高,性能良好。
- 3DES(Triple Data Encryption Standard):一种对称加密算法,较AES慢且不推荐在现代应用中使用。
- RSA:一种用于密钥交换的非对称加密算法。
- DH(Diffie-Hellman):一种密钥交换协议,用于安全地生成会话密钥。
WireGuard 协议
主要数据包类型包括:
- Handshake Initiation data packet(握手初始数据包)
- Handshake Response data packet(握手响应数据包)
- Cookie Reply data packet(Cookie 回复数据包)
- 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],
}
- 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),
})
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。