-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BLE Protocol Reverse Engineering #1
Comments
BLEScanner Connection Data
|
When looking at the names of the services, the name "authentication" is noticeable. Hopefully the dimmer has not to be activated by using some cryptographic keys. Due to the fact that the device is very cheap, it might be a very weak authentication. Maybe a look on other Xiaomi reverse engineering projects might help. I found a project about the Mijia temperature sensor. I'm not sure if this sensor has some authentication implemented: https://github.com/mspider65/Xiaomi-Mijia-Bluetooth-Temperature-and-Humidity-Sensor But there is a demo project for the Mijia (from a chinese guy), which implements some authentication: https://github.com/MiEcosystem/mijia_ble |
thank you @saeugetier for the assistance @0xabadc0fe 你能在这里协助吗? 谢谢 |
I'm interested in the encoder as well. So I ordered a sample as well. The microcontroller might have an external flash which hides some secrets. An interesting article about how to reverse BLE can be found here. |
there isn't any external flash inside, just one BLE module (TLSR8267 controller). All those article have one thing in common which is, (Device) <----> (Mi Home App), hence one can snoop BLE packets using developer mode settings in an Android phone but with this dimmer/encoder the command is sent to ceiling light and not to the app hence snooping is difficult. Here's the link to the image that details how communication happens. I'm stuck as I don't have the ceiling light to verify the same. The only way I can think getting around this is to emulate esp32 as a rotary encoder by advertising the same characteristics and inspect packets sent to it. Authentication happens just once when the dimmer is paired to the light. At this time all 3 devices are required - Mi Home App, Dimmer & Light |
I've been able to authenticate to the dimmer (I think) using a ESP32 and a ported version of the authentication logic from here: https://github.com/aprosvetova/xiaomi-kettle Could you post a log showing what happens after the authentication is done, with some commands going from the dimmer? If you could also upload the pcap-log that would be nice. (I suppose the log is from BtleJack?) |
sorry @nikko82 I haven't been able to take out time for this, thank you very much for your input. will give it a shot when time permits. The previous logs were shared by @matthias-schulz so can't comment on it. |
I found out, thanks to https://github.com/drndos/mi-kettle-poc/blob/master/mi-kettle.py that the last thing that is send to authCharacteristic must be calculated with cipher(token, [0x92, 0xAB, 0x54, 0xFA]). I've found the product key both by automating a brute force attack where I tried all keys until authentication was successful and also by reversing the cipher algorithm and brute forcing based on the data in the log from @matthias-schulz. Both ways gave the productId of 950. Using that productId and the token i found from the response I was able to calculate the same authentication values that was sent by the lamp in the log. This makes me very confident that all the data I'm sending to the dimmer is correct. But still I can't figure out how to subscribe to commands from the dimmer. |
@nikko82 sounds good. I wish you good luck. As soon as my device arrives, I will take a look, if i can help with reversing. |
@saeugetier do you have a micro:bit or any other equipment that you can use to sniff the traffic? |
@nikko82 I think I have several devices which can be used for sniffing. But I don't have a Yeelight light. I only own the dimmer. |
For your information: currently I'm working on an esp32 implementation of the dimmer knob. It is not fully working for now. But you can stay tuned: https://github.com/saeugetier/LowPowerDimmerKnop Reversing the protocoll doesn't seem easy. Building an own firmware seems to be the way with less effort. But the hardware has to be modified. The new implementation will use wifi and mqtt. Current state: the rotary encoder and push button are evaluated via ULP. Next step is to remove all debug variables and write the wifi code. Very next step: enable OTA and wifi setting dialog via button on top. |
Any progress here? My guess is that It sends command thru BLE adv data. Here is the data i got
My read: Command SN is increased by 1 and goes to 0 after 0xff. |
More log for clockwise rotation:
|
Update sorry, I haven't got the time to work on this, I also have ordered corresponding light which may help in reverse engineering, but I haven't received it yet .. will try extracting time .. thank you all for the help |
MORE INFO:
Digged into mi ble code: Hold the small button on the top for 3 seconds, and connect, there is a BLE Char described as "beaconkey", and can read out 12bytes content. I think it should be part of AES key. (which changes every connection, explains how "bonding").
|
@syu-source as @Staars mensioned, there is a strange repo with no description and some code around mibeacon protocol with ccm_auth_crypt aes_ccm_encrypt_and_tag inside. https://github.com/MiEcosystem/mijia_ble_common May be it will help you |
Yes, i am using code from this repo. |
Maybe this can help?: https://medium.com/@yogeshojha/i-hacked-xiaomi-miband-3-and-here-is-how-i-did-it-43d68c272391 I just got a Yeelight dimmer switch too, I'd love to use it as-is without replacing the BLE platform it uses! |
@nikko82 do you have a proof of concept for authentication? Trying to see if I can adapt the mi-kettle code you linked but I'm not that familiar with BLE. Not sure what handle to use for EDIT: I believe I've authenticated, using @syu-source how did you capture the data from the advertise packet? |
@syu-source I've reached pretty much the same conclusion as you here, except what concerns me is that the "encrypted obj" is a very strange length for it to be AES128. I would expect it to match the block size of 128 bits / 16 bytes. What could you do with 6 bytes? The product ID makes total sense, if we take |
I didn't look into details but, these tow functions take any length of data, and as I tested, they work with 6 bytes.
pi equals to pt. |
@syu-source I found this document which shows it is legal to have a 1-byte MIC. |
@0xabadc0fe seems like a Xiaomi employee since his email address ends with xiaomi.com and he will not provide us with any help obviously. |
Hello, |
Works. posted results here custom-components/ble_monitor#353 (comment) |
Script to get the beaconkey is added in the BLE monitor documentation (including updated script for more devices). |
Confirming total success. Got encryption key using get_beacon_key, installed HomeAssistant with https://github.com/custom-components/ble_monitor and cofigured device using key. It works. |
@Ernst79 could you elaborate on how the BLE Monitor works for the YLKG08YL dimmer? How should the data on https://github.com/archaron/docs/blob/master/BLE/ylkg08y.md be combined into decoding a message, say: with the beaconkey: 10 d8 99 8c 8e cd 72 9d e4 21 02 8d From what I gather from xiaomi.py: Is (any of) that correct? Many thanks in advance! |
@wouterf11 beaconkey is encrypted in this example (was not decrypted with token). use this sample data for dimmer to check your code. |
Here is a little python script that shows the decryption. from Cryptodome.Cipher import AES
data_string = "043e25020103008b98c54124f819181695fe5830b603368b98c54124f88bb8f2661351000000d6ef"
aeskey = "b853075158487ca39a5b5ea9"
# frame dev ct ---mac------ ----encrypted payload- rssi
# ctrl id cipherpayld- -cnt-- tk
# 043e25020103008b98c54124f819181695fe 5830 b603 36 8b98c54124f8 8bb8f2661351 000000 d6 ef
data = bytes(bytearray.fromhex(data_string))
key = bytes.fromhex(aeskey)
key_1 = key[0:6]
key_2 = bytes.fromhex("8d3d3c97")
key_3 = key[6:]
key = b"".join([key_1, key_2, key_3])
print("key: ", key.hex())
xiaomi_index = data.find(b'\x16\x95\xFE')
xiaomi_mac_reversed = data[xiaomi_index + 8:xiaomi_index + 14]
print("reversed mac: ", xiaomi_mac_reversed.hex())
# reversed mac: 8b98c54124f8
framectrl_data = data[xiaomi_index + 3:xiaomi_index + 5]
print("frame ctrl: ", framectrl_data.hex())
# frame ctrl: 5830
device_type = data[xiaomi_index + 5:xiaomi_index + 7]
print("device type (product id): ", device_type.hex())
# device type (product id): b603
encrypted_payload = data[xiaomi_index + 14:-1]
print("encrypted payload: ", encrypted_payload.hex())
# encrypted payload: 8bb8f2661351000000d6
packet_id = data[xiaomi_index + 7:xiaomi_index + 8]
payload_counter = b"".join([packet_id, encrypted_payload[-4:-1]])
print("payload counter: ", payload_counter.hex())
# payload_counter: 36000000
nonce = b"".join([framectrl_data, device_type, payload_counter, xiaomi_mac_reversed[:-1]])
print("nonce: ", nonce.hex())
# nonce: 5830b603360000008b98c54124
aad = b"\x11"
token = encrypted_payload[-1:]
print("token: ", token.hex())
# token: d6
cipherpayload = encrypted_payload[:-4]
print("cipher payload: ", cipherpayload.hex())
# cipher payload: 8bb8f2661351
cipher = AES.new(key, AES.MODE_CCM, nonce=nonce, mac_len=4)
cipher.update(aad)
decrypted_payload = cipher.decrypt(cipherpayload)
print("decrypted payload: ", decrypted_payload.hex())
# decrypted payload: 01100300ff04 The decrypted payload can be read as follows. button, value and press are the names I use in BLE monitor, depending on the device type, they are translated to a message. See the I also tried your BLE advertisement + beaconkey, but it doesn't seem to be right, I get this as result.
|
he used sample data from old github, where beaconkey was not decrypted using token.
|
Thanks a lot!! I will have a look. |
I successfully got dimmer beakonKey using method 6 from FAQ,
My configuration.yaml:
They seem to happen every time dimmer action is sent... |
Did you restart HA? |
Can you show the log from right after the start of HA? |
That's debug log enabled, of course.
|
Btw, i'm running on a RPI B4, Home Assistant OS 5.13 |
You have entered the MAC address reversed (per two characters in your config |
Script told me that mac address is
I double checked mac address in the config, it's the exact same. |
I got it! Thank you for your help and your amazing work, I've been following the YLKg08YL thread closely, it inspired me to create a proper home automation ✨ |
I will change the script to return the real MAC. I can understand its confusing. |
@Ernst79 mac is reversed in miio cmd response (method 6 he used). just bold in faq to reverse it during remote/dimmer setup in HA. afaik mac for dimmer/remote (not from bundle) always starts with F8:24:41. |
Ah, you’re right. I’ll highlight it in the FAQ |
I've made a full python code that pairs and reads Yeelight dimmer data. |
Also I'm glad to present ESP-IDF component that adds Yeelight YLKG08Y support to your ESP32 projects - yeelight-dimmer-esp32 |
Dose the xiaomihome app need the old version? the web url is cannot work,https://github.com/custom-components/ble_monitor/issues/353 ,could you share the xiaomihome app? thx |
@Busyrev Does any Xiaomi software show the battery value? |
No idea, I`m not using xiaomi software at all. |
https://stackoverflow.com/questions/70426330/decrypt-aes-128-ccm-on-nodejs-without-auth-tag reports that the As a result:
(Also, I don't think you should bother libraries to support a The C code with |
Inputs from @matthias-schulz
The text was updated successfully, but these errors were encountered: