Skip to content

Commit

Permalink
ver 3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
pvvx committed May 24, 2021
1 parent e83919e commit 0b9e26d
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 4 deletions.
Binary file removed ATC_Thermometer30.bin
Binary file not shown.
Binary file added ATC_Thermometer32.bin
Binary file not shown.
Binary file removed CGG1_v30.bin
Binary file not shown.
Binary file added CGG1_v32.bin
Binary file not shown.
2 changes: 1 addition & 1 deletion InfoMijiaBLE/Mijia BLE MiBeacon protocol v5.md
Expand Up @@ -52,7 +52,7 @@ In order to facilitate users to quickly discover and establish a connection with
| 6 | Object Include | 0: does not contain Object; 1: contains Object |
| 7 | Mesh | 0: does not include Mesh; 1: includes Mesh. For standard BLE access products and high security level access, this item is mandatory to 0. This item is mandatory for Mesh access to 1. For more information about Mesh access, please refer to Mesh related documents |
| 8 | registered | 0: The device is not bound; 1: The device is registered and bound. This item is used to indicate whether the device is reset |
| 8 | solicited | 0: No operation; 1: Request APP to register and bind. It is only valid when the user confirms the pairing by selecting the device on the developer platform, otherwise set to 0. The original name of this item was bindingCfm, and it was renamed to solicited "actively request, solicit" APP for registration and binding |
| 9 | solicited | 0: No operation; 1: Request APP to register and bind. It is only valid when the user confirms the pairing by selecting the device on the developer platform, otherwise set to 0. The original name of this item was bindingCfm, and it was renamed to solicited "actively request, solicit" APP for registration and binding |
| 10 ~ 11 | Auth Mode | 0: old version certification; 1: safety certification; 2: standard certification; 3: reserved |
| 12 ~ 15 | version | Version number (currently v5) |

Expand Down
Binary file removed MHO_C401_v30.bin
Binary file not shown.
Binary file added MHO_C401_v32.bin
Binary file not shown.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -137,7 +137,8 @@ In case you want to go back to the original firmware, you can download them here
| 2.8 | Added saving bindkey to EEP if mi-keys are erased, reduced TX power to 0 dB for defaults
| 2.9 | Added additional id flags to advertising packages
| 3.0 | Added toggle support for advertising package structures for third-party software
| 3.1 | Fix security attributes for pincode
| 3.1 | Fix security attributes (for pincode)
| 3.2 | Added new encrypted beacon formats, reed switch maintenance.


## Applications
Expand Down
4 changes: 2 additions & 2 deletions firmware.json
@@ -1,3 +1,3 @@
{"version": 49,
"custom":["ATC_Thermometer31.bin", "MHO_C401_v31.bin", "CGG1_v31.bin"],
{"version": 50,
"custom":["ATC_Thermometer32.bin", "MHO_C401_v32.bin", "CGG1_v32.bin"],
"original":["Original_OTA_Xiaomi_LYWSD03MMC_v1.0.0_0109.bin","Original_OTA_Xiaomi_MHO_C401_v1.0.0_0010.bin","Original_OTA_CGG1_v1.0.1_0093.bin"]}
114 changes: 114 additions & 0 deletions test_adv_cust.py
@@ -0,0 +1,114 @@
import asyncio
import struct
import binascii
from Crypto.Cipher import AES

def parse_value(hexvalue):
vlength = len(hexvalue)
# print("vlength:", vlength, "hexvalue", hexvalue.hex(), "typecode", typecode)
if vlength == 3:
temp = hexvalue[0]/2 - 40
humi = hexvalue[1]/2
batt = hexvalue[2] & 0x7F
trg = hexvalue[2] >> 7
print("Temperature:", temp, "Humidity:", humi, "Battery:", batt, "Trg:", trg)
return 1
if vlength == 6:
(temp, humi, batt, trg) = struct.unpack("<hHBB", hexvalue)
print("Temperature:", temp/100, "Humidity:", humi/100, "Battery:", batt, "Trg:", trg)
return 1
print("MsgLength:", vlength, "HexValue:", hexvalue.hex())
return None

def decrypt_payload(payload, key, nonce):
token = payload[-4:] # mic
cipherpayload = payload[:-4] # EncodeData
print("Nonce: %s" % nonce.hex())
print("CryptData: %s" % cipherpayload.hex(), "Mic: %s" % token.hex())
cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=4)
cipher.update(b"\x11")
data = None
try:
data = cipher.decrypt_and_verify(cipherpayload, token)
except ValueError as error:
print("Decryption failed: %s" % error)
return None
print("DecryptData:", data.hex())
print()
if parse_value(data) != None:
return 1
print('??')
return None

