Протокол miIO
Общие положения
miIO - проприетарный шифрованный сетевой протокол Xiaomi, по которому взаимодействуют wifi-устройства из экосистемы Xiaomi и приложение Mihome на смартфоне. В качестве транспорта используется UDP и порт 54321. Содержимое пакетов шифруется. Для контроля корректности принимаемых пакетов используется контрольная сумма на основе алгоритма MD5.
Данный протокол используется только при взаимодействии в пределах локальной сети. Взаимодействие между устройствами, приложением Mihome и облаком Xiaomi осуществляется по другому протоколу, расшифровать который пока никому не удалось.
Структура пакета
В протоколе miIO различают два типа пакетов - основной и hello-пакет. Hello-пакет применяется для поиска устройств в сети путем его широковещательной рассылки, либо для начала сессии с конкретным устройством. Для отправки устройству непосредственно команд используется основной пакет.
Пакет формируется из данных в hex-формате, состоит из заголовка (header) и полезной нагрузки (data).
Структура полей пакета приведена на схеме:
- Magic - "магическое" число, всегда равно 0х2131 (2 байта).
- Length - длина пакета в байтах(заголовок+данные) (2 байта).
- Unknown - поле неизвестного назначения. Всегда заполнено нулями 0х00000000, а у hello-пакета 0хFFFFFFFF (4 байта).
- Device type - тип устройства (2 байта).
- Device ID - идентификатор устройства (2 байта).
- Time stamp - временная отметка, время работы устройства в секундах (4 байта).
- Checksum - контрольная сумма всего пакета по алгоритму MD5. Перед расчетом КС это поле временно заполняется нулями (16 байт).
- Data - полезная нагрузка произвольной длины - зашифрованные данные, отправляемые устройству. В hello-пакете это поле отсутствует.
В hello-пакете все поля, кроме Magic и Length, принимают значение 0хFF.
В особом случае, при ответе на hello-пакет, поле Checksum будет содержать 128-битное уникальное значение токена устройства. Это правило всегда актуально для новых устройств, которые еще не подключены к домашней wifi точке доступа (не проинициализированы). В остальных случаях все зависит от прошивки устройства.
Сессия
Любое взаимодействие клиента и устройства начинается с "рукопожатия" (handshake). Клиент отправляет hello-пакет устройству и ждет от него ответ. Устройство в ответном пакете (длиной также 32 байта) отправляет свой тип, идентификатор, время работы в секундах и токен (либо нули вместо него). На основе полученных данных клиент формирует основной пакет с зашифрованной командой и отправляет устройству. Получив и выполнив команду от клиента, устройство отправляет ответный пакет с результатом выполнения принятой команды либо с ошибкой ее выполнения.
Процедура "рукопожатия" также используется для поиска устройств в локальной сети (discover). При этом hello-пакет отправляется не на конкретный IP, а на широковещательный адрес сегмента сети. Таким образом hello-пакеты получают все устройства, находящиеся в этом сегменте сети, и соответственно сообщают обратно клиенту о своем существовании.
Шифрование
Для шифрования отправляемых данных используется симметричный алгоритм шифрование AES128 в режиме CBC. 128-битные ключ шифрования (Key) и вектор инициализации (IV) формируются из уникального токена устройства по следующим формулам:
- Key = MD5(Token);
- IV = MD5(Token+IV);
Перед шифрованием необходимо выполнить процедуру дополнения данных PKCS#7 padding, а после расшифровки - обратную процедуру.
Формат API-команд
Команды, отправляемые устройству и принимаемые от него, представлены в формате JSON.
Запрос:
1 |
{"id":1,"method":"get_prop","params":["power"]} |
Ответ:
1 |
{"id":1,"result":["ok"]} |
Основные поля - это:
- id - идентификатор запроса. Его значение не является обязательным для большинства устройств, поэтому можно всегда выставлять равным 1. Но может быть полезен, когда одному и тому же устройству одновременно отправляются команды с разных клиентов. Для некоторых устройств (например, пылесос) данный параметр должен быть уникальным при каждом запросе.
- method - метод, действие. Возможные варианты зависят от конкретного устройства, но есть и общие для всех.
- params - массив свойств, параметров. Возможные варианты зависят от конкретного устройства.