nccchirag / yeelight-ble-rotary-dimmer

YLKG08YL Yeelight bluetooth dimmer rotary switch protocol (#TODO reverse engineer) and hardware details.
68 stars 2 forks source link

BLE Protocol Reverse Engineering #1

Open nccchirag opened 4 years ago

nccchirag commented 4 years ago

Inputs from @matthias-schulz

yee-rc detected as F8:24:41:C1:D1:1F (Yeelink) -67 dBm.

 │   Handles    │ Service > Characteristics │  Properties   │         Data         │
├──────────────┼───────────────────────────┼───────────────┼──────────────────────┤
│ 0001 -> 001a │ fe95                      │               │                      │
│ 0003         │     0001                  │ WRITE, NOTIFY │                      │
│ 0007         │     0002                  │ READ          │ 0000                 │
│ 000a         │     0004                  │ READ          │ O993yDåo8f04X        │
│ 000d         │     0005                  │ WRITE, NOTIFY │                      │
│ 0010         │     0007                  │ WRITE         │                      │
│ 0013         │     0010                  │ WRITE         │                      │
│ 0016         │     0013                  │ READ, WRITE   │ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ │
│ 0019         │     0014                  │ READ, WRITE   │ L8e"ëad<01cúýéû 

LL Data: 05 22 ea 7f 8e f9 d1 c2 e0 ab df 41 24 f8 bb 3d e9 b1 d9 16 42 08 06 00 43 00 00 00 d0 07 ff ff ff ff 1f 10
[i] Got CONNECT_REQ packet from c2:d1:f9:8e:7f:ea to f8:24:41:df:ab:e0
 |-- Access Address: 0xb1e93dbb
 |-- CRC Init value: 0x4216d9
 |-- Hop interval: 67
 |-- Hop increment: 16
 |-- Channel Map: 1fffffffff
 |-- Timeout: 20000 ms

LL Data: 13 09 08 e1 00 00 00 00 00 00 00
LL Data: 0b 09 09 01 00 00 00 00 00 00 00
LL Data: 06 10 0c 00 05 00 12 01 08 00 10 00 20 00 00 00 c8 00
LL Data: 0a 0c 08 00 04 00 11 06 01 00 1a 00 95 fe
LL Data: 13 0c 00 08 06 00 24 00 00 00 c8 00 08 00
LL Data: 1e 0a 06 00 05 00 13 01 02 00 00 00
LL Data: 12 0b 07 00 04 00 10 1b 00 ff ff 00 28
LL Data: 0a 09 05 00 04 00 01 10 1b 00 00
LL Data: 12 0d 09 00 04 00 06 01 00 ff ff 00 28 95 fe
LL Data: 0a 09 05 00 04 00 07 01 00 1a 00
LL Data: 12 0d 09 00 04 00 06 1b 00 ff ff 00 28 95 fe
LL Data: 0a 09 05 00 04 00 01 06 1b 00 0a
LL Data: 12 0b 07 00 04 00 08 01 00 1a 00 02 28
LL Data: 0a 09 05 00 04 00 01 08 01 00 00
LL Data: 12 0b 07 00 04 00 08 01 00 1a 00 03 28
LL Data: 06 1b 17 00 04 00 09 07 02 00 18 03 00 01 00 06 00 02 07 00 02 00 09 00 02 0a 00 04 00
LL Data: 1e 0b 07 00 04 00 08 0b 00 1a 00 03 28
LL Data: 06 1b 17 00 04 00 09 07 0c 00 18 0d 00 05 00 0f 00 08 10 00 07 00 12 00 08 13 00 10 00

LL Data: 05 22 08 e4 ad a2 ac c8 1f d1 c1 41 24 f8 60 58 ac 0b 72 86 a0 08 06 00 43 00 00 00 d0 07 ff ff ff ff 1f 10
[i] Got CONNECT_REQ packet from c8:ac:a2:ad:e4:08 to f8:24:41:c1:d1:1f
 |-- Access Address: 0x0bac5860
 |-- CRC Init value: 0xa08672
 |-- Hop interval: 67
 |-- Hop increment: 16
 |-- Channel Map: 1fffffffff
 |-- Timeout: 20000 ms

LL Data: 13 09 08 e1 00 00 00 00 00 00 00
LL Data: 0b 09 09 01 00 00 00 00 00 00 00
LL Data: 12 0b 07 00 04 00 10 01 00 ff ff 00 28
LL Data: 0a 0c 08 00 04 00 11 06 01 00 1a 00 95 fe
LL Data: 13 0c 00 08 06 00 24 00 00 00 c8 00 08 00
LL Data: 1e 0a 06 00 05 00 13 01 02 00 00 00
LL Data: 12 0b 07 00 04 00 10 1b 00 ff ff 00 28
LL Data: 0a 09 05 00 04 00 01 10 1b 00 00
LL Data: 12 0d 09 00 04 00 06 01 00 ff ff 00 28 95 fe
LL Data: 12 0d 09 00 04 00 06 1b 00 ff ff 00 28 95 fe
LL Data: 0a 09 05 00 04 00 01 06 1b 00 0a
LL Data: 12 0b 07 00 04 00 08 01 00 1a 00 02 28
LL Data: 0a 09 05 00 04 00 01 08 01 00 00
LL Data: 12 0b 07 00 04 00 08 01 00 1a 00 03 28
LL Data: 0a 1b 17 00 04 00 09 07 02 00 18 03 00 01 00 06 00 02 07 00 02 00 09 00 02 0a 00 04 00
LL Data: 12 0b 07 00 04 00 08 0b 00 1a 00 03 28
LL Data: 0a 1b 17 00 04 00 09 07 0c 00 18 0d 00 05 00 0f 00 08 10 00 07 00 12 00 08 13 00 10 00

LL Data: 05 22 40 9f ce 64 21 c3 a3 d5 c1 41 24 f8 12 8c e2 7b eb 6e 0f 08 06 00 43 00 00 00 d0 07 ff ff ff ff 1f 05
[i] Got CONNECT_REQ packet from c3:21:64:ce:9f:40 to f8:24:41:c1:d5:a3
 |-- Access Address: 0x7be28c12
 |-- CRC Init value: 0x0f6eeb
 |-- Hop interval: 67
 |-- Hop increment: 5
 |-- Channel Map: 1fffffffff
 |-- Timeout: 20000 ms

LL Data: 13 09 08 e1 00 00 00 00 00 00 00
LL Data: 0b 09 09 01 00 00 00 00 00 00 00
LL Data: 12 0b 07 00 04 00 10 01 00 ff ff 00 28
LL Data: 0a 0c 08 00 04 00 11 06 01 00 1a 00 95 fe
LL Data: 0a 09 05 00 04 00 01 10 1b 00 00
LL Data: 12 0d 09 00 04 00 06 01 00 ff ff 00 28 95 fe
LL Data: 0a 09 05 00 04 00 07 01 00 1a 00
LL Data: 12 0d 09 00 04 00 06 1b 00 ff ff 00 28 95 fe
LL Data: 0a 09 05 00 04 00 01 06 1b 00 0a
LL Data: 12 0b 07 00 04 00 08 01 00 1a 00 02 28
LL Data: 0a 09 05 00 04 00 01 08 01 00 00
LL Data: 0a 1b 17 00 04 00 09 07 02 00 18 03 00 01 00 06 00 02 07 00 02 00 09 00 02 0a 00 04 00
LL Data: 12 0b 07 00 04 00 08 0b 00 1a 00 03 28
LL Data: 0a 1b 17 00 04 00 09 07 0c 00 18 0d 00 05 00 0f 00 08 10 00 07 00 12 00 08 13 00 10 00
LL Data: 12 0b 07 00 04 00 08 14 00 1a 00 03 28
LL Data: 0a 14 10 00 04 00 09 07 15 00 0a 16 00 13 00 18 00 0a 19 00 14 00
LL Data: 12 09 05 00 04 00 04 04 00 05 00
LL Data: 0a 0e 0a 00 04 00 05 01 04 00 02 29 05 00 01 29
LL Data: 12 09 05 00 04 00 04 08 00 08 00
LL Data: 0a 0a 06 00 04 00 05 01 08 00 01 29
LL Data: 12 09 05 00 04 00 04 0b 00 0b 00
LL Data: 0a 0a 06 00 04 00 05 01 0b 00 01 29
LL Data: 0a 0a 06 00 04 00 05 01 0e 00 01 29
LL Data: 0a 0a 06 00 04 00 05 01 11 00 01 29
LL Data: 12 09 05 00 04 00 04 14 00 14 00
LL Data: 0a 0a 06 00 04 00 05 01 14 00 01 29
LL Data: 12 09 05 00 04 00 04 17 00 17 00
LL Data: 0a 0a 06 00 04 00 05 01 17 00 01 29
LL Data: 12 09 05 00 04 00 04 1a 00 1a 00
LL Data: 0a 0a 06 00 04 00 05 01 1a 00 01 29
LL Data: 12 0b 07 00 04 00 12 13 00 90 ca 85 de
LL Data: 0a 05 01 00 04 00 13
LL Data: 12 09 05 00 04 00 12 04 00 01 00
LL Data: 0a 05 01 00 04 00 13
LL Data: 12 13 0f 00 04 00 12 03 00 8c d1 cf 62 43 fb b1 d3 f8 2a f2 b9
LL Data: 1a 05 01 00 04 00 13
LL Data: 06 13 0f 00 04 00 1b 03 00 5e 6a 72 c9 52 b1 95 a9 2c 0f 1f 51
LL Data: 1e 0b 07 00 04 00 12 03 00 99 7b 30 c5
LL Data: 06 05 01 00 04 00 13
LL Data: 1e 07 03 00 04 00 0a 19 00
LL Data: 06 11 0d 00 04 00 0b 4c 0a 2a 21 a8 c9 4a 69 63 4c e7 31
LL Data: 1f 02 02 13
nccchirag commented 4 years ago

BLEScanner Connection Data

Custom Service
0000FE95-0000-1000-8000-00805F9B34FB
    Custom Characteristic
        UUID: 00000001-0000-1000-8000-00805F9B34FB
        Properties: WRITE,NOTIFY
        Write Type:WRITE REQUEST

        Descriptors:
        Client Characteristic Configuration
        UUID: 0x2902
        Notifications or indications disabled
        Characteristic User Description
        UUID: 0x2901
        token
    Custom Characteristic
        UUID: 00000002-0000-1000-8000-00805F9B34FB
        Properties: READ
        Value:
        Hex: 0x0000

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        productid
    Custom Characteristic
        UUID: 00000004-0000-1000-8000-00805F9B34FB
        Properties: READ
        Value:\ ?
        A *
        Hex: 0x5C0B1F0A410C2AB0394B

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        ver
    Custom Characteristic
        UUID: 00000005-0000-1000-8000-00805F9B34FB
        Properties: WRITE,NOTIFY
        Write Type:WRITE REQUEST

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        wificfg
    Custom Characteristic
        UUID: 00000007-0000-1000-8000-00805F9B34FB
        Properties: WRITE
        Write Type:WRITE REQUEST

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        eventrule
    Custom Characteristic
        UUID: 00000010-0000-1000-8000-00805F9B34FB
        Properties: WRITE
        Write Type:WRITE REQUEST

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        authentication
    Custom Characteristic
        UUID: 00000013-0000-1000-8000-00805F9B34FB
        Properties: READ,WRITE
        Write Type:WRITE REQUEST

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        sn
    Custom Characteristic
        UUID: 00000014-0000-1000-8000-00805F9B34FB
        Properties: READ,WRITE
        Write Type:WRITE REQUEST

        Descriptors:
        Characteristic User Description
        UUID: 0x2901
        beaconkey
saeugetier commented 4 years ago

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

nccchirag commented 4 years ago

thank you @saeugetier for the assistance yes, it seems authentication might be weak and the dimmer supports mi Home app so, mostly it would be implementing the same authentication as the one mentioned in the link you shared. Let me have a look

@0xabadc0fe 你能在这里协助吗? 谢谢

saeugetier commented 4 years ago

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. https://medium.com/@yogeshojha/i-hacked-xiaomi-miband-3-and-here-is-how-i-did-it-43d68c272391 Maybe the authentication process is the same as for the Mi Band 3. The IOT gadgets and the fitness tracker are developed by different teams, but with some luck it might be the same.

nccchirag commented 4 years ago

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 Check this operation demo. During the demo the phone Bluetooth seems Off (unless he has hide that icon from status bar, which is rare). The dimmer is enumerated in the app via the ceiling light (which has both BLE & Wifi), and I think the pairing process is complete before that

nikko82 commented 4 years ago

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 The productId seems to be 950. I'm stuck at what to do after authenticating. I've tried to write 0x92, 0xAB, 0x54, 0xFA to authCharacteristic, and writing 0x99, 0x7b, 0x30, 0xc5 instead which is what I can see from your log in the first post. I then read verCharacteristics (UUID 0004), or UUID 0014 which it seems like is read in the log. I've then tried to update the list of characteristics, but it doesn't change (maybe I need to run some command to update it?).

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?)

