VMess Protocol
VMess is the original encrypted communication protocol of V2Ray.
VMess protocol header has two authentication methods:
- AEAD Authentication: Uses AEAD encryption to ensure the integrity of the protocol header;
- MD5 Authentication: Traditional authentication method, uses MD5 + AES-128-CFB to encrypt the protocol header, cannot guarantee the integrity of the header itself.
Warning
MD5 authentication is deprecated. Please use AEAD authentication.
Currently, VMess can automatically negotiate between AEAD and MD5 authentication based on the protocol header.
Version
The current version number is 1.
Dependencies
Underlying Protocol
VMess is a TCP-based protocol, and all data is transmitted using TCP.
User ID
ID is equivalent to UUID, which is a 16-byte random number that functions as a token. An ID has the form: de305d54-75b4-431b-adb2-eb6b9e546014, almost completely random, and can be generated by any UUID generator, such as this one.
The user ID can be specified in the configuration file.
Functions
MD5: MD5 function
- Input: byte array of any length
- Output: 16-byte array
HMAC: HMAC function
- Input parameters:
- H: Hash function
- K: Key, byte array of any length
- M: Message, byte array of any length
- Input parameters:
Shake: SHA3-Shake128 function
- Input: byte array of any length
- Output: byte array of any length
KDF: Key Derivation Function, takes a master key in byte array form and several path components in byte array form, generates a subkey (used for AEAD authentication)
KDF(key, path...): hmac_creator = HMAC(SHA256, "VMess AEAD KDF") for each p in path: hmac_creator = HMAC(hmac_creator, p) return hmac_creator(key)CmdKey: A 16-byte key derived from user UUID (used for AEAD authentication)
CmdKey = MD5(UUID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
Communication Process
VMess is a stateless protocol, meaning the client and server can transmit data directly without handshaking, and each data transmission has no effect on other transmissions before or after.
The VMess client initiates a request, and the server determines whether the request comes from a legitimate client. If verification passes, the request is forwarded, and the obtained response is sent back to the client.
VMess uses an asymmetric format, meaning the request sent by the client and the response from the server use different formats.
Client Request
A client request consists of three parts: Authentication Information, Instruction Section, and Data Section. The format of authentication information and instruction section varies depending on the authentication method.
AEAD Authentication Format
| 16 bytes | 18 bytes | 8 bytes | Y bytes | Remaining |
|---|---|---|---|---|
| EAuID | ALength | Nonce | AHeader | Data Section |
Where:
- EAuID: Encrypted Authentication ID, used to identify user identity;
- ALength: Encrypted instruction section length (2 bytes plaintext + 16 bytes GCM Tag);
- Nonce: Random number for AEAD encryption;
- AHeader: Encrypted instruction section;
- Data Section: Actual transmitted data.
To maintain compatibility with the original protocol and configuration, the client's UUID information must be calculated from and only from the first 16 bytes.
EAuID (Encrypted Authentication ID)
EAuID plaintext format:
| 8 bytes | 4 bytes | 4 bytes |
|---|---|---|
| Timestamp | Rand | CRC |
Where:
- Timestamp: 64-bit Unix timestamp in seconds (Big-Endian);
- Rand: Random number;
- CRC:
CRC32([Timestamp, Rand]), using IEEE polynomial;
EAuID encryption:
- Encryption key:
KDF(CmdKey, "AES Auth ID Encryption")[:16] - Encryption method: AES-128 block cipher
ALength (Encrypted Length)
ALength is the 16-bit big-endian VMess packet header length encrypted with AES-128-GCM.
- Encryption key:
KDF(CmdKey, "VMess Header AEAD Key_Length", EAuID, Nonce)[:16] - Nonce:
KDF(CmdKey, "VMess Header AEAD Nonce_Length", EAuID, Nonce)[:12] - Additional Data (AD): EAuID
AHeader (Encrypted Header)
AHeader is the VMess standard header encrypted with AES-128-GCM (i.e., the instruction section content below).
- Encryption key:
KDF(CmdKey, "VMess Header AEAD Key", EAuID, Nonce)[:16] - Nonce:
KDF(CmdKey, "VMess Header AEAD Nonce", EAuID, Nonce)[:12] - Additional Data (AD): EAuID
AES-GCM requires that Key-Nonce combinations do not repeat. Since EAuID and Nonce are used as KDF inputs for Key and Nonce, there are 96 bits of random entropy to ensure no repetition. Since the user UUID is used as input, it cannot be decrypted by attackers.
MD5 Authentication Format (Deprecated)
| 16 bytes | X bytes | Remaining |
|---|---|---|
| Authentication Info | Instruction Section | Data Section |
Where:
- Authentication Info: HMAC-MD5 hash value, used to verify client identity;
- Instruction Section: AES-128-CFB encrypted instructions;
- Data Section: Actual transmitted data.
Authentication Information
The authentication information is a 16-byte hash value, calculated as follows:
- H = MD5
- K = User ID (16 bytes)
- M = UTC time, accurate to the second, a random value within 30 seconds before or after the current time (8 bytes, Big-Endian)
- Hash = HMAC(H, K, M)
Instruction Section Encryption
The instruction section is encrypted with AES-128-CFB:
- Key:
MD5(User ID + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21')) - IV:
MD5(X + X + X + X), where X = []byte(time when authentication info was generated) (8 bytes, Big-Endian)
Instruction Section (Common)
The structure of the instruction section is the same for both AEAD and MD5 authentication methods, differing only in the encryption method:
- AEAD Authentication: Used as plaintext for AHeader, encrypted with AES-128-GCM;
- MD5 Authentication: Encrypted with AES-128-CFB.
| 1 byte | 16 bytes | 16 bytes | 1 byte | 1 byte | 4 bits | 4 bits | 1 byte | 1 byte | 2 bytes | 1 byte | N bytes | P bytes | 4 bytes |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Version Ver | Request Encryption IV | Request Encryption Key | Response Auth V | Option Opt | Margin P | Encryption Sec | Reserved | Command Cmd | Port | Address Type T | Address A | Random | Checksum F |
Option Opt details (when a bit is 1, the option is enabled):
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| X | X | X | A | P | M | R | S |
Where:
- Version Ver: Always 1;
- Request Encryption IV: Random value;
- Request Encryption Key: Random value;
- Response Auth V: Random value;
- Option Opt:
- S (0x01): Standard format data stream (enabled by default);
- R (0x02): Client expects to reuse TCP connection (deprecated since V2Ray 2.23+);
- Only valid when S is enabled;
- M (0x04): Enable metadata obfuscation (recommended);
- Only valid when S is enabled;
- When enabled, client and server need to construct two Shake instances: RequestMask = Shake(Request Encryption IV), ResponseMask = Shake(Response Encryption IV);
- P (0x08): Global padding;
- Only valid when M is enabled;
- Data section encryption must be AES-128-GCM or ChaCha20-Poly1305;
- When enabled, client and server generate random-length padding bytes based on the Shake instance and append them after the ciphertext;
- A (0x10): Enable authenticated packet length experiment;
- X: Reserved;
- Margin P: Add P random bytes before the checksum;
- Encryption method: Specifies the encryption method for the data section:
- 0x01: Legacy (AES-128-CFB);
- 0x03: AES-128-GCM;
- 0x04: ChaCha20-Poly1305;
- 0x05: None;
- 0x06: Zero (no encryption, no chunking, raw stream);
- Command Cmd:
- 0x01: TCP data;
- 0x02: UDP data;
- Port: Integer port number in Big-Endian format;
- Address Type T:
- 0x01: IPv4;
- 0x02: Domain name;
- 0x03: IPv6;
- Address A:
- When T = 0x01, A is a 4-byte IPv4 address;
- When T = 0x02, A is 1-byte length (L) + L-byte domain name;
- When T = 0x03, A is a 16-byte IPv6 address;
- Checksum F: FNV1a hash of all content in the instruction section except F (Big-Endian);
Data Section (Common)
The data section is used to transmit actual request/response data. There are two formats:
- Basic Format: Direct data transmission, deprecated;
- Standard Format: Chunked data transmission with better encryption and integrity verification (default).
Basic Format (Deprecated)
This format is only for backward compatibility and may be removed in future versions.
All data is considered the actual content of the request. This content will be sent to the address specified in the instruction section. When Cmd = 0x01, the data is sent via TCP; when Cmd = 0x02, the data is sent via UDP.
This format supports None and AES-128-CFB encryption methods. The Key and IV are specified in the instruction section.
Zero Encryption Method
When the encryption method is Zero (0x06), the basic format is forced (instead of standard format), and no encryption is performed. Specific behavior:
- Encryption method is treated as None;
- Opt(S) (standard format) is forcibly disabled;
- Opt(M) (metadata obfuscation) is forcibly disabled;
This means the data section will be transmitted as completely unencrypted raw stream. Note that the protocol header is still encrypted/authenticated using AEAD or MD5.
Standard Format
When Opt(S) is enabled, the data section uses this format. The actual request data is divided into several small chunks, each with the following format. After the server verifies all chunks, it forwards them in basic format.
| 2 bytes | L-P bytes | P bytes |
|---|---|---|
| Length L | Data Packet | Random |
Where:
- Length L:
- Integer in Big-Endian format, maximum value is 2^14;
- When Opt(M) is disabled, actual value of L = data value;
- When Opt(M) is enabled, actual value of L = data value xor Mask. Mask = (RequestMask.NextByte() << 8) + RequestMask.NextByte();
- Padding Length P:
- When Opt(P) is disabled, P = 0, no padding bytes;
- When Opt(P) is enabled, P = ((RequestMask.NextByte() << 8) + RequestMask.NextByte()) % 64;
- Data Packet: Data packet encrypted with the specified encryption method;
Before transmission ends, the data packet must contain actual data, i.e., data other than length and authentication data. When transmission ends, the client must send an empty data packet, i.e., L = 0 (no encryption) or authentication data length (with encryption), to indicate the end of transmission.
Let data packet length R = L - P. According to different encryption methods, the data packet format is as follows:
- No encryption:
- R bytes: Actual data;
- AES-128-CFB: Entire data section is encrypted using AES-128-CFB
- 4 bytes: FNV1a hash of actual data (Big-Endian);
- R - 4 bytes: Actual data;
- AES-128-GCM: Key is the Key from instruction section, IV = count (2 bytes) + IV (10 bytes). Count starts from 0 and increments by 1 for each packet; IV is bytes 3 to 12 of the instruction section IV.
- R - 16 bytes: Actual data;
- 16 bytes: GCM authentication info;
- ChaCha20-Poly1305: Key = MD5(Instruction Section Key) + MD5(MD5(Instruction Section Key)), IV = count (2 bytes) + IV (10 bytes). Count starts from 0 and increments by 1 for each packet; IV is bytes 3 to 12 of the instruction section IV.
- R - 16 bytes: Actual data;
- 16 bytes: Poly1305 authentication info;
Server Response
The server response format corresponds to the client request. The server uses the corresponding response format based on the client request's authentication method (AEAD or MD5).
AEAD Authentication Response
In AEAD authentication mode, the response encryption Key and IV are derived as follows:
- Response Encryption Key:
SHA256(Request Encryption Key)[:16] - Response Encryption IV:
SHA256(Request Encryption IV)[:16]
The response header data is encrypted using AES-128-GCM, divided into length and content parts.
Response length encryption (2 bytes length + 16 bytes GCM Tag):
- Encryption key:
KDF(Response Encryption Key, "AEAD Resp Header Len Key")[:16] - Nonce:
KDF(Response Encryption IV, "AEAD Resp Header Len IV")[:12] - Additional Data (AD): None (nil)
Response content encryption:
- Encryption key:
KDF(Response Encryption Key, "AEAD Resp Header Key")[:16] - Nonce:
KDF(Response Encryption IV, "AEAD Resp Header IV")[:12] - Additional Data (AD): None (nil)
MD5 Authentication Response (Deprecated)
In MD5 authentication mode, the response encryption Key and IV are derived as follows:
- Response Encryption Key:
MD5(Request Encryption Key) - Response Encryption IV:
MD5(Request Encryption IV)
The response header data is encrypted using AES-128-CFB.
Response Header Format
The actual response data varies depending on encryption settings.
| 1 byte | 1 byte | 1 byte | 1 byte | M bytes | Remaining |
|---|---|---|---|---|---|
| Response Auth V | Option Opt | Command Cmd | Command Length M | Command Content | Actual Response Data |
Where:
- Response Auth V: Must match the Response Auth V in the client request;
- Option Opt:
- 0x01: Server is ready to reuse TCP connection (deprecated since V2Ray 2.23+);
- Command Cmd:
- 0x01: Dynamic port instruction;
- Actual Response Data:
- If Opt(S) is enabled in the request, standard format is used; otherwise, basic format is used;
- If Opt(M) is enabled in the request, metadata obfuscation is enabled, with Shake instance ResponseMask;
- If Opt(P) is enabled in the request, global padding is enabled, with Shake instance ResponseMask;
- Format is the same as request data;
Dynamic Port Instruction
| 1 byte | 2 bytes | 16 bytes | 2 bytes | 1 byte | 1 byte |
|---|---|---|---|---|---|
| Reserved | Port | User ID | AlterID | User Level | Valid Time T |
Where:
- Port: Integer port number in Big-Endian format;
- Valid Time T: Minutes;
When the client receives a dynamic port instruction, the server has opened a new port for communication, and the client can send data to the new port. After T minutes, this port will become invalid, and the client must use the main port again for communication.
Notes
- To ensure forward compatibility, the value of all reserved fields must be 0. ENDOFFILE
