glucometers-tech/glucometer-protocols

Libre 2 Protocol

DreadRoberts opened this issue · 30 comments

I have a Libre 2 and would like to get the data from it. Did you have the chance to look at the protocol of such a device?

I don't have a Libre2 myself to reverse, as it is not available in the UK where I live, which is why there are no specs here for it yet.
If you want to try your luck at taking a look at the protocol and see if it uses the usual FreeStyle base, it might be possible to get it documented still.

Just as some info. I was trying to get data from a Libre 2. I do not have one myself but had to remotely debug.

The libre 2 seems to respond to the commands of the original Libre. Especially reading serial number and stuff works.

But $history? or $arresult? return Garbage. This will return a lot of data, but the content is always the same thing which does not make any sense.

As I do not have a device myself it is hard to debug this any further.

I've added a file with the list of known commands from the previous FreeStyle devices in Flameeyes/glucometerutils@beecba3

You can run it with

./reversing_tools/abbott/freestyle_hid_console.py /dev/hidraw2 < reversing_tools/abbott/known-commands.txt

to generate a log of responses to those. Maybe they use some of the other answers this time around.

Using strings -n 4 $file | LANG=C grep '^\$[a-z][a-z0-9]*[a-z][,?]*$' | LANG=C sort > commands with the firmware file extracted from the MacOSX app, I have built a new list of possible commands.
Since it will take several days (or longer) for me to get hold of the reader device again, perhaps someone else can make some sophisticated use of the list?

I think the Libre 2 is encrypting the data some how with the serial number

Hello DreadRoberts,
how do you come to the conclusion that the data might be encrypted?
Can you share some data with us?

Is it possible that it is the same on Libre1 reader with the most actual firmware 2.4.8 installed?
I now see in Wireshark what you are meaning I think.
With the Libre1 and firmware 2.4.8 I see also at beginning of USB transfer a message saying "ECDHE-RSA-AES256-GCM-SHA384" afterwards the only message is ASCII readable is the message with the serial number of the reader. The rest seems to be encrypted maybe really with the serial number...

My previous paoting is not completely correct, the plain text command "$patch" at the end of the transfer of the original software (Libre1 FW v2.4.8)also seems to report unencrypted data.

Is the firmware automatically updated when the Libre 1 device is connected to the Libre Software?
My current understanding of the process is the following:

  1. Software: request the Serialnumber with the command 0x05
  2. Device: answer to request with 0x06
  3. Software: sending challenge based on the serial number with 0x14
  4. Device: answer to challenge with 0x33

I also wrote a small python script to communicate with the device to test various commands (pywinusb is required):

import pywinusb.hid as hid
import time
import datetime

all_devices = hid.HidDeviceFilter(vendor_id = 0x1a61).get_devices()
target_usage= hid.get_full_usage_id(0xFF00, 0x01)
data_buffer_ascii = []

def response_handler(data):
    global data_buffer
    global data_buffer_ascii
    data_buffer = data[1:]
    data_buffer_ascii = []
    data_buffer_ascii.append("".join(chr(d) for d in data[3:data[2]+2])) # data[2] defines the length of the response

device = all_devices[0]
device.open()
device.set_raw_data_handler(response_handler)

data_sn = [0] * 65
data_sn[1] = 0x05 # serial number
# data[1] = 0x15 software version

device.send_output_report(data_sn)
time.sleep(0.5)
print(data_buffer_ascii)

For a reason that isn't completely clear to me (I'm a Python absolute beginner), the freestyle_hid_console.py script by Flameeyes does not work, as reported in https://github.com/Flameeyes/glucometerutils/issues/68 - but I do have a spare device and am willing to run some more tests if guided appropriately.

@DreadRoberts which (country) site did you manage to find desktop software for the Libre 2? I was provided with a device to test with, but on the German website there's no desktop software at all.