def decrypt_aes_ccm(key, mac, data):
print("MAC:", mac.hex(), "Binkey:", key.hex())
print()
adslength = len(data)
if adslength > 8 and data[0] <= adslength and data[0] > 7 and data[1] == 0x16 and data[2] == 0x1a and data[3] == 0x18:
pkt = data[:data[0]+1]
# nonce: mac[6] + head[4] + cnt[1]
nonce = b"".join([mac, pkt[:5]])
return decrypt_payload(pkt[5:], key, nonce)
else:
print("Error: format packet!")
return None

#=============================
# main()
#=============================
def main():
print()
temp = 22.53
humi = 50.12
batt = 99
trg = 135
print("Temperature:", temp, "Humidity:", humi, "Battery:", batt, "Trg:", trg)
print()

mac = binascii.unhexlify('ed5e0b38c1a4') # MAC
binkey = binascii.unhexlify('12345678901234567890123456789012')
print("MAC:", mac.hex(), "Binkey:", binkey.hex())
print()

print("====== Test1 ATC encode ----------------------------------------")

data = struct.pack("<BBB", int((temp + 40)*2), int(humi*2), batt + (trg&2 << 6))
adshead = struct.pack(">BBHB", len(data) + 8, 0x16, 0x1a18, 0xbd) # ad struct head: len, id, uuid16, cnt
beacon_nonce = b"".join([mac, adshead])
cipher = AES.new(binkey, AES.MODE_CCM, nonce=beacon_nonce, mac_len=4)
cipher.update(b"\x11")
ciphertext, mic = cipher.encrypt_and_digest(data)
print("Data:", data.hex())
print("Nonce:", beacon_nonce.hex())
print("CryptData:", ciphertext.hex(), "Mic:", mic.hex())
adstruct = b"".join([adshead, ciphertext, mic])
print()
print("AdStruct:", adstruct.hex())
print()
print("====== Test1 ATC decode ----------------------------------------")
decrypt_aes_ccm(binkey, mac, adstruct);

print()
print("====== Test2 PVVX encode ----------------------------------------")
data = struct.pack("<hHBB", int(temp*100), int(humi*100), batt, trg)
adshead = struct.pack(">BBHB", len(data) + 8, 0x16, 0x1a18, 0xbd) # ad struct head: len, id, uuid16, cnt
beacon_nonce = b"".join([mac, adshead])
cipher = AES.new(binkey, AES.MODE_CCM, nonce=beacon_nonce, mac_len=4)
cipher.update(b"\x11")
ciphertext, mic = cipher.encrypt_and_digest(data)
print("Data:", data.hex())
print("Nonce:", beacon_nonce.hex())
print("CryptData:", ciphertext.hex(), "Mic:", mic.hex())
adstruct = b"".join([adshead, ciphertext, mic])
print()
print("AdStruct:", adstruct.hex())
print()
print("====== Test2 PVVX decode ----------------------------------------")
#mac = binascii.unhexlify('a4c1380b5eed')
#adstruct = binascii.unhexlify('0e161a1821a3dbe71940006994b078')
print("AdStruct:", adstruct.hex())
decrypt_aes_ccm(binkey, mac, adstruct);


if __name__ == '__main__':
main()

0 comments on commit 0b9e26d

Please sign in to comment.