米家智能设备协议完整具体的分析- Xiaomi Mi Home Binary Protocol
https://awsl.rip/2022/01/07/42988ce3d67b/
背景
米家这种面向消费者的大型项目,数据通行的安全性一定要得到保证。例如米家的摄像头配对后,传输的数据要保证不被第三方从中间手段获取,要有加密后的数据包。
miio.protocol = Xiaomi Mi Home Binary Protocoll
Xiaomi Mi Home Binary Protocol doc:https://github.com/OpenMiHome/mihome-binary-protocol/blob/master/doc/PROTOCOL.md
Xiaomi Miio devices miio协议设备
Packet format
从设计角度来讲,首先构造一个数据包.
首先需要
接下来是安全方面的考量,数据包中要包含该设备的唯一识别码、时间戳、密钥、数据包的校验和(Checksum)以及最重要的——数据本身。
根据以上信息,给出米家数据包头的具体格式便很容易理解。
握手协议(SmartConnect)
Client → Device
Hello Packet
米家的网络传输协议基于UDP,那么对于设备的识别就会变得容易,因为我们可以<broadcast>地址通过网关(家庭路由器或智能网关)直接向局域网中的全部设备广播一个识别数据包,进行有效回显的设备即为支持米家的设备。
这个数据包的名字叫做称为Hello Packet。
发送的Hello Packet内容:
发送的Hello Packet内容:
Device → Client
回显内容中,DID被替换为设备的识别码,Stamp被替换为当前设备的时间戳,Token字段返回设备的Token。
Example output:
Notes注意
数据加密
米家的数据加密使用AES-128-CBC算法,使用PKCS7作为数据填充的方式,加密的密钥和IV矢量如下。
Key = MD5(Token);
IV = MD5(MD5(Key) + Token);
在数据包头部以后,就是我们加密后的数据了,但在填充数据之后还要做一件很关键的事情——修改包头。在米家协议中对数据包头的验证很严格,我们首先需要填写当前数据包生成的时间(相对设备时间戳,但一般应用中为设备时间戳+1)需要用Token填充好Checksum字段(Token字段),然后对整个数据包进行MD5校验,生成的MD5重新写入Checksum字段。
做好这一切后,即可向指定地址的设备发送数据了。
https://awsl.rip/2022/01/07/42988ce3d67b/
背景
米家这种面向消费者的大型项目,数据通行的安全性一定要得到保证。例如米家的摄像头配对后,传输的数据要保证不被第三方从中间手段获取,要有加密后的数据包。
miio.protocol = Xiaomi Mi Home Binary Protocoll
The Mi Home Binary Protocol is used to configure & control smart home devices made by Xiaomi.
It is an encrypted, binary protocol, based on UDP. The designated port is 54321.
Xiaomi is a manufacturer of smart home devices under the "MiHome" label. These devices use an encrypted, proprietary network protocol to communicate with the official smartphone app. It operates on UDP port 54321.
Xiaomi Mi Home Binary Protocol doc:https://github.com/OpenMiHome/mihome-binary-protocol/blob/master/doc/PROTOCOL.md
Xiaomi Miio devices miio协议设备
miIO-discovery获取token与控制 port 54321
Packet format
从设计角度来讲,首先构造一个数据包.
首先需要
从数据包内容中识别出智能家居支持米家,所以一定要构造一个数据包头,在米家协议中是0x2131(Magic Number),数据包的长度也要提供。
接下来是安全方面的考量,数据包中要包含该设备的唯一识别码、时间戳、密钥、数据包的校验和(Checksum)以及最重要的——数据本身。
根据以上信息,给出米家数据包头的具体格式便很容易理解。
struct miioheader{
uint16_t magic = 0x2131; // Magic Number
uint16_t length; // 长度
uint32_t pad_unk = 0x0; // 目前未知,但具体使用时基本置零
uint32_t DID; // 设备识别码
uint32_t stamp; // 数据包时间戳
union {
uint8_t token[16]; // 该设备的密钥
uint8_t chksum[16]; // 校验和
}
};
握手协议(SmartConnect)
Client → Device
Hello Packet
米家的网络传输协议基于UDP,那么对于设备的识别就会变得容易,因为我们可以<broadcast>地址通过网关(家庭路由器或智能网关)直接向局域网中的全部设备广播一个识别数据包,进行有效回显的设备即为支持米家的设备。
这个数据包的名字叫做称为Hello Packet。
设备给我们的回显包含了设备的基本信息,当然,对于Hello Packet来讲,数据只包括上文提到的包头。
发送的Hello Packet内容:
发送的Hello Packet内容:
struct miioheader{
uint16_t magic = 0x2131; // Magic Number
uint16_t length = 0x20; // 长度
uint32_t pad_unk = 0x0; // 目前未知,但具体使用时基本置零
uint32_t DID = 0xFFFFFFFF; // 设备识别码
uint32_t stamp = 0xFFFFFFFF; // 数据包时间戳
union {
uint8_t token[16]; // 该设备的密钥
uint8_t chksum[16]; // 校验和
uint128_t hello = 0xffffffffffffffffffffffffffffffff;
} // 用FF填充
};
Device → Client
回显内容中,DID被替换为设备的识别码,Stamp被替换为当前设备的时间戳,Token字段返回设备的Token。
Example output:
### 192.168.13.2 => 192.168.13.1 (xx:xx:xx:xx:xx:xx => yy:yy:yy:yy:yy:yy)
META: Hello
### 192.168.13.2 <= 192.168.13.1 (xx:xx:xx:xx:xx:xx <= yy:yy:yy:yy:yy:yy)
META: device yy:yy:yy:yy:yy:yy has token: abcdef1234567890abcdef1234567890
### 192.168.13.2 => 192.168.13.1 (xx:xx:xx:xx:xx:xx => yy:yy:yy:yy:yy:yy)
{"id":1234567890,"method":"miIO.config_router",
"params":{"ssid":"WiFi name","passwd":"WiFi password","uid":987654321}}
### 192.168.13.2 <= 192.168.13.1 ( xx:xx:xx:xx:xx:xx <=yy:yy:yy:yy:yy:yy)
{"result":["ok"],"id":1234567890}
Notes注意
在2017-02-23年后的固件中,只有设备第一次配对才会返回设备的Token,其余的Hello Packet回显中该字段均以FF填充。如果已经配对,可以使用您的米家账户在小米云端直接获取设备Token或重置设备。
The 128-bit token is used to identify the device and, more importantly, to encrypt all further communication.
Update 2017-02-23: Xiaomi updated the device firmwares and only uninitialized devices reveal their token now.
As of 2017-02-10, the initialization process ("SmartConnect") leaks the user's WiFi credentials, due to weak encryption. See PROTOCOL.md for more details. I do not recommended connecting MiHome devices to your main WiFi network.
数据加密
米家的数据加密使用AES-128-CBC算法,使用PKCS7作为数据填充的方式,加密的密钥和IV矢量如下。
Key = MD5(Token);
IV = MD5(MD5(Key) + Token);
在数据包头部以后,就是我们加密后的数据了,但在填充数据之后还要做一件很关键的事情——修改包头。在米家协议中对数据包头的验证很严格,我们首先需要填写当前数据包生成的时间(相对设备时间戳,但一般应用中为设备时间戳+1)需要用Token填充好Checksum字段(Token字段),然后对整个数据包进行MD5校验,生成的MD5重新写入Checksum字段。
做好这一切后,即可向指定地址的设备发送数据了。
AES加密
填入时间戳和Token
指令数据
校验和
数据头初始化
0