Okay I've spent a few hours looking at this and I have some updates:

  • I'm not entirely convinced this is ECDHE encrypted at least for the Libre2 — I see too many repeated messages in the trace, so my gut feeling is that this is xor-encrypted or something simple like that, but I have no proof to match this.
  • The URBs (USB data) that are sent to the device during handshake are not sent from zeroed memory (not sure if this is a Windows API thing, or app thing), which means that there can be a lot of red herrings there. In my trace, I see references to oftware\Microsoft\Cryptography (which appears to me like a truncated registry key name), and :\Windows\system32\rsaenh.dll, but AFAICT the software uses neither. Following the shared HID protocol definition, that part of the message is ignored anyway.
  • I added an extraction script to help analyze usbmon pcapng traces. With the latest software on Windows and my old Libre device it never seem to throw errors (unlike the Libre2), and it does not seem to be encrypted at all. It may look like it's encrypted because it's using the binary protocol, which is the same as I described at the beginning of my FreeStyle Libre work.

I'll provide updates as I find them.

End of day updates:

I have updated the shared HID protocol with more details, as it looks like the initialisation is much shorter than I thought, for most other devices.

The extraction script is a bit smarter about ignoring the keepalive messages.

It appears to me that the way the software talks with the device is pretty much the same (beside encryption) between Libre 1 and Libre 2, so we have a high likeliness of being able to reuse most code once the encryption is defeated. In particular, while the software is using the binary mode (that I never finished reversing on the Libre 1), it also sends a couple of text commands towards the end of the connection establishment, which it does on the Libre 1 too — on that, they are $sn? and $swver?.

So what about that encryption challenge/response?

Command type 0x14 is not known on any previous devices, nor is, as far as I know, the 0x33 answer it receives. The first byte in both commands appears to be a sub-command. 0x11 appears to be some sort of request to the device, and afaict the device responds with exactly the same bytearray every time, starting with 0x16.

The software then sends a 0x14/0x17 command, which is composed of eight bytes that don't appear to change, and another 17 of them that do. The device responds with 0x33/0x18, eight bytes that change, then 15 that don't, eight that change, and two that are \x00\x20.

I don't seem to be able to get this to replay, but that may be me doing something wrong for now.

The fact that there are a couple of places where there's an eight bytes exchange makes me wonder if it's just AES256.

Silly me — it needs to have 32 bytes to be AES256 — but we have 8 bytes only at best.

At 64-bit encryption, options are fairly limited. DES is an option, but that sounds a bit silly. Unless they use AES with only 8 variable bytes, but even that sounds silly.

We do have quite a bit of plaintext though.

So I have not managed to find time to set up a second VM to check if there's any at-install generation of secret material, here's three separate runs of the connection handshake for my meter: https://gist.github.com/Flameeyes/2008497a37e12fd61fa4429736f7aaa4

Turns out that these are not replayable, because the 0x33/0x18 command sends nonces or other ephemeral keys. But we do have a bit of guessed cleartext to oracle this around if needed.

I'll try to get usbpcap format into usbmon-tools so that the extraction tool works with native Windows capture, I think it's feasible.

Did you pair a sensor with the reader? Could the eight-byte fixed sequence be an encoding of the sensor serial number, as discussed here?
Or is the reader itself communicating in encrypted form, even if no particular sensor is involved?

There is a sensor paired to the reader in the three traces I shared earlier. But that's not affecting the pre-encryption commands, as they behave the same in the first trace I have here, which is without any sensor paired. So I can say that the encryption of the reader communication itself is not at all related to the sensor being used.

In that case, would it help to compare the comm_unic_ation with a different reader, to find out whether the encryption is bound to the hardware or not? (No windows here though.)

So, I just realized I spoke too soon. When I compare the three captures I got for the initialization, two receive the same initial response (which is also the same as my initial capture, not provided), but the third does not.

And indeed, now that I try to reproduce this, I get a different 16 bytes every turn. So maybe that's not some kind of serial but an actual 16-bytes key.

