ZigBee
# This is the "well-known" zigbee2mqtt key
# The ikea key is not known, might be per gateway
nwk_key = b"\x01\x03\x05\x07\x09\x0b\x0d\x0f\x00\x02\x04\x06\x08\x0a\x0c\x0d"
IEEE 802.15.4 header
| 2 | Frame Control Field
2:0 frame type 0 = beacon, 1 = data, 2 = ack, 3 = cmd
6 pan compression
11:10 dest mode
13:12 src mode
| 1 | Sequence
| 2? | Destination PAN
| 2? | Destination short address
| 8? | Destination long address
| 2? | Source PAN
| 2? | Source short address
| 8? | Source long address
| ? | Payload
Command Packet
| 1 | Type 4 = data request, 7 = beacon request
Data Packet
| 2 | Frame Control Field
1:0 type 0 = data, 1 = command, 2 = rerved, 3 = inter-pan
9 security
11 extended destination present
12 extended source present
| 2 | Destination
| 2 | Source
| 1 | Radius
| 1 | Sequence
| 8? | Extended destination
| 8? | Extended source (if not present, use the one in the outer header?)
| 6-18? | Security header
| ? | Payload (encrypted if security header is present)
| 4? | Encrypted Message Integrity Code (MIC if the security header is present)
Security header
| 1 | Security Control Field (this is often not right?)
5 extended nonce (means the source is in the header)
| 4 | Sequence Number
| 8? | Source address (if extended nonce is set)
| 1 | Key sequence (always 0?)
Payload and MIC decryption:
key = keyring[key_seq](key_seq)
K = [ 1, src_addr[0:8](0:8), sequence[0:4](0:4), 0, 0 ]
mic = AES(key, K) ^ EncryptedMIC[0:4](0:4)
for i range(0, payload_len, 16):
K[15](15) += 1
message[i:i+16](i:i+16) = AES(key, K) ^ payload[i:i+16](i:i+16)
Message integrity validation:
CCM\* is messy.
```
K = [ 1, src_addr[0:8](0:8), sequence[0:4](0:4), 0, 0 ]
auth_data = data_packet[0:key_sequence](0:key_sequence)
l_a = len(auth_data)
auth_data = [ l_a >> 8, l_a >> 0, auth_data, padding to 16 bytes ]
b0 = [ ?, src_addr[0:8](0:8), sequence[0:4](0:4), l, l_m >> 8, l_m >> 0 ]
X = AES(key, b0)
for i in range(0, l_a, 16):
X ^= AES(Key, auth_data[i:i+16](i:i+16))
for i in range(0, l_m, 16):
X ^= AES(Key, message[i:i+16](i:i+16))
if X[0:4](0:4) == mic[0:4](0:4):
# hurrah!