Skip to content

Fix 5 protocol 3.5 (6699) packet bugs causing v3.5 devices to stay unavailable#1

Open
aimaaaimaa wants to merge 1 commit into
ClermontDigital:mainfrom
aimaaaimaa:fix/protocol-3-5-packet-bugs
Open

Fix 5 protocol 3.5 (6699) packet bugs causing v3.5 devices to stay unavailable#1
aimaaaimaa wants to merge 1 commit into
ClermontDigital:mainfrom
aimaaaimaa:fix/protocol-3-5-packet-bugs

Conversation

@aimaaaimaa

Copy link
Copy Markdown

Summary

This fixes 5 bugs in the 6699 protocol implementation that prevented protocol 3.5 devices from ever connecting. Tested against a Mirabella Genio A60 RGB bulb.

Bug 1 — pack_message_6699: length field too large

The length field included the 4-byte trailing suffix (+4), making it 48 instead of 44. Since the length field is part of the GCM AAD, a wrong value produces a wrong GCM tag — the device silently rejects SESS_KEY_NEG_START and never responds. Fix: remove +4 from the length calculation.

Bug 2 — unpack_message_6699: wrong payload_end

payload_end was calculated as header_len + header.length - 4, cutting 4 bytes short, placing ciphertext/tag boundaries incorrectly and causing GCM decryption to fail on all device responses. Fix: payload_end = header_len + header.length (suffix lives outside plen).

Bug 3 — unpack_message_6699 + add_data: buffer handling missing +4

The data-length check and buffer-advance in the 6699 branch of add_data did not account for the 4-byte trailing suffix outside the plen region. Fix: +4 on both the length check and buffer advance.

Bug 4 — unpack_message_6699: 4-byte retcode not stripped from responses

All responses from v3.5 devices include a 4-byte return code at the start of the GCM-encrypted payload (0x00000000 = success), matching the 55AA convention. This was not stripped, so:

  • _negotiate_session_key used the wrong nonce → wrong session key derived
  • DP_QUERY responses started with \x00\x00\x00\x00 → JSON parsing failed

Fix: strip the 4-byte retcode from the decrypted payload and surface it in the TuyaMessage retcode field, consistent with how unpack_message (55AA) handles retcodes.

How it was diagnosed

  • Enabled HA debug logging via REST API (logger/set_level)
  • Compared raw packet bytes from a working tinytuya probe vs ProperGoodTuya — found the length field discrepancy (44 vs 48)
  • Raw TCP test scripts against the device to confirm each fix worked before applying to HA

Test plan

  • v3.5 device connects and shows valid state in HA
  • Session key negotiation completes without HMAC check failure
  • DP_QUERY response decrypts and JSON-parses correctly
  • Existing v3.3/v3.4 devices unaffected (the 55AA unpack_message path is unchanged)

🤖 Generated with Claude Code

…able

Tested against a Mirabella Genio A60 RGB bulb (bf5a70c8c88945ac62lhk1).
Before these fixes the device never connected; after it connects and
reports status correctly.

Bug 1 — pack_message_6699: length field incorrectly included the 4-byte
trailing suffix (+4), making it 48 instead of 44. The length field is
part of the GCM AAD; a wrong value produces a wrong GCM tag, so the
device silently rejects SESS_KEY_NEG_START and never responds.
Fix: remove the +4 from the length calculation.

Bug 2 — unpack_message_6699: payload_end was calculated as
header_len + header.length - 4, cutting 4 bytes short and placing the
ciphertext/tag boundaries incorrectly, causing GCM decryption to fail
on all device responses.
Fix: payload_end = header_len + header.length (suffix is outside plen).

Bug 3 — unpack_message_6699 + add_data: the data-length check and
buffer-advance in the 6699 branch of add_data did not account for the
4-byte trailing suffix that sits outside the plen-bounded region.
Fix: +4 on both the length check and the buffer advance.

Bug 4 (retcode) — unpack_message_6699: all responses from v3.5 devices
include a 4-byte return code at the start of the GCM-encrypted payload
(0x00000000 = success), matching the 55AA convention. This was not
stripped, so _negotiate_session_key used the wrong nonce (deriving a
wrong session key) and DP_QUERY responses started with \x00\x00\x00\x00
causing JSON parsing to fail.
Fix: strip the 4-byte retcode from decrypted payload and surface it in
the TuyaMessage retcode field, consistent with unpack_message (55AA).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant