openScale
openScale copied to clipboard
Wyze Scale (WHSCL1) Support
Wyze Scale (WHSCL1)
Vendor App: https://play.google.com/store/apps/details?id=com.hualai&hl=en_US&gl=US
Product Page https://www.wyze.com/products/wyze-scale
Step 1: Read the general reverse engineer process
- [x] I have read the how to reverse engineer a Bluetooth 4.x wiki entry
Step 2: Acquiring some Bluetooth traffic Attach 3 log files with the corresponding true values, read here for further information.
- Bluetooth HCI Snoop log file user settings in the vendors app:
sex male, body height: 6'4" ft, Year of Birth 1991
measured true values in the vendors app for the 1. HCI Snoop log file:
Number | 1 |
---|---|
Date and Time | 2022.05.05 09:27 PM |
Weight | 168.4lb |
BMI | 20.5 |
Body Fat | 15.1% |
Muscle Mass | 134.2lb |
Body Water | 62.2% |
Lean Body Mass | 143.0lb |
Bone Mass | 8.8lb |
Protein | 17.5% |
Visceral Fat | 7 |
BMR | 1771 |
Metabolic Age | 27 |
Log 1: btsnoop_hci_168.4.log
- Bluetooth HCI Snoop log file user settings in the vendors app:
sex male, body height: 6'4" ft, Year of Birth 1991
measured true values in the vendors app for the 2. HCI Snoop log file:
Number | 2 |
---|---|
Date and Time | 2022.05.05 09:31 PM |
Weight | 188.7lb |
BMI | 23.0 |
Body Fat | 21.4% |
Muscle Mass | 139.3lb |
Body Water | 57.6% |
Lean Body Mass | 148.3lb |
Bone Mass | 9.0lb |
Protein | 16.2% |
Visceral Fat | 8 |
BMR | 1823 |
Metabolic Age | 27 |
Log 2: btsnoop_hci_188.7.log
- Bluetooth HCI Snoop log file user settings in the vendors app:
sex male, body height: 6'4" ft, Year of Birth 1991
measured true values in the vendors app for the 3. HCI Snoop log file:
Number | 3 |
---|---|
Date and Time | 2022.05.05 09:35 PM |
Weight | 209.2lb |
BMI | 25.5 |
Body Fat | 29.5% |
Muscle Mass | 138.4lb |
Body Water | 51.6% |
Lean Body Mass | 147.5lb |
Bone Mass | 9.0lb |
Protein | 14.5% |
Visceral Fat | 9 |
BMR | 1815 |
Metabolic Age | 29 |
Log 3: btsnoop_hci_209.2.log
Step 3: Discover Bluetooth services and characteristic Read here how to create the openScale debug file
OpenScale Log: openScale_2022-05-05_13-39[1].txt
BLE Scanner: WHSCL1DeviceInfo.txt
Wyze API example (from a separate project, may not be relevant for this but found it interesting) https://github.com/JoshuaMulliken/ha-wyzeapi/issues/93#issuecomment-970230075 ScaleVariables.txt
So I'm trying to fetch the logs for the Wyze Scale X, but I wonder how you made sense of the data. Opening the btsnoop_hci.log
in notepad results in gibberish and when I open it up in wireshark, I do see my phone and my device listed there, but I can't find the packets in which my weight or other details are listed. Mind helping me out?
As the data in the logs is often obfuscated or in byte code I used the wyze app to pull the values associated with the logs eg I started the logging, weighed myself, noted the values in the wyze app, stopped the logging, saved the log, rinse and repeat etc. In theory logical data should be able to be derived from a comparison of the resulting tables and the logs but I didn't get much further than gathering the data as I moved on to other projects. I left the logs here as a basepoint for others to compare against. As a note I have the original wyze scale, don't know how much the API or Bluetooth logs differ between this and the X.
I have both the OG scale and the Scale X, and would be happy to help y'all do any testing necessary
Has adding this particular Hardware been abandoned?
here's a hand-annotated protocol dump for you :)
-------------------------------------------------------------------------------
Send public key to scale
> 00f000089ad9fd9600000000
(public key = 0x96FDD99A)
-------------------------------------------------------------------------------
received public key from scale
< 42f000089cebc88600000000
(public key = 0x86C8EB9C)
-------------------------------------------------------------------------------
send CMD_SYNC_TIME
(raw)
> [22, 0, 7, 0, 1, -88, -85, -58, -68, 101, 1]
(rawhex)
> 16 00 07 00 01 A8 AB C6 BC 65 01
(encrypted)
> 1101000bd2d3e619fd6e58d6dfb23437dbc5486a
time = 0x65BCC6AB = time in seconds since epoch = Friday, February 2, 2024 10:40:43 AM GMT
os = 0x01 (probably specifies the type of timestamp? 0x01 being unix timestamps?)
-------------------------------------------------------------------------------
receive sync type reply
(raw)
< 53010007aff48a08e48a47ff
(unencrypted)
< 2201030001a800
last byte = 00 = success
-------------------------------------------------------------------------------
send CMD_USER_LIST_NEW
(raw)
> [22, 0, 2, 0, 13, -88]
(encrypted)
> 1201000668e95d0a577b99ff
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 54010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_USER_LIST_NEW response
(raw)
< 55010020542e23a5086cd3aa4fd800f6c5846ad1e40f592000525f04ed8cc484d0ddd71a
(unencrypted)
< 22011c000da801 2f319e4a8a8db394f3fa7ef7f9fdaa7f a618 01 2c b4 01 00 440c
user id = 2f319e4a8a8db394f3fa7ef7f
weight = 18A6 = 6310/100 = 63.1kg
sex = 1 = M
age = 2c = 44
height = b4 = 180cm = ~5'11"
athlete mode = 1
only weight = 0
last impedence = 0c44 = 3140
-------------------------------------------------------------------------------
send CMD_UPDATE_USER
(raw)
> [22, 0, 27, 0, 10, -88, 47, 49, -98, 74, -118, -115, -77, -108, -13, -6, 126, -9, -7, -3, -86, 127, -100, 24, 1, 44, -76, 1, 0, 68, 12]
(raw hex)
> 1601B000AA8 2F319E4A8A8DB394F3FA7EF7F9FDAA7F 9C18 01 2C B4 01 00 440C
(same data format as CMD_USER_LIST_NEW above)
(encrypted)
> 1301001f238da6606738035f7a0b9e248c4425eee9abcef013ec18704b00a25a67b61b97
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_UPDATE_USER response
(raw)
< 5701000784ca88c0aa083ca5
(unencrypted)
< 220103000aa800
last byte = 00 = success
-------------------------------------------------------------------------------
send CMD_CURRENT_USER_NEW
(raw)
> [22, 0, 27, 0, 14, -88, 47, 49, -98, 74, -118, -115, -77, -108, -13, -6, 126, -9, -7, -3, -86, 127, 0, 0, 1, 44, -76, 1, 0, 68, 12]
(rawhex)
> 16001B000EA8 2F319E4A8A8DB394F3FA7EF7F9FDAA7F 0000 01 2C B4 01 00 440C
(same data format as CMD_USER_LIST_NEW above)
(encrypted)
> 1401001f1bed79bee2fa41fe7a0b9e248c4425ee8502f6a177eb46dd4b00a25a67b61b97
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 58010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_CURRENT_USER_NEW response
(raw)
< 59010007074cec7f57017c55
(unencrypted)
< 220103000ea800
last byte = 00 = success
-------------------------------------------------------------------------------
received CMD_HISTORY_WEIGHT_DATA message
(raw)
5a010035eff26c5502366821b6dfd8281e9021297835b63beb35103b4f3873cc93d4251d09e4bd155a1416685d1594d262adf844c466b564917154c6
(unencrypted)
2201310009a801 5859bb65 2f319e4a8a8db394f3fa7ef7f9fdaa7f 01 2c b4 01 00 b018 440c 3200 3302 25 b702 c400 5802 06 8206 29 c300
timestamp = 0x65bb5958 = 1706776920 (seconds since epoch) = Thursday, February 1, 2024 8:42:00 AM
user id = 2f319e4a8a8db394f3fa7ef7f9fdaa7f
sex = 01 = M
age = 2C = 44
height = b4 = 180cm
athlete mode = 01 = true
only weight = 00 = false
weight = 0x18b0 = 63.2kg
impedance = 0c44 = 3140
bfp = 0x0032
muscleMass = 0x0233
boneMass = 0x25
water = 0x02b7
protein = 0x00c4
lbm = 0x0258
vfal = 0x06
bmr = 0x0682
bodyAge = 0x29 = 41
bmi = 0x00c3 = 195/10 = 19.5
-------------------------------------------------------------------------------
sending CMD_HISTORY_WEIGHT_DATA response
(I believe this is what causes the scale to delete this weight record from its cache)
> (raw)
[22, 0, 3, 0, 9, -88, 0]
> (encrypted)
15010007cfe3996cd84441fe
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
received CMD_HISTORY_WEIGHT_DATA message
(raw)
< 5c010035a032ddbcf744f3c32428de44c0f974ab7835b63beb35103b4f3873cc93d4251dc0087481fa43d47eea5c20685e15c628dfe5e6bd2ae334f8
(unencrypted)
< 2201310009a801c09abc652f319e4a8a8db394f3fa7ef7f9fdaa7f012cb40100a6180000000000000000000000000000000000c300
-------------------------------------------------------------------------------
sending CMD_HISTORY_WEIGHT_DATA response
(raw)
> [22, 0, 3, 0, 9, -88, 0]
(encrypted)
> 16010007cfe3996cd84441fe
-------------------------------------------------------------------------------
more uninteresting empty CMD_CUR_WEIGHT_DATA messages
(encrypted)
5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(encrypted)
5e010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(encrypted)
5f010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
sending CMD_SET_UNIT command
(raw)
> [22, 0, 3, 0, 4, -88, 1]
(encrypted)
> 17010007ab0e171ea32daa02
1 = lb, 0 = kg?
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA messages
(raw)
< 50010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 51010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
<22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
------------------------------------------------------------------------------
CMD_SET_UNIT response
(raw)
< 520100074ef5ff79730a6d8d
(unencrypted)
< 2201030004a800
last byte = 00 = success
-------------------------------------------------------------------------------
send CMD_SET_HELLO
(raw)
> [22, 0, 3, 0, 5, -88, 0]
(encrypted)
> 180100077d672d3be2b4d174
0 = no hello?
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 53010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_SET_HELLO response
(raw)
< 5401000739f2a50482b55de6
(unencrypted)
< 2201030005a800
last byte = 00 = success
-------------------------------------------------------------------------------
send CMD_BROAD_TIME
(broadcast time.. whatever that is)
(raw)
> [22, 0, 4, 0, 7, -88, 0, 0]
(encrypted)
> 1901000844bf4f1e6fc839cf
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA messages
(raw)
< 55010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unecrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_BROAD_TIME response
(raw)
< 570100073bea9f9b77972b1f
(unencrypted)
< 2201030007a800
last byte = 00 = success
-------------------------------------------------------------------------------
send CMD_DEV_BIND_STATE
(raw)
> [22, 0, 2, 0, 12, -88]
(encrypted)
> 1a010006b9cafd3fdfcde557
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 58010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_DEV_BIND_STATE response
(raw)
< 5901000810e429f07761449f
(unencrypted)
< 220104000ca80100
color = 01 ??
status = 00 = success
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA messages
(raw)
< 5a010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
< 5c010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
sending CMD_CURRENT_USER_NEW (again??)
(raw)
> [22, 0, 27, 0, 14, -88, 47, 49, -98, 74, -118, -115, -77, -108, -13, -6, 126, -9, -7, -3, -86, 127, -100, 24, 1, 44, -76, 1, 0, 68, 12]
(rawhex)
> 16001B000EA8 2F319E4A8A8DB394F3FA7EF7F9FDAA7F 9C18 01 2C B4 01 00 440C
(encrypted)
> 1b01001f1bed79bee2fa41fe7a0b9e248c4425eee9abcef013ec18704b00a25a67b61b97
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_CURRENT_USER_NEW response
(raw)
< 5e010007074cec7f57017c55
(unencrypted)
< 220103000ea800
status = 00 = success
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA messages
(raw)
> 5f010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 50010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 51010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
sending CMD_SET_UNIT
(raw)
> [22, 0, 3, 0, 4, -88, 1]
(encrypted)
> 1c010007ab0e171ea32daa02
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 52010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_SET_UNIT response
(raw)
< 530100074ef5ff79730a6d8d
(unencrypted)
< 2201030004a800
status = 00 = success
-------------------------------------------------------------------------------
sending CMD_SET_HELLO
(raw)
> [22, 0, 3, 0, 5, -88, 0]
(encrypted)
> 1d0100077d672d3be2b4d174
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 54010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_SET_HELLO response
(raw)
< 5501000739f2a50482b55de6
(unencrypted)
< 2201030005a800
status = 00 = success
-------------------------------------------------------------------------------
sending CMD_BROAD_TIME
(raw)
> [22, 0, 4, 0, 7, -88, 0, 0]
(encrypted)
> 1e01000844bf4f1e6fc839cf
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA message
(raw)
< 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
< 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
-------------------------------------------------------------------------------
CMD_BROAD_TIME response
(raw)
< 570100073bea9f9b77972b1f
(unencrypted)
< 2201030007a800
status = 00 = success
-------------------------------------------------------------------------------
sending CMD_DEV_BIND_STATE
(raw)
> [22, 0, 2, 0, 12, -88]
(encrypted)
> 1f010006b9cafd3fdfcde557
-------------------------------------------------------------------------------
CMD_DEV_BIND_STATE response
(raw)
< 5901000810e429f07761449f
(unencrypted)
< 220104000ca80100
status = 00 = success
-------------------------------------------------------------------------------
uninteresting empty CMD_CUR_WEIGHT_DATA messages
(raw)
> 5a010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5c010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5e010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5f010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 50010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 51010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 52010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 53010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 54010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 55010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 56010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 57010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 58010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 59010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5a010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5b010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5c010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
(raw)
> 5d010033b21b07b51f9eec6bea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628ea5c20685e15c628e4a12a355257a7aa
(unencrypted)
> 22012f0008a864000000000000000000000000000000000000000000000000000000000000000000000000000000000000c300
The encryption used is XXTEA, with keys exchanged via the classic Diffie–Hellman key exchange.
some POC python code:
def _enable_encryption(self):
base = 5
modulus = 0xFFFFFFC5
private_key = secrets.randbits(32)
print("private key: %08x" % private_key)
public_key = pow(base, private_key, modulus)
print("public key: %08x" % public_key)
message = io.BytesIO()
message.write(struct.pack('b', self._get_next_frame()))
message.write(b'\xf0\x00\x08')
message.write(struct.pack('<I', public_key))
message.write(b'\x00\x00\x00\x00')
print("Sending public key to scale")
self._write_queue.put(message.getvalue())
encryption_reply: EncryptionReply = self.wait_for_message(EncryptionReply)
if encryption_reply is None:
raise Exception("Didn't get a public key back from the scale")
shared_key = pow(encryption_reply.other_public_key, private_key, modulus)
self._xxtea_key = struct.pack("@8s8x", bytes("%08x" % shared_key, "utf-8"))
print("shared key = %08x, %s" % (shared_key, hex(shared_key)))
print("xxtea key = %s" % binascii.hexlify(self._xxtea_key))
def _handle_encrypted_message(self, buf):
assert len(buf) >= buf[3] + 4
assert (len(buf) - 4) % 8 == 0
payload_length = buf[3]
message = io.BytesIO()
for i in range(0, int(len(buf) / 8)):
decrypted = xxtea.decrypt(buf[i * 8 + 4: (i+1) * 8 + 4], self._xxtea_key, padding=False)
message.write(decrypted)
decrypted_buf = message.getvalue()
print("decrypted data: %s" % binascii.hexlify(decrypted_buf, ","))
reply_class = REPLY_MAP.get(decrypted_buf[4])
if not reply_class:
print("Received unexpected message type: 0x%02x" % decrypted_buf[4])
return
self._read_queue.put(reply_class(decrypted_buf[0:payload_length]))
def send_message(self, buf):
print("sending message: %s" % binascii.hexlify(buf))
message = io.BytesIO()
message.write(struct.pack("4b", self._get_next_frame() + 0x10, 1, 0, len(buf)))
padded_payload = io.BytesIO()
padded_payload.write(buf)
while len(padded_payload.getvalue()) % 8 > 0:
padded_payload.write(b'\x00')
for i in range(0, int(len(padded_payload.getvalue()) / 8)):
message.write(xxtea.encrypt(padded_payload.getvalue()[i*8:(i+1)*8], self._xxtea_key, padding=False))
self._write_queue.put(message.getvalue())
I forgot to mention, this is from a wyze scale x
I've published some proof-of-concept (python) code for talking to the scale: https://github.com/JesusFreke/wyze_scale_tool
There should be enough info there to be able to implement the protocol in java for android