ID эквивалентен [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) - это 16-байтовое случайное число, которое действует как токен.
ID выглядит следующим образом: de305d54-75b4-431b-adb2-eb6b9e546014, он практически полностью случаен и может быть сгенерирован с помощью любого генератора UUID, например [этого](https://www.uuidgenerator.net/).
VMess - это протокол без сохранения состояния, то есть клиент и сервер могут передавать данные напрямую без рукопожатия, и каждая передача данных не влияет на предыдущие или последующие передачи.
Клиент VMess отправляет запрос, а сервер проверяет, исходит ли этот запрос от легитимного клиента. Если проверка пройдена, сервер пересылает запрос и отправляет полученный ответ клиенту.
| Номер версии Ver | Вектор инициализации для шифрования данных | Ключ для шифрования данных | Аутентификация ответа V | Опция Opt | Остаток P | Метод шифрования Sec | Зарезервировано | Команда Cmd | Порт Port | Тип адреса T | Адрес A | Случайные данные | Контрольная сумма F |
- Вектор инициализации для шифрования данных: случайное значение;
- Ключ для шифрования данных: случайное значение;
- Аутентификация ответа V: случайное значение;
- Опция Opt:
- S (0x01): стандартный формат потока данных (рекомендуется включать);
- R (0x02): клиент ожидает повторного использования TCP-соединения (устарело в Xray 2.23+);
- Действительна только при включенной опции S;
- M (0x04): включить обфускацию метаданных (рекомендуется включать);
- Действительна только при включенной опции S;
- Если эта опция включена, клиент и сервер должны создать два экземпляра Shake: RequestMask = Shake(вектор инициализации для шифрования данных запроса), ResponseMask = Shake(вектор инициализации для шифрования данных ответа).
- X: зарезервировано
- Остаток P: добавить P байт случайных данных перед контрольной суммой;
- Метод шифрования: указывает метод шифрования для части с данными, возможные значения:
- 0x00: AES-128-CFB;
- 0x01: без шифрования;
- 0x02: AES-128-GCM;
- 0x03: ChaCha20-Poly1305;
- Команда Cmd:
- 0x01: данные TCP;
- 0x02: данные UDP;
- Порт Port: номер порта в формате Big Endian;
- Тип адреса T:
- 0x01: IPv4
- 0x02: доменное имя
- 0x03: IPv6
- Адрес A:
- Если T = 0x01, A - это 4-байтовый адрес IPv4;
- Если T = 0x02, A - это 1 байт длины (L) + L байт доменного имени;
- Если T = 0x03, A - это 16-байтовый адрес IPv6;
- Контрольная сумма F: хэш FNV1a всей части с командой, кроме F;
### Часть с данными
Если Opt(S) включена, для части с данными используется следующий формат. Фактические данные запроса разбиваются на несколько блоков, каждый из которых имеет следующий формат. После проверки всех блоков сервер пересылает их в соответствии с базовым форматом.
| 2 байта | L байт |
|---------|--------------|
| Длина L | Пакет данных |
Где:
- Длина L: целое число в формате Big Endian, максимальное значение 2^14;
- Если Opt(M) включена, значение L = истинное значение xor Mask. Mask = (RequestMask.NextByte() <<8)+RequestMask.NextByte();
- Пакет данных: пакет данных, зашифрованный указанным методом шифрования;
До завершения передачи в пакете данных должны быть фактические данные, то есть данные, отличные от длины и данных аутентификации. При завершении передачи клиент должен отправить пустой пакет данных, то есть L = 0 (без шифрования) или длину данных аутентификации (с шифрованием), чтобы сигнализировать о завершении передачи.
Формат пакета данных зависит от метода шифрования:
- Без шифрования:
- L байт: фактические данные;
- AES-128-CFB: вся часть с данными шифруется с помощью AES-128-CFB
- 4 байта: хэш FNV1a фактических данных;
- L - 4 байта: фактические данные;
- AES-128-GCM: ключ - это ключ из части с командой, вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
- L - 16 байт: фактические данные;
- 16 байт: данные аутентификации GCM
- ChaCha20-Poly1305: ключ = MD5(ключ из части с командой) + MD5(MD5(ключ из части с командой)), вектор инициализации = count (2 байта) + IV (10 байт). count начинается с 0 и увеличивается на 1 для каждого пакета данных; IV - это байты с 3 по 12 из вектора инициализации части с командой.
- L - 16 байт: фактические данные;
- 16 байт: данные аутентификации Poly1305
## Ответ сервера
Данные заголовка ответа шифруются с помощью AES-128-CFB, вектор инициализации - MD5(вектор инициализации для шифрования данных), ключ - MD5(ключ для шифрования данных). Фактические данные ответа зависят от настроек шифрования.
| 1 байт | 1 байт | 1 байт | 1 байт | M байт | Оставшаяся часть |
| Зарезервировано | Порт Port | Идентификатор пользователя | AlterID | Уровень пользователя | Время действия T |
Где:
- Порт Port: номер порта в формате Big Endian;
- Время действия T: количество минут;
Когда клиент получает команду динамического порта, сервер уже открыл новый порт для связи, и клиент может отправлять данные на этот новый порт. Через T минут этот порт станет недействительным, и клиент должен будет снова использовать основной порт для связи.
## Примечания
- Для обеспечения обратной совместимости все зарезервированные поля должны иметь значение 0.