nccchirag commented 4 years ago

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.

nikko82 commented 4 years ago

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.

saeugetier commented 4 years ago

@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.

nikko82 commented 4 years ago

@saeugetier do you have a micro:bit or any other equipment that you can use to sniff the traffic?

saeugetier commented 4 years ago

@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.

saeugetier commented 4 years ago

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.

thedayu commented 4 years ago

Any progress here? I tried YLKG08YL, and found that THIS device sends BLE advertise at clicking or rotating, no matter it is connected or not.

My guess is that It sends command thru BLE adv data. Here is the data i got [clockwise, counter clockwise, click, double click, long press]

Type: 0x16 Value: 95FE5830B603E6381FC34124F81962647279260400004A
Type: 0x16 Value: 95FE5830B603E7381FC34124F881FE75CD2DBE040000D0
Type: 0x16 Value: 95FE5830B603E8381FC34124F81E9180BCC248040000B4
Type: 0x16 Value: 95FE5830B603E9381FC34124F8A2FB15DDC53C040000A6
Type: 0x16 Value: 95FE5830B603EA381FC34124F8BF414286576E040000A5

My read: 95FE5830B603 - EA - 381FC34124F8 - BF414286576E - 04 - 0000A5 [service id] [Command SN] [device id] [command content] [time] [checksum]

Command SN is increased by 1 and goes to 0 after 0xff. [[[Need help]]] command content is different every time, should be encoded with something.

thedayu commented 4 years ago

More log for clockwise rotation:

 Type: 0x16 Value: 95FE5830B6037B381FC34124F8837E33ED9CB50800005C
 Type: 0x16 Value: 95FE5830B6037C381FC34124F8353FBAFAED2508000013
 Type: 0x16 Value: 95FE5830B6037D381FC34124F8FD9E018C46FE08000009
 Type: 0x16 Value: 95FE5830B6037E381FC34124F897645E49EAB2080000F3
 Type: 0x16 Value: 95FE5830B6037F381FC34124F87898DA62791E0800005C
 Type: 0x16 Value: 95FE5830B6037F381FC34124F87898DA62791E0800005C
 Type: 0x16 Value: 95FE5830B60380381FC34124F89E27ABB24B6F08000040
 Type: 0x16 Value: 95FE5830B60381381FC34124F8D91603561B7E080000CA
 Type: 0x16 Value: 95FE5830B60382381FC34124F8886E32BAA798080000F1
 Type: 0x16 Value: 95FE5830B60382381FC34124F8886E32BAA798080000F1
 Type: 0x16 Value: 95FE5830B60383381FC34124F86EA7D1F540CF08000052
 Type: 0x16 Value: 95FE5830B60384381FC34124F83A706F766DA208000085
 Type: 0x16 Value: 95FE5830B60385381FC34124F869A53577F37708000015
 Type: 0x16 Value: 95FE5830B60386381FC34124F8F14A85463CBE0800004F
 Type: 0x16 Value: 95FE5830B60387381FC34124F85474F4AB55E808000013
 Type: 0x16 Value: 95FE5830B60388381FC34124F89B2AD0B7E7C4080000BD
 Type: 0x16 Value: 95FE5830B60389381FC34124F8893D613033A50800008A
 Type: 0x16 Value: 95FE5830B6038A381FC34124F8298A4AD061C508000045
 Type: 0x16 Value: 95FE5830B6038A381FC34124F8298A4AD061C508000045
 Type: 0x16 Value: 95FE5830B6038B381FC34124F8E0B0EA70E35608000059
nccchirag commented 4 years ago

Update Happy new to year to all!

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

thedayu commented 4 years ago

MORE INFO: 90% sure it is using Mibeacon protocol, described as follow:

    ServiceID   [2Byte] 95FE
    FrameControl    [2B]    5830 --> Encyrpted, contains Obj, version 3, no auth.
    Product ID  [2B]    B603
    Sequence    [1B]    8B
    MAC     [6B]    381FC34124F8 <- My device.
    OBJ Encyrpted   [6B]    E0B0EA70E356  <<<<<<-----------
    Ext seq     [3B]    080000
    No idea     [1B]    59    <---might be message integrity check, but according to spec,   MIC should be 4bytes long.

Digged into mi ble code: payload object is encrypted with aes_ccm_encrypt_and_tag, which takes 16 bytes beacon key.

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"). I have put up code for AES decryption and tried with Product id/Service id and some other things, add up with that 12bytes beaconkey to get 16 bytes as key, so far, no luck.

Custom Characteristic
    UUID: 00000014-0000-1000-8000-00805F9B34FB
    Properties: READ,WRITE
    Write Type:WRITE REQUEST

    Descriptors:
    Characteristic User Description
    UUID: 0x2901
    beaconkey
Busyrev commented 4 years ago

@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

thedayu commented 4 years ago

Yes, i am using code from this repo. For now the issue is, what is the 16bytes key to decrypt.

ufanders commented 4 years ago

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!

kueblc commented 4 years ago

@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 auth and authInit.

EDIT: I believe I've authenticated, using authInit = 19 and auth = 3. I noticed that these handles had the UUIDs of 0010 and 0001 respectively, which corresponds with what I've read on aprosvetova/xiaomi-kettle. I'm curious as to how @aprosvetova found this mapping. Using these handles and the PoC for mi-kettle from @drndos I received a token that matched the "should be token". If I'm understanding this correctly it looks like next I need to find the UUID for status.

@syu-source how did you capture the data from the advertise packet?

kueblc commented 4 years ago

MORE INFO: 90% sure it is using Mibeacon protocol, described as follow:

  ServiceID   [2Byte] 95FE
  FrameControl    [2B]    5830 --> Encyrpted, contains Obj, version 3, no auth.
  Product ID  [2B]    B603
  Sequence    [1B]    8B
  MAC     [6B]    381FC34124F8 <- My device.
  OBJ Encyrpted   [6B]    E0B0EA70E356  <<<<<<-----------
  Ext seq     [3B]    080000
  No idea     [1B]    59    <---might be message integrity check, but according to spec,   MIC should be 4bytes long.

@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 B603 as a LE decimal, I see we get 950, the previous found product ID.

thedayu commented 4 years ago

I didn't look into details but, these tow functions take any length of data, and as I tested, they work with 6 bytes. aes_ccm_encrypt_and_tag aes_ccm_auth_decrypt

    uint8_t pi[32] = { 0xF6,0xA7,0x5E,0x39,0x7A,0x72 };
    uint8_t po[32];
    uint8_t pt[32];
    dumphex(pi, 6);
    aes_ccm_encrypt_and_tag(key, c, sizeof(beacon_nonce), &aad, 1, pi, 6, po, mic, sizeof(mic));
    dumphex(po, 6);
    aes_ccm_auth_decrypt(key, c, sizeof(beacon_nonce), &aad, 1, po, 6, pt, mic, 4);
    dumphex(pt, 6);

pi equals to pt.

kueblc commented 4 years ago

@syu-source I found this document which shows it is legal to have a 1-byte MIC.

aheadlead commented 4 years ago

thank you @saeugetier for the assistance yes, it seems authentication might be weak and the dimmer supports mi Home app so, mostly it would be implementing the same authentication as the one mentioned in the link you shared. Let me have a look

@0xabadc0fe 你能在这里协助吗? 谢谢

@0xabadc0fe seems like a Xiaomi employee since his email address ends with xiaomi.com and he will not provide us with any help obviously.

joeschny commented 4 years ago

Hello, is this thread dead ? thx

ufanders commented 4 years ago

I hope not! I might just rip out the Yeelight dimmer electronics and replace them with Arduino code running on a Nordic nRf52* BLE module

ur1katz commented 4 years ago

I currently cant test this myself but i'm pretty sure the Telink Bluetooth mesh protocol is used to connect the lamp to the dimmer https://github.com/google/python-dimond

tcwj2008 commented 4 years ago

@ufanders Could you share the Arduino code,please

kueblc commented 4 years ago

I currently cant test this myself but i'm pretty sure the Telink Bluetooth mesh protocol is used to connect the lamp to the dimmer https://github.com/google/python-dimond

What makes you say this? It's not a Google product and shares none of the Characteristic UUIDs. If you read this thread, we've determined confidently that this the MiBeacon protocol.

@ufanders Could you share the Arduino code,please

@tcwj2008 https://github.com/nccchirag/yeelight-ble-rotary-dimmer/issues/1#issuecomment-536265188

is this thread dead ?

@joeschny no. We've accomplished quite a bit but there are still challenges ahead.

You can use https://github.com/drndos/mi-kettle-poc as a starting point. I was able to modify the script to authenticate with the switch, assign a serial, and decrypt the beaconkey. The switch broadcasts mi beacon advertising packets whenever it is operated. We haven't yet figured out how to decrypt the payload of these packets however.

I was able to reverse engineer much of the Xiaomi Android app, along with resources available at https://github.com/MiEcosystem/mijia_ble_common and found that this is an RC4 authenticated device. This makes sense as looking back to https://github.com/aprosvetova/xiaomi-kettle, we see that the cipher is actually an implementation of RC4, whether they realized it or not.

As far as decrypting the broadcast packets, @syu-source theorizes that they are encrypted with AES-CCM but we haven't determined what is used as the key and nonce. Through testing it is evident that the cipher text changes for each event, and that the cipher text (and sequence number) is repeatable by resetting the device (removing the battery). This leads me to believe the sequence number is used as part of the encryption.

Due to this fact, and since AES-CCM is an XOR between the plain text and the cipher stream, I was able to create a proof of concept that allows you to prerecord a sequence of identical events (ie, repeatedly tapping the button), reset the device, and then XOR the prerecorded cipher text with the newly received cipher text based on the sequence number.

The result is that, while this isn't true decryption, I can reliably determine which function was activated for as many sequence steps as are prerecorded. It's been about two months since I've worked on this, had higher priority tasks come up, so it'll take me some time to gather my notes, but I would be happy to share what I've discovered so far about the payload structure.

ur1katz commented 4 years ago

@kueblc i'm following this thread closely and it was really great to see the kettle POC working. In a normal ble connection you'd expect another service for data/notify but that's not the case here and that makes me think they used the Tlink "mesh" protocol.

The link I sent is not for a google product its an implementation of the protocol used by TLSR826X(8267 in our case) chips. i'm pretty familiar with these SOC's and there's little space in those to create an entire new protocol. If the dimmer can sync with more than one light I don't believe its self implemented. If it's just sending broadcasts than maybe.

Would be great if you share some of your findings. Anyways thanks for your work on this issue.

ufanders commented 4 years ago

I worked on a BLE product that simply rotated MACs and sent its data AES encrypted, within advertising packets. Would this be possible with what you're seeing?

kueblc commented 4 years ago

The link I sent is not for a google product its an implementation of the protocol used by TLSR826X(8267 in our case) chips. i'm pretty familiar with these SOC's and there's little space in those to create an entire new protocol. If the dimmer can sync with more than one light I don't believe its self implemented. If it's just sending broadcasts than maybe.

@ur1katz thanks for clarifying. Upon disassembly I can confirm your finding that it is running on the TLSR8267F512ET32 SoC.

I worked on a BLE product that simply rotated MACs and sent its data AES encrypted, within advertising packets. Would this be possible with what you're seeing?

The MAC is indeed shuffled and used as part of the authentication process, see mixA and mixB in the mi-kettle PoC. The payload is confirmed to be distributed by way of advertising packets.

dezaxe69210 commented 4 years ago