What I know from the sensor is,for Libre2 data structure,there are 2 more parts than Libre1,called PatchInfo(6 bytes) and PatchUID(8 bytes).

PatchUID is constant,but the last 2 bytes of PatchInfo is changing with every read.

I think that the data storeed in Reader also encrypted by the sensor itself,just use the data from sensor to calculate decrypt keys

I played around with the desktop software and noticed something which might be helpful:
If you attach a reader and go to the device settings to update the reader clock, each time you press the "Update" button a new session is started with the device.

And if you press the update button multiple times the software crashes which sometimes leads to unencrypted packets being sent.

So I got some news from a deep dive into the code of the software itself.

  • The encryption is not a simple xor-based one, but is something with HMACs and challenge-response. I've not made progress to figure out what it is and how to reimplement yet, though.
  • The encryption is only applied at the transport layer: once that's identified, the Libre 2 uses the same protocol as Libre 1 — although this does not guarantee that the text based protocol of Libre 1 will work.
  • For future reference, any time Abbott internals refer to "patch" they mean the sensor.

End-of-weekend update:

  • My best guess is that the encryption uses an Encrypt-then-MAC system (EtM).
  • There are two sets of keys that are generated: one for the authentication handshake, and one for the transport encryption. As far as I can tell, they are initialized from the serial number of the reader (not of the patch), and two pair of strings: (AuthrEnc, AuthrMac) for the authentication, (SessnEnc, SessnMac) for the encryption.
  • They are using some (C++?) library for the encryption itself, which was actually built without debug or logging, so that part is slightly harder to understand.

I don't think I'll have any time to work on this in the next ~week or so. If anyone is interested in digging deeper, I can provide partial exports of the data from Ghidra to work on more of it.

Sorry for the late response, I would love to have a look at your ghidra files! I have started a project by myself but maybe you have found something I haven’t

@DreadRoberts if you want a copy hit me by email (email in the repo) and I'll be happy to share.

So I went back to this after a few more months and I have been going through some of the state machine logic to understand it:

  • The CHALLENGE message sent by the device is 15-bytes, but the software only takes the first 8.
  • The CHALLENGE RESPONSE sent by the software is composed of 16-bytes encrypted, a constant 0x01 and 8-bytes MAC.
  • The encrypted 16-bytes are encrypted from the original 8-bytes taken from the CHALLENGE message, followed by 8-bytes of random.
  • The MAC is calculated on the whole 20-bytes rather than just on the encrypted path.

I have not found algorithms it's using. It's definitely using a generic library for the encryption because it has more KDFs than it uses built in.

Also it's either a stream cipher or one with 64-bit blocks. Since my first few captures had the same 15-bytes coming from the device, I can say that the same 8 bytes are always encoded with the same 8 bytes back.

I managed to find more information:

  • The remaining 7 bytes from CHALLENGE are the IV (initialization vector) for the encryption.
  • Each encrypted message (after setup) has four bytes MAC (64-bit MAC algorithm, truncated to 32-bit) and four bytes sequence number (independent between the two devices) that are not encrypted.
  • I've updated extract_freestyle to extract those two metadata pieces from the messages, but still no clue on the algorithms yet.

Hello @Flameeyes
I decided to resurrect this issue to understand the current progress made on decoding the Libre 2 protocol and if you believe it's a feasible task (toy project). My idea was to stream the data to a Garmin device, but from my initial research it seems no one has managed to break the encryption to read the data live.
Thank you very much for your feedback!

Hello @Flameeyes
I am trying to read libre pro-SRAM RF-stack memory but I couldn't access it. the available (nonvolatile) FRAM memory can be entirely covered with the block number range 0x00 to 0xFF of the standard commands which I am able to read the 256 blocks. The upper blocks are located in (volatile) SRAM. Could you please share the command to access these upper blocks in SRAM?

any update in reading SRAM of libre pro