(WIP) Wireshark dissector for a proprietary protocol found on TP-Link Tapo cameras, dissecting device discovery packets on ports UDP/20002 and UDP/20004, as well as control and media stream packets on port TCP/8800. Tested on TP-Link Tapo C100 IP camera.
Wireshark filters programmed for this protocol:
| Packet Type | Field Name | Description |
|---|---|---|
| Device discovery packet | tapo.header | Raw header bytes |
| Device discovery packet | tapo.signature | Signature bytes |
| Device discovery packet | tapo.payload_length | Payload length |
| Device discovery packet | tapo.unknown_1 | Unknown field number 1 |
| Device discovery packet | tapo.unknown_2 | Unknown field number 2 |
| Device discovery packet | tapo.crc32 | CRC cheksum |
| Device discovery packet | tapo.data | Payload (JSON data) |
| Contol/media packet | tapo.device_stream_boundary | Device stream boundary |
| Contol/media packet | tapo.content_type | Content Type |
| Contol/media packet | tapo.content_length | Content Length |
| Contol/media packet | tapo.session_id | Session ID |
| Contol/media packet | tapo.encrypted | Payload encryption flag |
Ports UDP/20002 and UDP/20004 are used with configuration and cryptography-related information being sent.
For device discovery packets the header is 16 bytes long, fields of which are only partially identified as of now:
The fields are identified as follows:
- Byte 1-4: Signature of Discovery Message.
- Byte 5-6: Payload Length of Discovery Message.
- Byte 7-8: Unknown field 1.
- Byte 9-12: Unknown field 2.
- Byte 13-16: CRC32 cheksum.
Below is the header's representation in Wireshark:
More information about header structure of the tapo device discovery packet can be found on this Stack Overflow discussion thread.
Observed payloads include:
- Device configuration messages, some data encrypted with AES key:
{
"error_code": 0,
"result": {
"device_id": "REDACTED",
"device_name": "Tapo C100",
"device_type": "SMART.IPCAMERA",
"device_model": "C100",
"ip": "REDACTED",
"mac": "REDACTED",
"hardware_version": "4.0",
"firmware_version": "1.1.21 Build 220511 Rel.42882n(4555)",
"factory_default": false,
"mgt_encrypt_schm": {
"is_support_https": true
},
"encrypt_info": {
"sym_schm": "AES",
"key": "REDACTED",
"data": "REDACTED"
}
}
}- Public RSA key:
{
"params": {
"rsa_key": "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvzPNrLCSw3Rqf+AKwla2\\nntENZ+P4UUwGDzwvSc5HyJIYkY5+aQ8tpdQAO6NfN1JlVAUm94gxH5cw9s+xGgok\\nusbhFCHvMFp2g0CxvFg1P225+fq8Hmqqm9JN/ZkL2qwR4to6yvn256IqUxzmwKi8\\nFiX60VmAkmeJDOy8XGcN8ch385T9/sX1KyKZNxzX4z5xJEOlwcr5ZdhUeOmB6dbF\\njFF8GliOKSZdE01GVgeZPqJA21/8EQa1yJy8v31o+NNRd3QJaWjIzFqjGs1sl+Zj\\niPggKWcR/LqGt8Dd031velv2gVgmyBIjqi779cxns8IA5zYsvJbkxm0pFr3CU3GZ\\nYQIDAQAB\\n-----END PUBLIC
KEY-----\\n"
}
}A proprietary protocol that manages JSON control messages and encrypted media (audio + video) streams runs on port TCP/8800.
Header is formed from the first 28 bytes of a control and media packet. Fields are text based rather that byte-based:
| Field Name | Description |
|---|---|
| ----device-stream-boundary-- | Every control/media packet starts with this text as a start boundary |
| Content-Type: <type> | application/json for JSON payloads and video/mp2t for video stream |
| Content-Length: <length> | Length of a single message |
| X-Session-Id: <id> | ID of a current session |
| X-If-Encrypt: <bool> | Payload encryption flag; 0 - unencrypted, 1 - encrypted |
Payloads of this protocol include JSON-formatted stream information and encrypted video stream with a type of mp2t.
- Request of video stream:
{
"params": {
"preview": {
"audio": [
"default"
],
"audio_config": {
"encode_type": "G711alaw",
"sample_rate": "8"
},
"channels": [
0
],
"deviceId": "REDACTED",
"resolutions": [
"HD"
],
"track_id": "REDACTED"
},
"method": "get"
},
"seq": 1,
"type": "request"
}- Response on success:
{
"type": "response",
"seq": 1,
"params": {
"error_code": 0,
"session_id": "1"
}
}- Channel lens mask info:
{
"type": "notification",
"params": {
"event_type": "channel_lens_mask_info",
"channels": 0,
"enabled": "off"
}
}- Channel resolution info:
{
"type": "notification",
"params": {
"event_type": "channel_resolution_info",
"channels": 0,
"resolution": "1280*720"
}
}