Hello everybody, I'm very very newbie about all this stuff. But as I'm interested in use this swich with my yeelight color bulbs i post my founding here. So what I've discovered, I don't know if its something useful or helpful but, in disassembling the switch I noticed a sticker on the microchip. Maybe you have already see it. This sticker has a QRCode on it, so I tried first to scan it, to use it with Xiaomi Home app but did not work. So I fell on this git, and I've downloaded BLE scanner on my phone and I tried QRCode scanner on it. So there is data from this QRCode : something like this F82441C3E465 (I have changed the last three digits from real mine). Another thing that I've done is to scan the QRCode from the manual and it led me to play store app : WeChat.. I dont read chinese so maybe it's intended. Don't know if it helps, these are my 2 cents

EDIT : after verification, this the MAC adress... i'm so disappointed...

madprogrammer commented 4 years ago

Me too decided to give this a try. So far I've been able to successfully authenticate with the dimmer using @nikko82 hints, as well as receive the BLE adv messages when interacting with the dimmer. I believe, the only thing left is to figure out the encryption key for the OBJ Encyrpted portion of the advertisement, which is obviously being setup during the authentication process, and subsequently used to encrypt the adv packets. Hope I'll have some luck here.

dezaxe69210 commented 4 years ago

@madprogrammer how can I help you?

madprogrammer commented 4 years ago

@dezaxe69210 I only have the dimmer, not any compatible ceiling lights (because when I bought the dimmer I mistakenly thought it was compatible with WiFi bulbs). If you have a compatible light, it would be helpful if you managed to somehow extract the firmware of the light (e.g. by intercepting traffic during a firmware upgrade via MiHome APP, or extract it by searching through the MiHome related files on your smartphone). Then, possibly by reverse engineering that FW we could find out how to derive the AES key.

dezaxe69210 commented 4 years ago

@madprogrammer I'm in the same case as you, I have only the dimmer..

dezaxe69210 commented 4 years ago

ble_lt_sdk_lt_4_1.zip

8267_module.zip maybe it will help

The latest thing I've found : see attached : you will find mijia/ xiaomi informations

madprogrammer commented 4 years ago

Although Xiaomi's documentation in some sources says 1 byte MIC is possible, every example code found online for MiBeacon implementation, as well as the AES CCM code that it uses (NIST SP800-38C compilant from mbedtls) allows for a minimal tag length of 4 bytes, which makes me think that the crypto implementation in our dimmer might be different from other MiBeacon devices, and probably not even AES128, though the TLSR8267 chip does support hardware AES crypto acceleration.

weswes commented 3 years ago

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.

I'm also interested by a dimmer knob with esp32. Another solution may be to use a shelly dimmer with a rotary knob: https://www.instructables.com/id/Shelly-Dimmer-Wall-Switch-With-Rotary-Knob-and-Hom/

JD99 commented 3 years ago

hi. maybe it will help

https://github.com/AlexxIT/XiaomiGateway3

Zn4rK commented 3 years ago

@kueblc @ufanders @thedayu

I just found this thread yesterday, and I agree that it looks like the Mi Beacon protocol.

I don't have much to contribute with right now, but, it looks like their closed source of https://github.com/MiEcosystem/mijia_ble_libs is embedded in ble_lt_sdk_lt_4_1.zip that @dezaxe69210 posted.

