Протокол VMess

VMess - это зашифрованный транспортный протокол, который может служить мостом между клиентом и сервером Xray.

Версия

Текущая версия протокола - 1.

Зависимости

Базовый протокол

VMess - это протокол, основанный на TCP, все данные передаются по TCP.

Идентификатор пользователя

ID эквивалентен UUIDОткрыть в новой вкладке - это 16-байтовое случайное число, которое действует как токен. ID выглядит следующим образом: de305d54-75b4-431b-adb2-eb6b9e546014, он практически полностью случаен и может быть сгенерирован с помощью любого генератора UUID, например этогоОткрыть в новой вкладке.

Идентификатор пользователя можно указать в файле конфигурации.

Функции

Процесс коммуникации

VMess - это протокол без сохранения состояния, то есть клиент и сервер могут передавать данные напрямую без рукопожатия, и каждая передача данных не влияет на предыдущие или последующие передачи.

Клиент VMess отправляет запрос, а сервер проверяет, исходит ли этот запрос от легитимного клиента. Если проверка пройдена, сервер пересылает запрос и отправляет полученный ответ клиенту.

VMess использует асимметричный формат, то есть запрос, отправляемый клиентом, и ответ сервера имеют разные форматы.

Запрос клиента

16 байтX байтОставшаяся часть
Информация для аутентификацииЧасть с командойЧасть с данными

Информация для аутентификации

Информация для аутентификации - это 16-байтовое хэш-значение, которое вычисляется следующим образом:

  • H = MD5
  • K = идентификатор пользователя (16 байт)
  • M = время UTC с точностью до секунды, случайное значение в диапазоне ±30 секунд от текущего времени (8 байт, Big Endian)
  • Hash = HMAC(H, K, M)

Часть с командой

Часть с командой шифруется с помощью AES-128-CFB:

  • Ключ: MD5(идентификатор пользователя + []byte('c48619fe-8f02-49e0-b9e9-edf763e17e21'))
  • Вектор инициализации: MD5(X + X + X + X), X = []byte(время генерации информации для аутентификации) (8 байт, Big Endian)
1 байт16 байт16 байт1 байт1 байт4 бита4 бита1 байт1 байт2 байта1 байтN байтP байт4 байта
Номер версии VerВектор инициализации для шифрования данныхКлюч для шифрования данныхАутентификация ответа VОпция OptОстаток PМетод шифрования SecЗарезервированоКоманда CmdПорт PortТип адреса TАдрес AСлучайные данныеКонтрольная сумма F

Подробности опции Opt: (если бит равен 1, опция включена)

01234567
XXXXXMRS

Где:

  • Номер версии Ver: всегда равен 1;
  • Вектор инициализации для шифрования данных: случайное значение;
  • Ключ для шифрования данных: случайное значение;
  • Аутентификация ответа 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 байтОставшаяся часть
Аутентификация ответа VОпция OptКоманда CmdДлина команды MСодержимое командыФактические данные ответа

Где:

  • Аутентификация ответа V: должна совпадать с аутентификацией ответа V в запросе клиента;
  • Опция Opt:
    • 0x01: сервер готов повторно использовать TCP-соединение (устарело в Xray 2.23+);
  • Команда Cmd:
    • 0x01: команда динамического порта
  • Фактические данные ответа:
    • Если Opt(S) в запросе включена, используется стандартный формат, в противном случае используется базовый формат.
    • Формат такой же, как и у данных запроса.
      • Если Opt(M) включена, значение длины L = истинное значение xor Mask. Mask = (ResponseMask.NextByte() << 8) + ResponseMask.NextByte();

Команда динамического порта

1 байт2 байта16 байт2 байта1 байт1 байт
ЗарезервированоПорт PortИдентификатор пользователяAlterIDУровень пользователяВремя действия T

Где:

  • Порт Port: номер порта в формате Big Endian;
  • Время действия T: количество минут;

Когда клиент получает команду динамического порта, сервер уже открыл новый порт для связи, и клиент может отправлять данные на этот новый порт. Через T минут этот порт станет недействительным, и клиент должен будет снова использовать основной порт для связи.

Примечания

  • Для обеспечения обратной совместимости все зарезервированные поля должны иметь значение 0.