66 lines
1.7 KiB
Python
Executable File
66 lines
1.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# encoding: utf-8
|
|
"""
|
|
multicast.py
|
|
Created by kueblc on 2019-01-25.
|
|
Encode data for Tuya smartconfig via multicast
|
|
multicast strategy reverse engineered by kueblc
|
|
"""
|
|
|
|
from crc import crc_32
|
|
|
|
from Crypto.Cipher import AES
|
|
pad = lambda data, block_size : data + ('\0' * ( (block_size - len(data)) % block_size ) )
|
|
aes = AES.new( b'a3c6794oiu876t54', AES.MODE_ECB )
|
|
encrypt = lambda data : aes.encrypt( pad(data, 16).encode() )
|
|
|
|
def encode_pw( pw ):
|
|
r = []
|
|
pw_bytes = [ ord(c) for c in pw ]
|
|
encrypted_pw = encrypt(pw)
|
|
# CRC and length are from plaintext
|
|
crc = crc_32(pw_bytes)
|
|
# length, twice
|
|
r.append( len(pw) )
|
|
r.append( len(pw) )
|
|
# encode CRC as LE
|
|
r.extend([ (crc >> i) & 255 for i in range(0,32,8) ])
|
|
# payload, AES encrypted
|
|
r.extend( encrypted_pw )
|
|
return r
|
|
|
|
def encode_plain( s ):
|
|
r = []
|
|
s_bytes = [ ord(c) for c in s ]
|
|
crc = crc_32(s_bytes)
|
|
# length, twice
|
|
r.append( len(s) )
|
|
r.append( len(s) )
|
|
# encode CRC as LE
|
|
r.extend([ (crc >> i) & 255 for i in range(0,32,8) ])
|
|
# payload, plaintext
|
|
r.extend( s_bytes )
|
|
return r
|
|
|
|
def bytes_to_ips( data, sequence ):
|
|
r = []
|
|
if len(data) & 1:
|
|
data.append(0)
|
|
for i in range(0, len(data), 2):
|
|
r.append( "226." + str(sequence) + "." + str(data[i+1]) + "." + str(data[i]) )
|
|
sequence += 1
|
|
return r
|
|
|
|
multicast_head = bytes_to_ips([ ord(c) for c in "TYST01" ], 120)
|
|
|
|
def encode_multicast_body( password, ssid, token_group ):
|
|
r = []
|
|
ssid_encoded = encode_plain(ssid)
|
|
r.extend( bytes_to_ips( ssid_encoded, 64 ) )
|
|
password_encoded = encode_pw(password)
|
|
r.extend( bytes_to_ips( password_encoded, 0 ) )
|
|
token_group_encoded = encode_plain(token_group)
|
|
r.extend( bytes_to_ips( token_group_encoded, 32 ) )
|
|
return r
|
|
|