logitech-unifying-device
logitech-unifying-device copied to clipboard
C-U0007 firmware 012.010.00032 dongles does not accept encrypted keyframes
Based on discussion and analysis here RoganDawes/LOGITacker#55, I suspect the latest firmware (012.010.00032) has some way to verify the counter from a real device and reject keyframes that do not count properly
More info shared here https://www.reddit.com/r/LiveOverflow/comments/g8ajed/reverse_engineering_of_logitech_unifying_firmware
Feel free to ask questions or post if you managed to solve this.
Do they reject everything or just the keyboard keys? What about mouse keyframes?
@skito
Only the keyboard frames which are encrypted. Mouse frames, which are unencrypted, works flawlessly.
If you have an ESP8266 and NRF24L01+, I can guide you through. Given that it all works for an earlier dongle firmware, I'm confident my AES encryption code is correct.
I was thinking to mount the NRF24L01 to Atmega328 CH340, which can be directly connected to PC via USB cable. Would you think that will work or it has to be ESP8266?
Are you planning to do something with the USB? The atmega should work, I'm just not sure of its computation power. Arduino IDE supports both atmega and ESP8266, but my code is based on VSCode, PlatformIO.
@bilogic My idea is just to have plug & play device to work on. How do you connect ESP8266 to the computer? HDM, USB or you connect it to something else? Sorry for for the dump questions, software engineering is my stronger side.
@skito the ESP8266 has development modules that connect via USB such as the Wemos D1 mini. Which timezone are you in? I'm on the move, can't provide useful links at the moment.
@bilogic I'm in EET. Whenever you had time I'll appreciate some Amazon or eBay links to get start with the necessary hardware. Otherwise the Software guidelines are pretty straight forward. Seems that you've done great job so far.
Do you mean Eastern GMT-4/5?
GMT +2
- ESP8266 https://www.ebay.com/itm/NodeMCU-Lua-ESP-12-WeMos-D1-Mini-WIFI-4M-Bytes-Development-Board-Module-ESP8266-/321989574625
- NRF24L01+ https://www.ebay.com/itm/For-Arduino-NRF24L01-Wireless-Wifi-Transceiver-2-4GHz-Antenna-Module-200M/192931634959
- NRF24L01+ power board https://www.ebay.com/itm/NRF24L01-Wireless-Adapter-Module-5V-Socket-Adapter-Plate-Board-for-6Pin-51/265033361916
This is what I'm using, feel free to find cheaper alternatives :) While waiting, you can familiarize yourself with VSCode + PlatformIO to compile the firmware first.
China is going into Chinese New Year, so expect 1-2 weeks of additional shipping.
You might also want to check out this thread first https://github.com/RoganDawes/LOGITacker/issues/55#issuecomment-713522457
Basically, have 2 x Logitech C-U0007 dongles flashed to the following firmware:
- 012.001.00019 - ESP8266 can move the mouse and send keystrokes
- 012.001.00032 - ESP8266 can only move the mouse, nothing happens when keystrokes are sent
This led me to try and reverse engineer the dongle firmware 012.001.00032, but I could not get far due to a lack of skill. See my updates here https://www.reddit.com/r/LiveOverflow/comments/g8ajed/reverse_engineering_of_logitech_unifying_firmware/
The dongle firmware is basically an Intel 8051 binary, I was hoping to figure out what has changed in 32 since 19.
Encryption method perhaps? You mentioned AES, maybe they changed from 128 to 256 or vice versa...will check as far as I get the hardware. I'm familiar with VS.Code, but new to PlatformIO. However I guess is nothing different from other frameworks.
Hmm, I'm working based on inference logic here:
- Logitech K270 keyboard's encrypted keystrokes works with 012.001.0019
- Logitech K270 keyboard's encrypted keystrokes works with 012.001.0032
- Firmware in the K270 keyboard remains unchanged, so...
Anyway, I shall not comment further on my opinions, I welcome your fresh perspective on this to hopefully get this resolved. :)
The AES is also quite unlike the typical AES implemented in more serious encryption. I can't remember the details off hand now, but do ask if you have trouble reading my code.
@bilogic
- ESP8266 https://www.ebay.com/itm/NodeMCU-Lua-ESP-12-WeMos-D1-Mini-WIFI-4M-Bytes-Development-Board-Module-ESP8266-/321989574625
- NRF24L01+ https://www.ebay.com/itm/For-Arduino-NRF24L01-Wireless-Wifi-Transceiver-2-4GHz-Antenna-Module-200M/192931634959
- NRF24L01+ power board https://www.ebay.com/itm/NRF24L01-Wireless-Adapter-Module-5V-Socket-Adapter-Plate-Board-for-6Pin-51/265033361916
This is what I'm using, feel free to find cheaper alternatives :) While waiting, you can familiarize yourself with VSCode + PlatformIO to compile the firmware first.
China is going into Chinese New Year, so expect 1-2 weeks of additional shipping.
On these how to properly connect both PCB - should I connect only 5v (VCC power supply rail) and Ground?
Yes, use the 5v for VCC, I have updated the readme.md
WEMOS D1 mini D3 <-> power board CS WEMOS D1 mini D4 <-> power board CE WEMOS D1 mini D5 <-> power board SCK WEMOS D1 mini D6 <-> power board MISO WEMOS D1 mini D7 <-> power board MOSI WEMOS D1 mini 5V <-> power board VCC WEMOS D1 mini GND <-> power board GND
Perfect! Thanks!
@skito just curious, do you plan to disassemble the dongle firmware?
@bilogic I think to give a try to the latest one - ...00032. Will connect with mouse movements first, to be sure that everything is connected properly and then will check up the keys encryption to try improve it. Do you know how to downgrade to ...00019 if I need it?
@skito no idea how to downgrade it. I have 2 dongles myself, one 00019 and the other 00032. I'm re-visiting old notes to see if I might have missed anything simple. I supposed the worst case is to manually flash in the downgrade.
Well the goal here is to have it working with the latest so...I'll got the parts upcoming week.
I wonder what is the "magic key sequence" here https://www.youtube.com/watch?v=EksyCO0DzYs
@bilogic Are there any additional steps for connecting the D1 Mini ESP8266? PlatformIO can recognize the device.

Nevermind, I needed to install additional CH34x driver. Now everything runs correctly and I'm able to send mouse movements to the receiver. So far so good. I'll let you know if any progress.
Great, are you able to send encrypted keystrokes for dongle version 012.001.0019?
My version is 024.001.00023 and yes - I'm able to send the encrypted keystrokes without any modification of your code.
I think 024.001.00023 is meant for another hardware dongle, not C-U0007. In any case, is 024.001.00023 the latest in your series?
Yes - it's the latest one.
This is the dongle:

This is how it finds the device as keyboard.

Interesting, I take that when you select the Unifying Receiver, Update Firmware ends with 024.001.00023.
All I can say is mine still does not work with 012.001.00032
Strange indeed. I bought mine from here: https://amzn.to/3pyggbp
You can try get one as well.
Well, I'm certain buying from your link will work.
My interest is in, what did Logitech do in 012.001.00032 that was able to thwart packets being sent out from our devices. Until we figure that out, this hack remains "incomplete". :)
Whatever they did in 012.001.00032, they could well do the same in the next update to 024.001.00023.
I have some code at https://github.com/BerndGottschlag/goboard/blob/unifying/firmware/main/src/unifying.c based on your code, LOGITacker and mjackit that seems to work just fine with a stick that is reported as RQR12.03_B0025 as well as RQR12.10_B0032. I do not see any immediate differences to your code, but you might want to take a look. I increase the counter on every packet sent, whereas LOGITacker just increases the counter when it receives an ACK, but that should only make a difference when there is substantial packet loss.
@mgottschlag
Was your goboard able to send encrypted keystrokes through a RQR12.10_B0032?
"stick" to me seems to imply a mouse.
yes, it was, I mean the normal unifying receiver USB stick
yes, it was, I mean the normal unifying receiver USB stick
@mgottschlag
Wait, what?
Hmm which microprocessor does your code run on? It was not obvious to me at first glance.
Looks like you are also familiar with PCB design (Something which I'm not)
Ok, let's not get ahead of myself yet until this RQR12.10_B0032 is fixed. :)
My code is currently running on an NRF52840 board (Adafruit Feather NRF52840 Express), and it is able to communicate encrypted keystrokes to the usual unifying receivers with those two versions (in my experience, everything that is plugged into USB without any cable attached is called an "USB stick", which is probably what caused confusion).
@mgottschlag
Ok cool. From what I recall, my code increments with every packet.
Does your code perform all the extra initialization packets?
Those were not very well documented in the other projects and I kind of aggregated them here https://github.com/bilogic/logitech-unifying-device/blob/32b286ed944277fd0fadc646409d622b75e53aeb/src/ludevice.cpp#L790
I'm going to check your codes in a minute. Thank you.
No, I have not implemented reconnecting at all yet - I have not even implemented storing pairing info in a persistent way yet. At the moment, this is just a proof of concept so that I know that it will work later on. Currently it just polls one GPIO and sends a single keycode.
I see, hmm.
So you extracted the AES keys via sniffing or something, and constructed encrypted keystrokes packets which are accepted by the unifying dongle?
No, I did not. I do exactly what you do in your pairing code - I construct an AES key from the dongle's nonce/wpid, the address specified by the dongle and my device's serial number and nonce.
EDIT: This corresponds to luedevice::pair() - ludevice::reconnect() is, after all, only required when you are already paired to the dongle and want to reconnect.
Ok thanks let me find some time to scrutinize this. Thank you.
@bilogic On a more detailed test I can only do mouse movements and media keys. Mouse clicks and other keyboard keys doesn't work...
- @skito Good to know we are on the same page.
- @mgottschlag Can you confirm your code can send A-Z?
- We should examine https://github.com/BerndGottschlag/goboard/blob/unifying/firmware/main/src/unifying.c closely if it is able to send A-Z to
RQR12.10_B0032
Just figure out the mouse clicks. The mouse_payload was wrong.
Should be 0x02 and 0x03 for right and left clicks in ludevice.cpp:865

Ok will fix. Can re-verify the other earlier firmware and see if A-Z works?
@skito
- I went through the mouse code, it doesn't make sense that left click is
0x3, such button detection usually use bits as on/off.
0x2 = B10 // 2nd bit is on
0x3 = B11 // both bits are on, don't make sense
- I checked here too https://github.com/ronangaillard/logitech-mouse/blob/f29452d2ca9783224597d9dee1050bd4a14cfda5/logitech-mouse.cpp#L194
- Just to be absolutely sure, I tested against https://www.onlinemictest.com/mouse-test/ and my conclusion remains that left click is 0x1.
- Also, your code won't be able to detect both left and right clicks together, you have to
|the 2nd part.
if (leftClick)
mouse_payload[2] = 1;
if (rightClick)
mouse_payload[2] |= 2;
@mgottschlag
I went through both our codes, and updated mine with parts of yours, still no luck with A-Z on RQR12.10_B0032.
@skito
Any luck?
@bilogic Yes
0x01 - Left click 0x02 - Right click 0x04 - Middle click
https://gist.github.com/kkusch/245bb80ec4e7ab4d8cdc6b7eeb3f330f https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
The current payloads seems to be working as well, however the problem with the function is far more deeper.
Firstly - the overload method of move, taking the mouse clicks is wrong.

Line ludevice.cpp:845 should be move(x_move, y_move, 0, 0, leftClick, rightClick);
Then the mouse_payload at ludevice.cpp:866 and 869 aren't working every time for my receiver - but only the first time after pairing. After some experimenting with the payload I figure out the if you send a click command you then must send empty payload in order to apply the click.

That works every time for me now. Next week I can make a new branch and commit some improvements to see if they will work for you as well.
oh, yes, low level code requires you to fire click and unclick. Same goes for the keystrokes, press and release.
I will fix the double false, that is definitely a bug, but I don't think I wrote it... only copied from logitech-mouse 🤣🤣🤣
I was more focused on getting keystrokes as my aim is to have a Logitech compatible keyboard.
Well you can always have a touchpad on your keyboard :D Now when the mouse is working properly, I can take a look at the keystrokes.
Haha, ok we will see. I made some commits, see if you wanna pull them. Thanks!
@mgottschlag can confirm your repo is able to send A-Z keystrokes that are accepted by RQR12.10_B0032? Thank you.
Sorry, I wanted to do that yesterday, but did not find the time. I will have access to the prototype again on wednesday, I'll try to test again then.
I do not see why the test would fail, though - during the last test, the dongle accepted multiple key strokes, and I do not know why the dongle should reject other packet content.
@bilogic ist this what you meant? https://github.com/BerndGottschlag/goboard/blob/firmware/firmware/main/src/unifying.c#L492
That code indeed works with RQR12.03_B0025 and RQR12.10_B0032.
@mgottschlag
I can't seem to find the definitions for KEY_RETURN and KEY_A to understand your line of code confidently.
I assume it is going from A to Z until it this KEY_RETURN, so this causes A-Z to show on your host?
Hmm, ok, I will dig at my code harder to find out what is the issue. Thanks!
@mgottschlag would you be able to show me the counter in byte form?
i.e. suppose the counter is 0x12345678, next value would be 0x12345679, is this how you encode it?
encrypted_report[] 07 08 09 10 11 12 13
value xx xx xx 12 34 56 79
I always have trouble with endian-ness. Appreciate your inputs. Thank you!
KEY_A-KEY_RETURN are the HID key codes (src/keycodes.h), so yes, it cycles through a-z0-9
Currently, the initial counter is always 0xdeadc0de. Here are some example key packets - the counter is encrypted as big endian:
<info> app: 00 D3 C3 2E F5 67 ED 80|.....g..
<info> app: 05 F4 DE AD C1 4C 00 00|.....L..
<info> app: 00 00 00 00 00 E2 |......
...
<info> app: 00 D3 D5 86 C5 25 B8 A7|.....%..
<info> app: 7B 56 DE AD C1 4D 00 00|{V...M..
<info> app: 00 00 00 00 00 1F |......
...
<info> app: 00 D3 DF 76 27 91 07 AD|...v'...
<info> app: 83 96 DE AD C1 4E 00 00|.....N..
<info> app: 00 00 00 00 00 B9 |......
...
<info> app: 00 D3 23 95 13 26 24 3F|..#..&$?
<info> app: 7C A8 DE AD C1 4F 00 00||....O..
<info> app: 00 00 00 00 00 1A |......
@mgottschlag thanks! @skito did you manage to make any progress?
@bilogic No, not yet. Didn't had much time to work on it.
@bilogic So far I can tell that mouse payloads don't work neither with firmware 012.009.00030. Only pairing works so far.
@skito Does mouse actions work with RQR12.10_B0032 for you?
@bilogic I don't have RQR12.10_B0032 - only two dongles - 024.001.00023 and new one with 012.009.00030. The new one however works with the latest commit of yours. More specifically line 54 of ludevice.h

When the value is 0xe it works with both dongles. However drag&drop operations times out - when you start drag operation with left or right button it's been interrupted after 1 second.
With value of (1 << 14) drag&drop operations works perfectly, but only on firmware 024.001.00023. Firmware 012.009.00030 doesn't accept mouse movements at all.
So the actual solution here is to keep the mouse down button alive by sending payload every 10 milliseconds. Otherwise the newer firmware of Logitech receiver count it as button release (mouse up). I know that your focus is the keyboard, but this is just FYI. Someone else may have that struggle as well.
@skito feel free to submit PRs if it will make the code better. Thank you.
@mgottschlag can help check if your implementation works with RQR12.10_B0032 when all 6 keys are filled? e.g. abcdef
Not sure if this helps you guys in any way, but have you seen these files? https://lekensteyn.nl/files/logitech/
@rmbirle yes I have, thank you.
@bilogic any updates?
@Tiebe not really