There are a couple of interesting functions in their libs (I've concatenated the headers and source for readability):

/**@brief Function for encrypt the data.
 *
 * @details After Secure auth login, device and application will both generate the
 * same session key. This key will used to encrypt the data by AES128-CCM. The 
 * output is concatenating LSB of counter in nonce, cipher text and the MIC. So
 * the length of output buffer MUST be 6 bytes larger than input buffer.
 *
 * @param[in] input    plain text.
 * @param[in] len      plain text bytes.
 * @param[out] output  cipher text and 6-bytes extra info.
 */
int mi_session_encrypt(const uint8_t *input, uint8_t len, uint8_t *output);

// libs/common/mible_crypto.c
/**@brief Function for handling the Xiaomi Service's BLE events.
 *
 * @param[in] input    cipher text and 6-bytes extra info.
 * @param[in] len      num of byte.
 * @param[out] output  plain text.
 */
int mi_session_decrypt(const uint8_t *input, uint8_t ilen, uint8_t *output)
{
    uint32_t ret = 0;
    uint32_t curr_cnt = session_app_cnt;

    if (m_flags.initialized != 1)
        return 1;

    if (m_flags.processing == 1)
        return 2;

    if (m_flags.expired == 1)
        return 3;

    CRITICAL_SECTION_ENTER();
    m_flags.processing = 1;
    CRITICAL_SECTION_EXIT();

    session_nonce_t nonce = {0};
    nonce.iv = session_ctx.app_iv;
    uint16_t cnt_low = input[1]<<8 | input[0];
    update_cnt(&curr_cnt, cnt_low);

    if (curr_cnt <= session_app_cnt && curr_cnt != 0) {
        m_flags.processing = 0;
        return -1;
    } else {
        session_app_cnt = curr_cnt;
    }

    nonce.counter = session_app_cnt;
    ret = mi_crypto_ccm_decrypt(session_ctx.app_key,
                                (void*)&nonce, sizeof(nonce),
                                         NULL, 0,
                                      2+input, ilen-2-4,
                                       output,
                             2+input+ilen-2-4, 4);

    m_flags.processing = 0;

    if (ret == MI_SUCCESS) {
        mible_timer_stop(session_timer);
        mible_timer_start(session_timer, SESSION_KEY_VALID_PERIOD_SEC * 1000, NULL);
    }
    return ret;
}
int mi_crypto_ccm_decrypt( const uint8_t *key,
                        const uint8_t *iv, size_t iv_len,
                        const uint8_t *add, size_t add_len,
                        const uint8_t *in, size_t in_len,
                        uint8_t *out,
                        const uint8_t *tag, size_t tag_len )
{
    int ret = aes_ccm_auth_decrypt(key, iv, iv_len, add, add_len,
                                    in, in_len, out, tag, tag_len );
    return ret;
}

All sources that are mentioned here https://iot.mi.com/new/doc/embedded-development/ble/standard are present in that zip.

I'll keep digging, but since I discovered that we have access to the mijia_ble_libs now, I figured that I'll let you know!

AlexxIT commented 3 years ago

@JD99 heh. I came to you for help. Don't know how to decode Xiaomi Lock payload. I can control Yeelight Mesh lamps with miio protocol and Gateway 3. Don't implemented yet.

kiwipaulrob commented 3 years ago

See here for someone who is working with the Telink TLSR82** MCUs and has got to the point where he can upload custom software. I have used his online form to pair and update the firmware on these Xiaomi sensors.. Hopefully this can assist you to get pasts the encryption etc. Have a unit but don't have the knowledge to get it working with Home Assistant, counting on you guys....

kiwipaulrob commented 3 years ago

link didn't work..

https://github.com/atc1441/ATC_MiThermometer

a-andreyev commented 3 years ago

Not sure is it related, but I'm also searching for a solution for getting the data from YLKG07YL.

Found this project related to devices called yee-rc, not sure is it about BLE, but hopefully, some parts of the protocol could be related to yeelight ble rotary dimmer, since my ble device also called yee-rc ? :thinking:

a-andreyev commented 3 years ago

Also interesting findings:

a-andreyev commented 3 years ago

Thanks to the discussion, I'm also able to reproduce the auth and receiving the beacon procedure with the mikettle codebase (looks like YLKG07YL have the same productId 950). Trying to search for adv packets decryption details at https://github.com/MiEcosystem?q=ble: https://github.com/MiEcosystem/mijia_ble_common

LvivEchoes commented 3 years ago

Hi guys! Any updates here?

I also start reversing that, but still no luck. Found that some bytes are completely different, even if I step encoder +1 or -1 all time.

Also start using crypto utils in python to try decode payload from ble adv stream, but also still no luck. Going through mi app (official sources), found that they are using aes ccm decryption method, but key stored in beacon section (in service) only 12 bytes length, for decryption with that method - we need 16 bytes key length. Any suggestion? ideas?

Знімок екрана  о 22 13 19 Знімок екрана  о 22 20 34
latel commented 3 years ago

any progress here?