Closed Ernst79 closed 3 years ago
Do you know how to get the encryption key without ceiling light ? I do not have any BT Xiaomi gateway and I can't connect to the dimmer directly
I succeeded to retrieve the beaconKey
using ylkg08y.md and mikettle !!! The beaconKey
has been encrypted with the token: https://github.com/rexbut/mikettle/commit/62ca322c28ebef529b79e04a197999388bbf5d23#diff-5af407bf9ddc11b895e682c5e87562faaf8fa639563795be12af8049765d03b7R239
$ python3 demo.py connect F8:24:41:C5:98:8B 950
DEBUG:mikettle.mikettle:Init Mikettle with mac F8:24:41:C5:98:8B and pid 950
Connect
Authenticating
INFO:mikettle.mikettle:firmware_version: 1.0.1_1
INFO:mikettle.mikettle:beaconkey: b853075158487ca39a5b5ea9
@Ernst79 Do you think you can automate the recovery or do I have to write a script?
Well done. I think for now, it's the easiest to make a little script and a short explanation how to use it, I guess. I can put is somewhere here in the BLE monitor repo if you want and add the explanation in the FAQ. Just post it here and I will take care of it (or make a PR).
Perhaps later I can look into automating it, but that won't be shortly (as BLE monitor isn't designed to connect to anything, it just listens passively (by design 😄).
It would be nice to add it to this repo.
Source: https://github.com/rexbut/mikettle/blob/master/get_beacon_key.py
I tested with "YLKG08YL"
#!/usr/bin/env python3
# Usage:
# pip3 install bluepy
# python3 get_beacon_key.py <MAC> <PRODUCT_ID>
#
# List of PRODUCT_ID:
# 339: For 'YLYK01YL'
# 950: For 'YLKG07YL' and 'YLKG08YL'
#
# Example:
# python3 get_beacon_key.py AB:CD:EF:12:34:56 950
from bluepy.btle import UUID, Peripheral, DefaultDelegate
import random
import re
import sys
MAC_PATTERN = r"^[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}:[0-9A-F]{2}$"
UUID_SERVICE = "fe95"
HANDLE_AUTH = 3
HANDLE_FIRMWARE_VERSION = 10
HANDLE_AUTH_INIT = 19
HANDLE_BEACON_KEY= 25
MI_KEY1 = bytes([0x90, 0xCA, 0x85, 0xDE])
MI_KEY2 = bytes([0x92, 0xAB, 0x54, 0xFA])
SUBSCRIBE_TRUE = bytes([0x01, 0x00])
def reverseMac(mac) -> bytes:
parts = mac.split(":")
reversedMac = bytearray()
leng = len(parts)
for i in range(1, leng + 1):
reversedMac.extend(bytearray.fromhex(parts[leng - i]))
return reversedMac
def mixA(mac, productID) -> bytes:
return bytes([mac[0], mac[2], mac[5], (productID & 0xff), (productID & 0xff), mac[4], mac[5], mac[1]])
def mixB(mac, productID) -> bytes:
return bytes([mac[0], mac[2], mac[5], ((productID >> 8) & 0xff), mac[4], mac[0], mac[5], (productID & 0xff)])
def cipherInit(key) -> bytes:
perm = bytearray()
for i in range(0, 256):
perm.extend(bytes([i & 0xff]))
keyLen = len(key)
j = 0
for i in range(0, 256):
j += perm[i] + key[i % keyLen]
j = j & 0xff
perm[i], perm[j] = perm[j], perm[i]
return perm
def cipherCrypt(input, perm) -> bytes:
index1 = 0
index2 = 0
output = bytearray()
for i in range(0, len(input)):
index1 = index1 + 1
index1 = index1 & 0xff
index2 += perm[index1]
index2 = index2 & 0xff
perm[index1], perm[index2] = perm[index2], perm[index1]
idx = perm[index1] + perm[index2]
idx = idx & 0xff
outputByte = input[i] ^ perm[idx]
output.extend(bytes([outputByte & 0xff]))
return output
def cipher(key, input) -> bytes:
# More information: https://github.com/drndos/mikettle
perm = cipherInit(key)
return cipherCrypt(input, perm)
def generateRandomToken() -> bytes:
token = bytearray()
for i in range(0, 12):
token.extend(bytes([random.randint(0,255)]))
return token
def get_beacon_key(mac, product_id):
reversed_mac = reverseMac(mac)
token = generateRandomToken()
# Pairing
input(f"Activate pairing on your '{mac}' device, then press Enter: ")
# Connect
print("Connection in progress...")
peripheral = Peripheral(deviceAddr=mac)
print("Successful connection!")
# Auth (More information: https://github.com/archaron/docs/blob/master/BLE/ylkg08y.md)
print("Authentication in progress...")
auth_service = peripheral.getServiceByUUID(UUID_SERVICE)
auth_descriptors = auth_service.getDescriptors()
peripheral.writeCharacteristic(HANDLE_AUTH_INIT, MI_KEY1, "true")
auth_descriptors[1].write(SUBSCRIBE_TRUE, "true")
peripheral.writeCharacteristic(HANDLE_AUTH, cipher(mixA(reversed_mac, product_id), token), "true")
peripheral.waitForNotifications(10.0)
peripheral.writeCharacteristic(3, cipher(token, MI_KEY2), "true")
print("Successful authentication!")
# Read
beacon_key = cipher(token, peripheral.readCharacteristic(HANDLE_BEACON_KEY)).hex()
firmware_version = cipher(token, peripheral.readCharacteristic(HANDLE_FIRMWARE_VERSION)).decode()
print(f"beaconKey: '{beacon_key}'")
print(f"firmware_version: '{firmware_version}'")
def main(argv):
# ARGS
if len(argv) <= 2 :
print("usage: get_beacon_key.py <MAC> <PRODUCT_ID>\n")
print("PRODUCT_ID:")
print(" 339: For 'YLYK01YL'")
print(" 950: For 'YLKG07YL' and 'YLKG08YL'")
return
# MAC
mac = argv[1].upper()
if not re.compile(MAC_PATTERN).match(mac):
print(f"[ERROR] The MAC address '{mac}' seems to be in the wrong format")
return
# PRODUCT_ID
product_id = argv[2]
try:
product_id = int(product_id)
except Exception:
print(f"[ERROR] The Product Id '{product_id}' seems to be in the wrong format")
return
# BEACON_KEY
get_beacon_key(mac, product_id)
if __name__ == '__main__':
main(sys.argv)
The script works with "YLYK01YL" by setting PRODUCT_ID = 339
:
# python3 get_beacon_key_2.py f8:24:41:e9:50:74
Activate pairing on your 'F8:24:41:E9:50:74' device, then press Enter:
Connection in progress...
Successful connection!
Authentication in progress...
Successful authentication!
beaconKey: '471342543805f83c2caa9deb'
firmware_version: '1.0.1_1'
Thanks. I’ll add instructions in FAQ, will use this as the preferred solution for legacy encryption.
@rexbut nice! you can add pid to cmd line params after mac.
btw: this method (maybe with small adjustments per pid) can be probably used to auth/read key from any mijia ble device.
I just updated the script to take the PRODUCT_ID
as a parameter.
Can anyone verify that the script works with YLKG07YL
?
@rexbut trying it now. Will post here the result
@rexbut Tested with Yeelight Wireless Smart Dimmer Model: YLKG07YL Product Date:0806 It works
# python3 get_beacon_key.py -my-mac-here- 950
Activate pairing on your '-my-mac-here-' device, then press Enter:
Connection in progress...
Successful connection!
Authentication in progress...
Successful authentication!
beaconKey: '-my-key-here-'
firmware_version: '1.0.1_1'
@Ernst79 I`m not using Home Assistant, but custom scripts for my home automation. Is there a simple way to run ble-monitor scripts to just output to stdout decrypted messages from dimmer?
No, currently not. There have been requests to make it available as a pypi package, but I didn't have time to do that. But the main decoding is done in \custom_components\ble_monitor\ble_parser\xiaomi.py
. You could use aioblescan to get the raw BLE messages and write a script that does the parsing of these messages.
Installed HA, added device and it works. It shows actions from dimmer. Full chain works great.
I'm closing this issue, the script is placed in the repository and FAQ has been updated.
Hey,
I have a brand new YLKG07YL
dimmer from Amazon.com, I have tested it with the script but it just hangs after Authentication in progress...
.
It seems to hang on line 111:
auth_service = peripheral.getServiceByUUID(UUID_SERVICE)
I tested it manually with bluepy
:
>>> conn = Peripheral("F8:24:41:C5:13:7F")
>>> conn.getCharacteristics()
It also seems to hang, once connected, the orange light on the dimmer stops, then it sleeps for around 2-3 seconds, then it blinks again once and dies.
Did anyone else encounter this?
Hey,
I have a brand new
YLKG07YL
dimmer from Amazon.com, I have tested it with the script but it just hangs afterAuthentication in progress...
.It seems to hang on line 111:
auth_service = peripheral.getServiceByUUID(UUID_SERVICE)
I tested it manually with
bluepy
:>>> conn = Peripheral("F8:24:41:C5:13:7F") >>> conn.getCharacteristics()
It also seems to hang, once connected, the orange light on the dimmer stops, then it sleeps for around 2-3 seconds, then it blinks again once and dies.
Did anyone else encounter this?
Hi, did you solve it? I also have the dimmer in its new version and with the script I can't extract the key, it gives me an error after the connection.
Hi, did you solve it? I also have the new version of the dimmer and using the script to extract to 16 bit key also does not work
There are currently two ways described in the FAQ to get the encryption key for the Yeelight Remote (YLYK01YL) and Yeelight Dimmers (YLKG07YL and YLKG08YL). If you have easier ways to get the encryption key, please report in this issue.
I will later copy some relevant info from #289