LibreView online reporting service

You may remember I complained about cloud-based solutions before. I have had harsh words about what are to me irresponsible self-hosting suggestions, and I’m not particularly impressed by how every other glucometer manufacturer appears to want their tools to be used, uploading to their cloud solutions what I would expect is a trove of real-world blood sugar reports from diabetics.

But as it happens, since I’m using the FreeStyle LibreLink app on my phone, I get the data uploaded to Abbott’s LibreView anyway. The LibreView service is geo-restricted, so it might not be available in all the countries where FreeStyle Libre is present, which probably is why the standalone Windows app still exists, and why the Libre 2 does not appear to be supported by it.

I haven’t used the service at all until this past month, when I visited the diabetic nurse at the local hospital (I had some blood sugar control issues), and she asked me to connect with their clinic. Turns out that (with the correct authorization), the staff at the clinic can access the real-time monitoring that I get from the phone. Given that this is useful to me, I find this neat, rather than creepy. Also it seems to require authorization on both sides, and it includes an email notification, so possibly they didn’t do that bad of a job with it.

The site is also a good replacement for the desktop app, when using the app with the phone, rather than the reader. It provides the same level of details in the reports, including the “pattern insights”, and a full view of the day-to-day aligned on weeks. Generally, those reports are very useful. And they are available on the site even for yourself, not just for the clinics, which is nice.

Also it turns out that the app tracks how many phones you’ve been using to scan the sensor — in my case, six. Although it’s over 1⅓ years since I have used a different one. I couldn’t see a way to remove the old phones, but at the same time, they are not reporting anything in and they don’t seem to have a limit on how many you can have.

Overall it’s effectively just a web app version of the information that was already available on the phone (but hard to extract and share) or on the reader (if you are still using that). I like the interface and it seems fairly friendly.

Also, you may remember (or notice, if you read the links above) that I had taken an aside pointing out how Diabetes Ireland misunderstood the graphs shown in the report when the Libre reached Ireland. I guess they were not alone, because in this version of the report Abbott explicitly labels the 10th-90th percentile highlight, the 25th-75th percentile highlight, and the median line. Of course this assumes that whoever is reading the graph is aware of “percentile” and “median” stand for — but that’s at least a huge step in the right direction.

Leveling up my reverse engineering: time for Ghidra

In my quest to figure out how to download data from the Abbott FreeStyle Libre 2, I decided that figuring it out just by looking at the captures was a dead end. While my first few captures had me convinced the reader would keep sending the same challenge, and so I could at least replay that, it turned out to be wrong, and that excluded most of the simplest/silliest of encryption schemes.

As Pierre suggested me on Twitter, the easiest way to find the answer would be to analyze the binary itself. This sounded like a hugely daunting task for myself, as I don’t speak fluent Intel assembly, and particularly I don’t speak fluent Windows interfaces. The closest I got to this in the past has been the reverse engineering of the Verio, in which I ran the software on top of WinDbg and discovered, to my relief, that they not just kept some of the logging on, but also a whole lot of debug logs that made it actually fairly easy to reverse the whole protocol.

But when the options are learning enough about cryptography and cryptanalysis to break the encoding, or spend time learning how to reverse engineer a Windows binary — yeah I thought the latter would suit me better. It’s not like I have not dabbled in reversing my own binaries, or built my own (terrible) 8086 simulator in high school, because I wanted to be able to see how the registers would be affected, and didn’t want to wait for my turn to use the clunky EEPROM system we used in the lab (this whole thing is probably a story for another day).

Also, since the last time I considered reversing a binary (when I was looking at my laptop’s keyboard), there’s a huge development: the NSA released Ghidra. For those who have not heard, Ghidra is a tool to reverse engineer binaries that includes a decompiler, and a full blown UI. And it’s open source. Given that the previous best option for this was IDA Pro, with thousands of dollars of licenses expected, this opened a huge amount of doors.

So I spent a weekend in which I had some spare time to try my best on reversing the actual code coming from the official app for the Libre 2 — I’ll provide more detail of that once I understand it better, and I know which parts are critical to share, and which one would probably get me in trouble. In general, I did manage to find out quite a bit more about the software, the devices, and the protocol — if nothing else, because Abbott left a bunch of debug logging disabled, but built in (and no, this time the WinDbg trick didn’t work because they seems to have added an explicit anti-debugger exception (although, I guess I could learn to defeat that, while I’m at it).

Because I was at first a bit skeptical about my ability to do anything at all with this, I also have been running it in an Ubuntu VM, but honestly I’m considering switching back to my normal desktop because something on the Ubuntu default shell appears to mess with Java, and I can’t even run the VM at the right screen size. I have also considered running this in a Hyper-V virtual machine on my Gamestation, but the problem with that appears to be graphics acceleration: installing OpenSUSE onto it was very fast, but trying to use it was terribly sloppy. I guess the VM option is a bit nicer in the sense that I can just save it to power off the computer, as I did to add the second SSD to the NUC.

After spending the weekend on it, and making some kind of progress, and printing out some of the code to read it on paper in front of the TV with pen and marker, well… I think I’m liking the idea of this but it’ll take me quite a while, alone, to come up with enough of a description that it can be implemented cleanroom. I’ll share more details on that later. For the most part, I felt like I was for the first time cooking something that I’ve only seen made in the Great British Bake Off — because I kept reading the reports that other (much more experienced) people wrote and published, particularly reversing router firmwares.

I also, for once, found a good reason to use YouTube for tutorials. This video by MalwareTech (yes the guy who got arrested after shutting WannaCry down by chance) was a huge help to figure out features I didn’t even know I wanted, including the “Assume Register” option. Having someone who knows what he’s doing explore a tool I don’t know was very helpful, and indeed it felt like Adam Savage describing his workshop tools — a great way to learn about stuff you didn’t know you needed.

My hope is that by adding this tool to my toolbox – like Adam Savage indeed says in his Every Tool’s A Hammer (hugely recommended reading, by the way) – is that I’ll be able to use it not just to solve the mystery of the Libre 2’s encryption. But also that of the nebulous Libre 1 binary protocol, which I never figured out (there’s a few breadcrumbs I already found during my Ghidra weekend). And maybe even to figure out the protocol of one of the gaming mice I have at home, which I never completed either.

Of course all of this assumes I have a lot more free time than I have had for the past few years. But, you know, it’s something that I might have ideas about.

Also as a side note: while doing the work to figure out which address belongs to what, and particularly figure out the jumps through vtables and arrays of global objects (yeah that seems to be something they are doing), I found myself needing to do a lot of hexadecimal calculations. And while I can do conversions from decimal to binary in my head fairly easily, hex is a bit too much for me. I have been using the Python interactive interpreter for that, but that’s just too cumbersome. Instead, I decided to get myself a good old physical calculator — not least because the Android calculator is not able to do hex, and it seems like there’s a lack of “mid range” calculators: you get TI-80 emulators fairly easily, but most of the simplest calculators don’t have hex. Or they do, but they are terrible at it.

I looked up on Amazon for the cheapest scientific calculator that I could see the letters A-F on, and ordered a Casio fx-83GT X — that was a mistake. When it arrived, I realized that I didn’t pay attention to finding one with the hex key on it. The fx-83GT does indeed have the A-F inputs — but they are used for defining variables only, and the calculator does not appear to have any way to convert to hexadecimal nor to do hexadecimal-based operations. Oops.

Instead I ordered a Sharp WriteView EL-W531, which supports hex just fine. It has slightly smaller, but more satisfying, keys, but it’s yet another black gadget on my table (the Casio is light blue). I’ll probably end up looking out for a cute sticker to put on it to see it when I close it for storage.

And I decided to keep the Casio as well — not just because it’s handy to have a calculator at home when doing paperwork, even with all the computers around, but also because it might be interesting to see how much of the firmware is downloadable, and whether someone has tried flashing a different model’s firmware onto it, to expand its capabilities: I can’t believe the A-F keys are there just for the sake of variables, my guess is that they are there because the same board/case is used by a higher model that does support hex, and I’d expect that the only thing that makes it behave one way or the other is the firmware — or even just flags in it!

At any rate, expect more information about the Libre 2 later on this month or next. And if I decide to spend more time on the Casio as well, you’ll see the notes here on the blog. But for now I think I want to get at least some of my projects closer to completion.

FreeStyle Libre 2: encrypted protocol notes

When I had to write (in a hurry) my comments on Abbott’s DMCA notice to GitHub, I note that I have not had a chance to get my hands onto the Libre 2 system yet, because it’s not sold in the UK. After that, Benjamin from MillionFriends reached out to me to hear if I would be interested in giving a try to figure out how the reader itself speaks with the software. I gladly obliged, and spent most of the time I had during a sick week to get an idea of where we are with this.

While I would lie if I said that we’re now much closer to be able to download data from a Libre 2 reader, I can at least say that we have some ideas of what’s going on right now. So let me try to introduce the problem a second, because there’s a lot of information out there, and while there’s some of it that is quite authoritative (particularly as a few people have been reverse engineering the actual binaries), a lot of it is guesswork and supposition.

The Libre and Libre 2 systems are very similar — they both have sensors, and they both have readers. Technically, you could say that the mobile app (for Android or iOS) also makes up part of the system. The DMCA notice from Abbott that stirred so much trouble above was related to modifications to the mobile application — but luckily for me, my projects and my interests lay quite far away from that. The sensors can be “read” by their respective reader devices, or with a phone with the correct app on it. When reading the sensors with the reader, the reader itself stores the historical data and a bunch more information. You can download that data from the reader onto a computer with Windows or macOS with the official software from Abbott (assuming you can download a version of it that works for you, I couldn’t find a good download page for this on the UK website, but I was provided an EU version of the software as well.)

For the Libre system, I have attempted reversing the protocol, but ultimately it was someone else contributing the details of an usable protocol that I implemented in glucometerutils. For the Libre 2, the discussion already suggested it wouldn’t be the same protocol, and that encryption was used by the Libre 2 reader. As it turns out, Abbott really does not appear to appreciate customers having easy access to their data, or third parties building tools around their devices, and they started encrypting the communication between the sensors and the reader or app in the new system.

So what’s the state with the Libre 2? Well, one of the good news is that the software that I was given works with both the Libre and Libre 2 systems, so I could compare the USB captures on both systems, and that will (as I’ll show in a moment) help significantly. It also showed that the basics of the Abbott HID protocol were maintained: most of the handshake, the message types and the maximum message size. Unfortunately it was clear right away that indeed most of the messages exchanged were encrypted, because the message length made no sense (anything over 62 as length was clearly wrong).

Now, the good news is that I have built up enough interfaces in usbmon-tools that I could use to build a much more reusable extractor for the FreeStyle protocol, and introduce more of the knowledge of the encryption to it, so that it can be used for others. Being able to release these extraction tools I write, instead of just using them myself and letting them rot, was my primary motivation behind building usbmon-tools, so you could say that that’s an achieved target.

So earlier I said that I was lucky the software works with both the Libre and Libre 2 readers. The reason why that was luck, it’s because it shows that the sequence of operations between the two is nearly the same, and that some of the messages are not actually encrypted on the Libre 2 either (namely, the keepalive messages). Here’s the handshake from my Libre 1 reader:

[ 04] H>>D 00000000: 

[ 34] H<<D 00000000: 16                                                . 

[ 0d] H>>D 00000000: 00 00 00 02                                       .... 

[ 05] H>>D 00000000: 

[ 15] H>>D 00000000: 

[ 06] H<<D 00000000: 4A 43 4D 56 30 32 31 2D  54 30 38 35 35 00        JCMV021-T0855. 

[ 35] H<<D 00000000: 32 2E 31 2E 32 00                                 2.1.2. 

[ 01] H>>D 00000000: 

[ 71] H<<D 00000000: 01                                                . 

[ 21] H>>D 00000000: 24 64 62 72 6E 75 6D 3F                           $dbrnum? 

[ 60] H<<D 00000000: 44 42 20 52 65 63 6F 72  64 20 4E 75 6D 62 65 72  DB Record Number
[ 60] H<<D 00000010: 20 3D 20 33 37 32 39 38  32 0D 0A 43 4B 53 4D 3A   = 372982..CKSM:
[ 60] H<<D 00000020: 30 30 30 30 30 37 36 31  0D 0A 43 4D 44 20 4F 4B  00000761..CMD OK
[ 60] H<<D 00000030: 0D 0A                                             .. 

[ 0a] H>>D 00000000: 00 00 37 C6 32 00 34                              ..7.2.4 

[ 0c] H<<D 00000000: 01 00 18 00                                       .... 

Funnily enough, while this matches the sequence that Xavier described for the Insulinx, and that I always reused for the other devices too, I found that most of this exchange is for the original software to figure out which device you connected. And since my tools require you to know which device you’re using, I actually cleaned up the FreeStyle support code in glucometerutils to shorten the initialization sequence.

To describe the sequence in prose, the software is requesting the serial number and software version of the reader (commands 0x05 and 0x15), then initializing (0x01) and immediately using the text command $dbrnum? to know how much data is stored on the device. Then it starts using the “binary mode” protocol that I started on years ago, but never understood.

For both the systems, I captured the connection establishment, from when the device is connected to the Windows virtual machine to the moment when you can choose what to do. The software is only requesting a minimal amount of data, but it’s still quite useful for comparison. Indeed, you can see that after using the binary protocol to fetch… something, the software sends a few more text commands to confirm the details of the device:

[ 0b] H<<D 00000000: 12 3C AD 93 0A 18 00 00  00 00 00 9C 2D EA 00 00  .<..........-...
[ 0b] H<<D 00000010: 00 00 00 0E 00 00 00 00  00 00 00 7C 2A EA 00 00  ...........|*...
[ 0b] H<<D 00000020: 00 00 00 16 00 00 00 00  00 00 00 84 2D EA 00 21  ............-..!
[ 0b] H<<D 00000030: C2 25 43                                          .%C 

[ 21] H>>D 00000000: 24 70 61 74 63 68 3F                              $patch? 

[ 0d] H>>D 00000000: 3D 12 00 00                                       =... 

[ 60] H<<D 00000000: 4C 6F 67 20 45 6D 70 74  79 0D 0A 43 4B 53 4D 3A  Log Empty..CKSM:
[ 60] H<<D 00000010: 30 30 30 30 30 33 36 38  0D 0A 43 4D 44 20 4F 4B  00000368..CMD OK
[ 60] H<<D 00000020: 0D 0A                                             .. 

[ 21] H>>D 00000000: 24 73 6E 3F                                       $sn? 

[ 60] H<<D 00000000: 4A 43 4D 56 30 32 31 2D  54 30 38 35 35 0D 0A 43  JCMV021-T0855..C
[ 60] H<<D 00000010: 4B 53 4D 3A 30 30 30 30  30 33 32 44 0D 0A 43 4D  KSM:0000032D..CM
[ 60] H<<D 00000020: 44 20 4F 4B 0D 0A                                 D OK.. 

[ 21] H>>D 00000000: 24 73 77 76 65 72 3F                              $swver? 

[ 60] H<<D 00000000: 32 2E 31 2E 32 0D 0A 43  4B 53 4D 3A 30 30 30 30  2.1.2..CKSM:0000
[ 60] H<<D 00000010: 30 31 30 38 0D 0A 43 4D  44 20 4F 4B 0D 0A        0108..CMD OK.. 

My best guess on why it’s asking again for serial number and software version, is that the data returned during the handshake is only used to select which “driver” implementation to use, while this is used to actually fill in the descriptor to show to the user.

If I look at the capture of the same actions with a Libre 2 system, the initialization is not quite the same:

[ 05] H>>D 00000000: 

[ 06] H<<D 00000000: 4D 41 47 5A 31 39 32 2D  4A 34 35 35 38 00        MAGZ192-J4558. 

[ 14] H>>D 00000000: 11                                                . 

[ 33] H<<D 00000000: 16 B1 79 F0 A1 D8 9C 6D  69 71 D9 1A C0 1A BC 7E  ..y....miq.....~ 

[ 14] H>>D 00000000: 17 6C C8 40 58 5B 3E 08  A5 40 7A C0 FE 35 91 66  .l.@X[>..@z..5.f
[ 14] H>>D 00000010: 2E 01 37 88 37 F5 94 71  79 BB                    ..7.7..qy. 

[ 33] H<<D 00000000: 18 C5 F6 DF 51 18 AB 93  9C 39 89 AC 01 DF 32 F0  ....Q....9....2.
[ 33] H<<D 00000010: 63 A8 80 99 54 4A 52 E8  96 3B 1B 44 E4 2A 6C 61  c...TJR..;.D.*la
[ 33] H<<D 00000020: 00 20                                             .  

[ 04] H>>D 00000000: 

[ 0d] H>>D 00000000: 00 00 00 02                                       .... 

[ 34] H<<D 00000000: 16                                                . 

[ 05] H>>D 00000000: 

[ 15] H>>D 00000000: 

[ 06] H<<D 00000000: 4D 41 47 5A 31 39 32 2D  4A 34 35 35 38 00        MAGZ192-J4558. 

[ 35] H<<D 00000000: 31 2E 30 2E 31 32 00                              1.0.12. 

[ 01] H>>D 00000000: 

[ 71] H<<D 00000000: 01                                                . 

[x21] H>>D 00000000: 66 C2 59 40 42 A5 09 07  28 45 34 F2 FB 2E EC B2  f.Y@B...(E4.....
[x21] H>>D 00000010: A0 BB 61 8D E9 EE 41 3E  FC 24 AD 61 FB F6 63 34  ..a...A>.$.a..c4
[x21] H>>D 00000020: 7B 7C 15 DB 93 EA 68 9F  9A A4 1E 2E 0E DE 8E A1  {|....h.........
[x21] H>>D 00000030: D6 A2 EA 53 45 2F A8 00  00 00 00 17 CF 84 64     ...SE/........d 

[x60] H<<D 00000000: 7D C1 67 28 0E 31 48 08  2C 99 88 04 DD E1 75 77  }.g(.1H.,.....uw
[x60] H<<D 00000010: 34 5A 88 CA 1F 6D 98 FD  79 42 D3 F2 4A FB C4 E8  4Z...m..yB..J...
[x60] H<<D 00000020: 75 C0 92 D5 92 CF BF 1D  F1 25 6A 78 7A F7 CE 70  u........%jxz..p
[x60] H<<D 00000030: C2 0F B9 A2 86 68 AA 00  00 00 00 F9 DE 0A AA     .....h......... 

[x0a] H>>D 00000000: 9B CA 7A AF 42 22 C6 F2  8F CA 0E 58 3F 43 9C AB  ..z.B".....X?C..
[x0a] H>>D 00000010: C7 4D 86 DF ED 07 ED F4  0B 99 D8 87 18 B5 8F 76  .M.............v
[x0a] H>>D 00000020: 69 50 4F 6C CE 86 CF E1  6D 9C A1 55 78 E0 AF DE  iPOl....m..Ux...
[x0a] H>>D 00000030: 80 C6 A0 51 38 32 8D 01  00 00 00 62 F3 67 2E     ...Q82.....b.g. 

[ 0c] H<<D 00000000: 01 00 18 00                                       .... 

[x0b] H<<D 00000000: 80 37 B7 71 7F 38 55 56  93 AC 89 65 11 F6 7F E6  .7.q.8UV...e....
[x0b] H<<D 00000010: 31 03 3E 15 48 7A 31 CC  24 AD 02 7A 09 62 FF 9C  1.>.Hz1.$..z.b..
[x0b] H<<D 00000020: D4 94 02 C9 5F FF F2 7B  3B AC F0 F7 99 1A 31 5A  ...._..{;.....1Z
[x0b] H<<D 00000030: 00 B8 7B B7 CD 4D D4 01  00 00 00 E2 D4 F1 13     ..{..M......... 

The 0x14/0x33 command/response are new — and they clearly are used to set up the encryption. Indeed, trying to send out a text command without having issued these commands has the reader respond with a 0x33 reply that I interpret as a “missing encryption” error.

But you can also see that there’s a very similar structure to the commands: after the initialization, there’s an (encrypted) text command (0x21) and response (0x60), then there’s an encrypted binary command, and more encrypted binary responses. Funnily enough, that 0x0c response is not encrypted, and the sequence of responses of the same type is very similar between the Libre 1 and Libre 2 captures as well.

The similarities don’t stop here. Let’s look at the end of the capture:

[x0b] H<<D 00000000: A3 F6 2E 9D 4E 13 68 EB  7E 37 72 97 6C F9 7B D6  ....N.h.~7r.l.{.
[x0b] H<<D 00000010: 1F 7B FB 6A 15 A8 F9 5F  BD EC 87 BC CF 5E 16 96  .{.j..._.....^..
[x0b] H<<D 00000020: EB E7 D8 EC EF B5 00 D0  18 69 D5 48 B1 D0 06 A6  .........i.H....
[x0b] H<<D 00000030: 30 1E BB 9B 04 AC 93 DE  00 00 00 B6 A2 4D 23     0............M# 

[x21] H>>D 00000000: CB A5 D7 4A 6C 3A 44 AC  D7 14 47 16 15 40 15 12  ...Jl:D...G..@..
[x21] H>>D 00000010: 8B 7C AF 15 F1 28 D1 BE  5F 38 5A 4E ED 86 7D 20  .|...(.._8ZN..} 
[x21] H>>D 00000020: 1C BA 14 6F C9 05 BD 56  63 FB 3B 2C EC 9E 3B 03  ...o...Vc.;,..;.
[x21] H>>D 00000030: 50 B1 B4 D0 F6 02 92 14  00 00 00 CF FA C2 74     P.............t 

[ 0d] H>>D 00000000: DE 13 00 00                                       .... 

[x60] H<<D 00000000: CE 96 6D CD 86 27 B4 AC  D9 46 88 90 C0 E7 DB 4A  ..m..'...F.....J
[x60] H<<D 00000010: 8D CC 8E AA 5F 1B B6 11  4E A0 2B 08 C0 01 D5 D3  ...._...N.+.....
[x60] H<<D 00000020: 7A E9 8B C2 46 4C 42 B8  0C D7 52 FA E0 8F 58 32  z...FLB...R...X2
[x60] H<<D 00000030: DE 6C 71 3F BE 4E 9A DF  00 00 00 7E 38 C6 DB     .lq?.N.....~8.. 

[x60] H<<D 00000000: 11 06 1C D2 5A AC 1D 7E  E3 4C 68 B2 83 73 DF 47  ....Z..~.Lh..s.G
[x60] H<<D 00000010: 86 05 4E 81 99 EC 29 EA  D8 79 BA 26 1B 13 98 D8  ..N...)..y.&....
[x60] H<<D 00000020: 2D FA 49 4A DF DD F9 5E  2D 47 29 AB AE 0D 52 77  -.IJ...^-G)...Rw
[x60] H<<D 00000030: 2E EB 42 EC 7E CF BB E0  00 00 00 FE D4 DC 7E     ..B.~.........~ 

… Yeah many more encrypted messages …

[x60] H<<D 00000000: 53 FE E5 56 01 BB C2 A7  67 3E A6 AB DB 8E B7 13  S..V....g>......
[x60] H<<D 00000010: 6D F7 80 5C 06 23 09 3E  49 B4 A7 8B D3 61 92 C9  m..\.#.>I....a..
[x60] H<<D 00000020: 72 1D 5A 04 AE E3 3E 05  2E 1B C7 7C 42 2D F8 42  r.Z...>....|B-.B
[x60] H<<D 00000030: 37 88 7E 16 D9 34 8B E9  00 00 00 11 EE 42 05     7.~..4.......B. 

[x21] H>>D 00000000: 01 84 3F 02 36 1E A6 82  E2 C5 BF C2 40 78 B9 CD  ..?.6.......@x..
[x21] H>>D 00000010: E9 55 17 BE E9 16 8A 52  D2 D9 85 69 E4 D5 96 7A  .U.....R...i...z
[x21] H>>D 00000020: 55 6D DF 2E AF 96 36 53  64 C5 C7 D1 B6 6F 1A 1A  Um....6Sd....o..
[x21] H>>D 00000030: 4F 2F 25 FF 58 F4 EE 15  00 00 00 F6 9A 52 64     O/%.X........Rd 

[x60] H<<D 00000000: 19 F4 D4 F0 66 11 E3 CE  47 DE 82 87 22 48 3C 8D  ....f...G..."H<.
[x60] H<<D 00000010: BA 2D C0 37 12 25 CD AB  3A 58 C2 C4 01 88 60 21  .-.7.%..:X....`!
[x60] H<<D 00000020: 15 1E D1 EE F2 90 36 CA  B0 93 92 34 60 F5 89 E0  ......6....4`...
[x60] H<<D 00000030: 64 3C 20 39 BF 4C 98 EA  00 00 00 A1 CE C5 61     d< 9.L........a 

[x21] H>>D 00000000: D5 89 18 22 97 34 CB 6E  76 C5 5A 23 48 F4 5E C6  ...".4.nv.Z#H.^.
[x21] H>>D 00000010: 0E 11 0E C9 51 BD 40 D7  81 4A DF 8A 0B EF 28 82  ....Q.@..J....(.
[x21] H>>D 00000020: 1F 14 47 BC B8 B8 FA 44  59 7A 86 14 14 4B D7 0F  ..G....DYz...K..
[x21] H>>D 00000030: 37 48 CC 1F C5 A2 9E 16  00 00 00 00 A3 EE 69     7H............i 

[x60] H<<D 00000000: 62 33 4B 90 3B 68 3A D1  01 B1 15 4C 48 A1 6E 20  b3K.;h:....LH.n 
[x60] H<<D 00000010: 12 6F BC D5 50 33 9E C3  CC 35 4E C8 46 81 3E 6B  .o..P3...5N.F.>k
[x60] H<<D 00000020: 96 17 DF D5 8C 22 5C 3A  B7 52 C2 D9 37 71 B7 E2  ....."\:.R..7q..
[x60] H<<D 00000030: 5F C4 88 81 2A 91 65 EB  00 00 00 69 E2 A8 DE     _...*.e....i... 

These are once again text commands. In particular one of them gets a response that is long enough to span multiple encrypted text responses (0x60). Given that the $patch? command on the Libre 1 suggested it’s a multirecord command, it might be that the Libre 2 actually has a long list of patches.

So my best guess of this is that, aside for the encryption, the Libre 2 and Libre 1 systems are actually pretty much the same. I’m expecting that the only thing between us and being able to download the data out of a Libre 2 system is to figure out the encryption scheme and whether we need to extract keys to be able to do so. In the latter case that is something we should proceed carefully with, because it’s probably going to be the way Abbott is going to enforce their DMCA requests.

What do we know about the encryption setup, then? Well, I had a theory, but then it got completely trashed. I still got some guesses that for now appear solid.

First of all, the new 0x14/0x33 command/reply: this is called multiple time by the software, and the reader uses the 0x33 response to tell you either the encryption is missing or wrong, so I’m assuming these commands are encryption related. But since there’s more than one meaning for these commands, it looks like the first byte for each of these selects a “sub-command”.

The 0x14,0x11 command appears to be the starting point for the encryption; the device responds with what appears to be 15 random bytes. Not 16! The first byte again appears to be a “typing” specification and is always 0x16. You could say that the 0x14,0x11 command gets a 0x33,0x16 response. In the first three captures I got from the software, the device actually sent exactly the same bytes. Then it started giving a different response for each time I called it. So I guess it might be some type of random value, that needs some entropy to be re-generated. Maybe it’s a nonce for the encryption?

The software then sends a 0x14,0x17 command, which at first seemed to have a number of constant bytes in positions, but now I’m not so sure. I guess I need to compare more captures for that to be the case. But because of the length, there’s at most 25 bytes that are sent to the device.

The 0x33,0x18 response comes back, and it includes 31 bytes, but the last two appear to be constant.

Also if I compare the three captures, two that received the same 0x33,0x16 response, and one that didn’t, there are many identical bytes between the two with the same response (but not all of them!), and very few with the third one. So it sounds like either this is a challenge-response that uses the provided nonces, or it actually uses that value to do the key derivation.

If you’re interested in trying to figure out the possible encryption behind this, the three captures are available on GitHub. And if you find anything else that you want to share with the rest of the people looking at this, please let us know.

Abbott, the Libre 2, and the takedown

A few people today messaged and mentioned me on twitter regarding the news that Abbott has requested the takedown of something related to their Libre 2. I gave a quick hot take on this on Twitter, but I guess it’s worth having something in long form to be referenced, since I’m sure this will be talked about a lot more, not least because of the ominous permalink chosen by Boing Boing (“they-literally-own-you”) and the fact that, game of telephone style, the news went from the original takedown, to Reddit phrasing it as “Abbott asserts copyright on your data”, which is both silly and untrue.

So let’s start with a bit of background, that most of the re-posters of this story probably don’t know much about. The Libre 2 is an upgrade on the FreeStyle Libre system that I wrote a lot about and that I use daily. It comes with both a reader device and with support in the LibreLink app for both Android and (on more recent iPhones) iOS. The main difference with the Libre system is that the sensors provide both NFC and BLE capabilities, with the ability to proactively notify of high- or low-blood sugar conditions, that the old NFC-only sensors cannot provide, which is more similar to CGM solutions like Dexcom‘s.

In both the Libre and Libre 2 systems, the sensors don’t report blood sugar values, like in most classic glucometers. Instead they report a number of “raw” values, including from a number of temperature sensors. There’s a great explanation of these from Pierre Vandevenne, here and here. To get a real blood sugar measurement, you need to apply some algorithm, that Abbott still refines. The algorithm is what I usually refer to as “secret sauce”, and is implemented in both the reader’s firmware and the LibreLink app itself.

Above I used the word “something” to refer to what was taken down. The reason why I say that is that Boing Boing in the title straight up calls this a “tool” — but when you read the linked post from the affected person, it is described as “details of how to patch the LibreLink app”. Since I have not seen what the repository was before it was taken down, I have no idea which one to believe exactly. In either case, it looks like Abbott does not like someone to effectively leverage their “secret sauce” to use in a different application, but in particular, it does not look like we’re talking about something like glucometerutils, that implemented the protocol “clean”, without derivation off the original software.

Indeed, Boing Boing seems to make a case that this is equivalent of implementing a file format: «[…] just because Apple’s Pages can read Word docs, it doesn’t mean that Pages is a derivative of MS Office.» Except that it’s not as clear cut. If you implemented support for one format by copying the implementation code into your software, that actually would make it a derivative work, quite obviously. In this case, if I am to believe the original report instead, the taken down content were instructions to modify Abbott’s app — and not a redistribution of it. Since I’m not a lawyer, I have no idea where that stands, but it’s clearly not as black-and-white as Boing Boing appears to make it.

As I said on twitter, this does not affect either of my projects, since neither is relying on the original software, and are rather descriptions of the protocols. They also don’t include any information or support for the Libre 2, since the protocol appears to have changed. There’s an open issue with discussion, but it also appears that this time Abbott is using some encryption on the protocol. And that might be an interesting problem, as someone might have to get up close and personal with the code to figure that part out — but if that’s the case, we’re back at needing a clean-room design for implementing it.

I also want to quote Pierre explicitly from the posts I linked above:

[…] in the Libre FRAM, what we are seeing is a real “raw” signal. While the measure of the glucose signal itself is fairly reliable, it is heavily post-processed by the Libre firmware. Specifically – and in no particular order – temperature compensation, delay compensation, de-noising… all play a role. That understanding and, to some extent, my MD training, led me to extreme caution and prevented me from releasing my “solution”, which I knew to be both incomplete and unable to handle some error conditions.

The main driver behind my decision was the well known “first do no harm” (primum non nocere) motto, an essential part of the Hippocratic Oath which I symbolically took. I still stick by it today. […]

[…]

Today, there are a lot of add-on devices that aim to transform the Libre into a full CGM. To be honest, in general, I do not like either the results they provide or their (in)convenience. None of those I have tried delivered results that would lead to an approval by a regulatory agency, none of them were stable for long periods of time. But, apparently, patients still feel they are helpful and there is now a thriving community that aims at improving them.

Pierre Vandevenne

While I have not sworn a Hippocratic Oath myself, I have similar concerns to Pierre, and I have explicitly avoided documenting the sensors’ protocol, and I won’t be merging code that tries to read them directly, even if provided.

And when it comes to copyright issues, I do weigh them fairly heavily: they are the fundamental way that Free Software even works, by respecting licenses. So I will prefer someone to provide me with the description of Abbott’s encryption protocol, rather than an implementation of it where I may be afraid of a “poisonous tree.”

A FreeStyle Libre Update

The last time I wrote anything interesting about Abbott’s flash glucose monitor (don’t call it a CGM) was when I compared it with the underwhelming Dexcom G6. I thought it would be a good time to provide an update, what with Abbott sending a number of email reminding you to update their FreeStyle LibreLink app in the past couple of weeks.

First of all, there’s the matter of supplies. Back in January, I decided to test Dexcom’s CGM because Abbott’s supply issues bit me in the backside, as I could not get new sensors to keep up with my usage — particularly as the more active life in London with my girlfriend meant losing a couple more sensors to mistakes, such as bumping into the doorframe. For a while, you could only buy three sensors every 25 days, and even then, sometimes the lead time to fulfill the order would be over a week; nowadays this appears to be much better, and the time limit for the orders was removed recently.

Since I was not particularly thrilled to switch to the Dexcom G6, I had to find a way around these limits, beside counting on the two extra sensors I “gained” by not using the Libre for a month. Luck was that a friend of my girlfriend found the Libre sensors on sale in a brick-and-mortar store in Sharjah, and managed to send me six of them. The store had no limits on how many sensors you could buy, despite the FreeStyle UK website only allowing orders of three at most, and only to already-established customers.

The UAE-bought sensors are effectively the same as the British ones, with the same manufacturing information printed on them, and even similar enough lot numbers. The most visible difference is that the two alcohol-soaked tissues, provided for cleaning the insertion point, are missing.

The other difference is not visible in the packaging, or indeed on the hardware itself: the sensors are region-locked. Or maybe we should say that the app is. As it is, my (UK) FreeStyle LibreLink install did not want to set up the UAE-bought sensors. The reader device had no such concern and both initialised and read them just fine. I was originally a bit concerned and spot-checked the values with fingersticks, but it looked like there was no issue with the sensors at all.

I’ve been wondering just how much the supply problem connects with the region locking. Or just how fine-grained the region locking is: my Irish sensors worked perfectly fine with the UK app, although by that point, the app was not available in Ireland at all. But possibly all of these problems are gone.

Now, to go back to Abbott’s email messages to update their LibreLink app. The reason for this update is not much about the UI of the app itself – although that did change a bit, in subtle and annoying ways – but rather a change in their algorithm for turning the sensors’ readings into a human-understandable blood glucose reading. The “curve”, as it’s sometimes referred to. It’s important to note that what the sensors communicate with either the app or the reader device are not “fully cooked” blood sugar readings, but rather a set of different sensors reading, and that the app and reader will then apply some formulas to provide an equivalent reading to a fingerstick.

Much more interesting to me, in the announcement of the new curve, is that they also suggest users to update the firmware of reader devices to make use of the new fine-tuned algorithm. This is interesting because it makes the FreeStyle Libre the first glucometer with an upgradeable firmware. I have not actually run the update myself, yet. It needs to be done just before changing the sensor, as the reader will forget about its last sensor at that point, and I’m a bit worried that it might not work with UAE-bought sensors anymore after that. So I’m instead waiting to finish the supply of those sensors, and maybe get another one later to test after the update.

I also want to try to get a usbmon trace of the whole procedure for the firmware update. I’m not sure when Abbott will ever publish another update for the reader, but at least starting collecting the protocol would be interesting. Once I do that, you can expect another blog post on the topic.

And as a final note, glucomterutils is being updated as I type this to support reading and setting patient names. While I would not suggest people to use that field for their own personal glucometer, I thought it would be nice to provide the building block for more doctor-focused apps to be built out of it. As a reminder, the code is released under the MIT license, because using it to build something else is a primary focus of it — we need better tooling for glucometers, and not just in the Free Software world, but in the world in general!

Dexcom G6: new phone and new sensor

In the previous posts on the Dexcom G6, I’ve talked about the setup flow and the review after a week, before the first sensor expired. This was intentional because I wanted to talk about the sensor replacement flow separately. Turns out this post will also have a second topic to it, which came by by chance: how do you reconfigure the app when you change phone or, like it happened to me this time, when you are forced to do a factory reset.

I won’t go into the details of why I had to do a factory reset. I’ll just say that the previous point about email and identities was involved.

So what happens when the Dexcom is installed on a new phone, or when you have to reinstall this? The first thing it will ask you is to login again, which is the easy part. After that, though, it will ask you to scan the sensor code. Which made no sense to me! I said “No Code”, and then it asked me to scan the transmitter code. At which point it managed to pair with the transmitter, and it showed me the blood sugar readings for the past three hours. I can assume this is the amount of caching the transmitter can do. If the data is at all uploaded to Dexcom system, it is not shown back to the user beside those three hours.

It’s important to note here that unless you are at home (and you kept the box the transmitter came with), or you have written down the transmitter serial number somewhere, you won’t be able to reconnect. You need the transmitter serial number for the two of them to pair. To compare again this to the LibreLink app, that one only requires you to log in with your account, and the current sensor can just be scanned normally. Calibration info is kept online and transmitted back as needed.

A few hours later, the first sensor (not the transmitter) finally expired and I prepared myself to set the new one up. The first thing you see when you open the app after the sensor expired is a “Start new Sensor” button. If you click that, you are asked for the code of the sensor, with a drawing of the applicator that has the code printed on the cover of the glue pad. If you type in the code, the app will think that you already set up the whole sensor and it’s ready to start, and will initiate the countdown of the warm up. At no point the app direct you to apply the new sensor. It gives you the impression you need to first scan the code and then apply the sensor, which is wrong!

Luckily despite this mistake, I was able to tell the app to stop the sensor by telling it I’d be replacing transmitter. And then re-enrolling the already present transmitter. This is all completely messed up in the flow, particularly because when you do the transmitter re-enrolment, the steps are in the correct order: scan then tell you to put the transmitter in, and then scan the transmitter serial number (again, remember to keep the box). It even optionally shows you the explanation video again — once again, totally unlike just starting a new sensor.

To say that this is badly thought out is an understatement to me. I’ll compare this again with the LibreLink app that, once the sensor terminates, actually shows you the steps to put on a new sensor (you can ignore them and go straight to scanning the sensor if you know what you’re doing).

On the more practical side, the skin adhesive that I talked about last week actually seems to work fine to keep the sensor in place better, and it makes dealing with my hairy belly simpler by bunching up the hair and keep it attached to the skin, rather than having it act as a fur against the sensor’s glue. It would probably be quite simpler to put on if they provided a simpler guide on the size of the sensor though: showing it on the video is not particularly nice.

The sensor still needed calibration: the readings were off by more than 20% at first, although they are now back on track. This either means the calibration is off in general, or somehow there’s a significant variation between the value read by the Dexcom sensor and the actual blood sugar. I don’t have enough of a medical background to be able to tell this, so I leave that to the professionals.

At this point, my impression of the Dexcom G6 system is that it’s a fairly decent technical implementation of the hardware, but a complete mess on the software and human side. The former, I’m told can be obviated by using a third-party app (by the folks who are not waiting), which I will eventually try at this point for the sake of reviewing it. The latter, probably would require them to pay more attention to their competitors.

Abbott seems to have the upper-hand with the user-friendly apps and reports, even though there are bugs and their updates are very far in between. They also don’t do alerts, and despite a few third-party “adapters” to transform the Libre “flash” system into a more proper CGM, I don’t think there will be much in the form of reliable alerts until Abbott changes direction.

FreeStyle Libre and first responders

Over on Twitter, a friend asked me a question related to the FreeStyle Libre, since he knew that I’m an user. I provided some “soundbite-shaped” answers on the thread but since I got a few more confused replies afterwards, I thought I would try to make the answer a bit more complete:

Let’s start with a long list of caveats here: I’m not a doctor, I’m not a paramedic, I do not work for or with Abbott, and I don’t speak for my employer. All the opinions that follow are substantiated only by my personal experiences and expertise, which is to say, I’m an user of the Libre system and I happen to be a former firmware engineer (in non-medical fields) and have a hobby of reverse engineering glucometer communication protocols. I will also point out that I have explicitly not looked deeply into the NFC part of the communication protocol, because (as I’ll explain in a minute), that crosses the line of what I feel comfortable releasing to the public.

Let me start with the immediate question that Ciarán asks in the tweet. No, the communication between the sensor and the reader device (or phone app) is not authenticated or protected by a challenge/response pair, as far as I know. From what I’ve been told (yes I’m talking through hearsay here, but give me a moment), the sensor will provide the response no matter who is asking. But the problem is what that response represent.

Unlike your average test strip based glucometer, the sensor does not record actual blood glucose numbers. Instead it reports a timeseries of raw values from different sensors. Pierre Vandevenne looked at the full response and shed some light onto the various other values provided by the sensor.

How that data is interpreted by the reader (or app) depends on its calibration, which happens in the first 60 minutes of operation of the sensor. Because of this, the official tools (reader and app) only allows you to scan a sensor with the tool that started it — special concessions are made for the app: a sensor started by a reader device can be also “tied” to the app, as long as you scan it with the app during the first hour of operation. It does not work the other way, so if you initialize with the app, you can’t use the reader.

While I cannot be certain that the reader/app doesn’t provide data to the sensor to allow you to do this kind of dual-initialization, my guess is that they don’t: the launch of the app was not tied with any change to the sensors, nor with warnings that only sensors coming from a certain lot and later models would work. Also, the app is “aware” of sensors primed by the reader, but not vice-versa, which suggests the reader’s firmware just wouldn’t allow you to scan an already primed sensor.

Here is one tidbit of information I’ll go back to later on. To use the app, you need to sign up for an account, and all the data from the sensor is uploaded to FreeStyle’s servers. The calibration data appears to be among the information shared on the account, which allows you to move the app you use to a new phone without waiting to replace the sensor. This is very important, because you don’t want to throw away your sensor if you break your phone.

The calibration data is then used together with non-disclosed algorithms (also called “curves” in various blogs) to produce the blood glucose equivalent value shown to the user. One important note here is that the reader and the app do not always agree on the value. While I cannot tell for sure what’s going on, my guess is that, as the reader’s firmware is not modifiable, the app contains newer version of the algorithms, and maybe a newer reader device would agree with the app. As I have decided not to focus on reversing the firmware of the reader, I have no answer there.

Can you get answers from the sensor without the calibration data? As I’m not sure what that data is, I can’t give a definite answer, but I will note that there are a number of unofficial apps out there that purport of doing exactly that. These are the same apps that I have, personally, a big problem with, as they provide zero guarantee that their results are at all precise or consistent, and scare the crap out of me, if you plan on making your life and health depend on them. Would the paramedics be able to use one of those apps to provide vague readings off a sensor? Possibly. But let me continue.

The original tweet by Eoghan asks Abbott if it would be possible for paramedics to have a special app to be able to read the sensor. And here is where things get complicated. Because yes, Abbott could provide such an app, as long as the sensor was initialized or calibration-scanned by the app within the calibration hour: their servers have the calibration data, which is needed to move the app between phones without losing data and without waiting for a new sensor.

But even admitting that there is no technical showstopper to such an app, there are many more ethical and legal concerns about it. There’s no way that the calibration data, and even the immediate value, wouldn’t be considered Sensitive Personal Data. This means for Abbott to be able to share it with paramedics, they would have to have a sharing agreement in place, with all the requirements that the GDPR impose them (for good reason).

Adding to this discussion, there’s the question of whether it would actually be valuable to paramedics to have this kind of information. Since I have zero training in the field, I can’t answer for sure, but I would be cautious about trusting the reading of the sensor, particularly if paramedics had to be involved.

The first warning comes from Abbott themselves, that recommend using blood-based test strips to confirm blood sugar readings during rapid glucose changes (in both directions). Since I’m neither trained in chemistry nor medicine, I don’t know why that is the case, but I have read tidbits that it has to do with the fact that the sensor reads values from interstitial fluid, rather than plasma, and the algorithms are meant to correlate the two values. Interstitial fluid measurements can lag behind the plasma ones and thus while the extrapolation can be correct for a smooth change, it might be off (very much so) when they change suddenly.

And as a personal tale, I have experienced the Libre not reporting any data, and then reporting very off values, after spending a couple of hours in very cold environment (in Pittsburgh, at -14°C). Again, see Vandevenne’s blog for what’s going on there with temperatures and thermal compensation.

All in all, I think that I would trust better a single fingerprick to get a normal test-strip result, both because it works universally, whether you do have a sensor or not, and because its limitations are much better understood both by their users and the professionals. And they don’t need to have so many ethical and legal implications to use.

Diabetes and lifestyle with the FreeStyle Libre

In the comments to my review of the Android LibreLink app, I pointed out to Daniel that (much as I don’t particularly like the “blogger” label), I’m not a diabetes blogger, I’m a tech blogger who suffer from diabetes, and for that reason most of the stuff I posted about it has to do with the technical sides (after all the original set of posts were titled “Diabetes control and its tech”.)

I have, though, to excuse myself for once and write a little bit about lifestyle, but probably not from the same point of view that other bloggers might take in their writing, mostly due to style and interest. But I did say I would talk a little more to how the FreeStyle Libre changed my behaviour since I started using it in January this year (some ten months and something sooner than it was available in the country I live in.)

The Libre, unlike other CGM solutions, is not a real-time solution: it uses interstitial fluids for measurement, and because of that they provide warnings about time-delay, and quick changes in blood sugar; they don’t provide that much specifics, but I noticed something along the lines of 20 minutes delay after eating for the blood sugar to push back up, and what to me looks like “smoothing” of the graph, so that sudden changes in blood sugar are not noticeable. This is also due to the sampling rate (one reading once 15 minutes.)

So while it is not a perfect solution, particularly if you’re relying on it for taking fast insulin, it makes for a good learning experience. By looking at a graph after the fact, while the damage is already done, you can at least know what to repeat and what to avoid. If you want to be buzzword-y you can define it as human deep learning.

What I found is nothing particularly new or exciting, particularly for experts of diabetes, but it did help me understanding to what extend blood sugar can sway based on activity. I wanted to at least talk about some of the experiences I had over the past few months, just for sharing. It might or might not be of help to others, but at least I can show what kind of useful lessons can be learnt with solutions like the Libre.

Some months ago I went to IKEA to buy some furniture for my apartment in Dublin, namely a cupboard, and a new sofa (the one I had before turned out to be moldy from before I moved in, so I asked my landlords to please allow me to change it.) I received them on a Saturday very early (for me) morning: 8am. I had to wake up at 7.25am and have breakfast, I had a significant breakfast, which as usual involves lots of coffee. The delivery men brought the boxes inside and took the old sofa out, but the rest was up to me. I started with the sofa, and by 11am I had it done. I had to stop midway through to eat a packet of chocolate biscuits because I felt a bit dizzy and I found that I was going low on sugar quite quickly, even though it did go over the 10 mmol/l limit after breakfast. I had another “heavy” lunch (as in, more than double my usual amount of pasta) because I was still on the lower-side of the range, and I had one more piece of furniture to build. I had to stop by 2pm again to eat some ice-cream because I was below the 4mmol/l already. Over the course of the next two days, no matter how much I’d eat: pasta, ice-cream and biscuits, I didn’t go over 9 mmol/l at all.

What does that tell me? It’s clearly not bollocks when they say that physical activity helps a lot with diabetes; assembling IKEA furniture is clearly not a sport, but it worked effectively the same way. I’m still a lazy bum and have not done any sports, part of it because I feel horribly out of place in a gym, though I did enjoy bouldering with colleagues before, I should try that again. To be honest, this was not entirely new to me either; not only I did notice that even the WiiFit exercises used to help me lower my blood sugar much quicker, back in Italy when I was not on insulin nor under a solution like the Libre, but when a couple of years ago I ended up taking the 23andMe test, one of their reports had interesting information that was actually relevant to me:

Insulin sensitivity response to exercise: Exercise is associated with a 2% improvement in insulin sensitivity, on average.

Teran-Garcia M et al. (2005) . “Hepatic lipase gene variant -514C>T is associated with lipoprotein and insulin sensitivity response to regular exercise: the HERITAGE Family Study.” Diabetes 54(7):2251-5.

Improvement in glucose tolerance with regular exercise: Glucose tolerance improved with regular exercise.

Ruchat SM et al. (2010) . “Improvements in glucose homeostasis in response to regular exercise are influenced by the PPARG Pro12Ala variant: results from the HERITAGE Family Study.” Diabetologia 53(4):679-89.

Correlation does not imply causation, but these information correlate with my personal anecdotes, take it with as much salt as you want.

Speaking of correlation, and (as you’ll see) of 23andMe. I’m sure we all have wondered at some point if the drugs prescribed by our doctors actually help, or if they rely almost exclusively on placebo effect. Well, I unwittingly went through that experiment, by forgetting my meds a couple of times — anybody who’s on any kind of daily meds would tell you that even though it’s bad, it’s not always easy or obvious to keep your meds routine straight and never forget any, I can tell you that while travelling across timezones, it’s even harder. Since I’m on both insulin detemir and gliclazide I have at some point forgot one, the other, or (much more rarely) both. And I did find something interesting: I can much more easily notice by the graph the days in which I forgot the gliclazide than those in which I missed insulin. Missing insulin looks a lot like eating too much, particularly for breakfast. Missing gliclazide looks like the Y axis got transposed so the values read at least +3 overall, if not more. You can imagine that after I did make a mental note of that I paid much more attention to the pills than the injection, in the morning (it’s easy to do the opposite, since the injection requires more minding.)

As I said, this was also notable in the 23andMe report:

Sulfonylurea Metabolism: Somewhat reduced ability to clear sulfonylurea drugs from the body.

(This one has way too many references to easily cite them all, but it looks legit, my doctor was also interested to learn more about 23andMe after I sent him the printed report about this one.)

Staying with the list of don’ts, let me tell you about dessert. It would be easy to just say that diabetics should stay away from desserts at all time, but that is not true, as anybody with a bit of direct or indirect experience on the matter would know. Among other things, even though my friend the dietician gets upset when I do that, I have explicitly limited to a light lunch to be able to get a tasty and sugary dessert. This is not good of course and so I really do that rarely.

On the other hand, even with a normal lunch or dinner, I have started finding which configurations of meal could allow me to have a dessert and which does not. Turns out, what you ear is far from the only variable either. When you eat is also a factor, so for the same dessert I can have it for lunch, as long as I do my half hour walk home, but if I have it for dinner, even though I walk home, it spikes my blood sugar so high that I was seriously worried about my life.

All in all, the lessons I can learn from this device are still plenty, but it also means I am learning to look after myself a lot more than I was doing before, with significant less effort. It makes me happy, so I’ll be happy to continue paying for this if HSE is not to cover them (which is still unclear to me.)

Abbot FreeStyle Libre, the mobile app

You may remember I reviewed the Abbott FreeStyle Libre and even tried reverse engineering its protocol. One of the things that I did notice from the beginning is that the radio used by the sensors themselves is compatible with the NFC chip in most cellphones.

This was not a surprise to everybody; indeed I was pointed at a website (which I refuse to link) of Nightscouters (self-proclaimed people who “are not waiting”), which in turn pointed to an unofficial Android app that is able to read that data. The app is unsafe though (thus the lack of links), as it does not wait the first hour to get a reading, and allows to keep reading the sensor after the two weeks provided by the manufacturer. Their excuse is that you should be able to get the data and judge by yourself; I don’t like that answer, particularly as the raw readings need to be normalized by the Abbott reading device for it to have a valid reading.

Indeed, the various groups I see proclaiming “they are not waiting”, are vastly interested in the idea of quantified self, rather than having an actual health need for this data. They would be harmless, if they didn’t suggest using similarly risky methods to gain information that could be used to make medical decision. But this is a topic for another time.

Instead, a few months ago, Abbott themselves sent out an email to the register users that they made an official Android app available. Called LibreLink, and developed by a company identified as AirStrip Technologies based in San Antonio, Texas, this app is able to initialize and read a FreeStyle Libre sensor from an NFC-capable Android phone. It can be used to either replace the original Abbott reader device, or in addition to it.

I have tried it as soon as I could, which meant not right as I received the mail: the app is only able to read a sensor that it either initialize by itself, or one that was scanned during the one hour window in which the readings are not available. I suppose this has something to do with the pseudo-calibration that the FreeStyle Libre system provides.

Having the ability to take my readings from the phone turned out to be a good thing. While I would still try to keep the readings on the official device, which allows downloading them to a computer, and provides a full PDF I can send my doctor with the history, it allowed me to forget my reader at home for a day, and not having to worry, or being able to take a reading during a meeting in which I did not think to take the reader with me. It also provides more information than the reader itself, including what Abbott calls the Ambulatory Glucose Profile (AGP), which ends up being a graph of 10-90 percentiles, 25-75 percentiles, and median.

Aside: turns out that getting used to read percentile graphs, which is something my dayjob trained me to do, made it much more obvious to me what the AGP graphs were; I had to correct the Diabetes Ireland website, that listed it as a set of superimposed graphs. It took me a good half-hour to realize that it was just obvious to me due to my work, which is totally unrelated to health-care, but it would not be so to a doctor who has not seen that kind of monitoring before. Cross-discipline information exchange is good.

Unfortunately, it seems like the app likes to share data with its developers. This makes sense to a point: science is progressing, and they want to know how exactly it makes your life different, does it make it easier to keep your sugar within limits? Does it make it more likely to get sugar-lows, rather than highs? These are all good questions. I have not tried investigating (yet) whether the app shares this data over a properly encrypted channel or if it’s an actual privacy risk. I might better not know, since it does scare me a bit, but I guess I should do that at some point.

Again as an aside, I did get myself an Android phone capable of NFC, for the sole reason of being able to use that app while inspecting its traffic. The phone I used previously for that is my corporate phone, so I would not be able to fiddle with the traffic dumping on it. But I guess I’ll have to find more time for that, nowadays.

While I have been happy that the app was around, it was not perfect either. In particular I have a bad feeling that it might have something to do with two sensors failing on me with an error I did not see in the eight months before the app was introduced. I have made the mistake of not contacting Abbott right away about them, which meant I thrown them out without sending them for inspection, I have since realized my mistake but could not risk causing more failures until about this month, since I’ve been traveling a bit, and it takes me about a week or two to get new sensors in Dublin.

The reason why I suspect this is related to the app is not just that I didn’t get those kind of errors before I started using it, but also because I had read of similar failures happening when using the unofficial app suggested by Nightscouters, though in that case it’s said to be dependent on the NFC chip used by the cellphone. The two things together made me suspicious.

I’m actually told (by both my doctor and Diabetes Ireland) that Abbott is meant to start selling the device (and sensors) in Ireland before next month. Right now they do have an Irish website, which is more than they had when I started looking into it. I do not know as of yet, whether my long-term illness coverage includes these sensors or if I’ll have to keep paying for them myself (at least the falling Sterling is helping), but either way it’s going to be simpler to procure them if one of them fails.

As a final note, I should probably write down my own impressions when the sensor failed, compared to the article Daniel pointed me at back when I posted about my experimentation with this CGM (pardon, flash glucose monitoring system.) Although the first time this happened, it was not due to the mobile app; instead the application packet for the sensor failed, and I “primed” a sensor without a needle.

This happened when I was in Lisbon on vacation, and I only noticed after the hour passed, and I was queuing up for a train ticket to Cascais. I’ll admit it: I started panicking. I did not plan for it and I did not want to be out and about alone without the sensor. Part of the problem was to be found in me not having the normal glucometer with me, so having absolutely no way to make sure I was okay. The panic probably would have limited itself had I managed to get a ticket in less than twenty minutes. At the end I gave up when I got to the machine and it refused to accept either my cash (too wrinkly) or my card (too foreign.) So I turned around, went back to the hotel and put a new sensor (yes I traveled with a spare.)

Would I have panicked like in the linked article? Maybe, but I would like to think not. When the sensor actually failed me at home, this time indeed possibly due to the app, I didn’t have a spare sensor at home, and that made me angry. But at the same time, I knew it was not that important, I lived without it before, and I can live without it now, it’s just more inconvenient. What I did was putting a new cassette into the Accu-Chek which is significantly nicer to bring around than the kit for the Libre-as-glucometer, and ordered more sensors. I ended up staying a week without the Libre; it bothered me but I didn’t change much of my habits: the Libre trained me on how to relate my sensory experience with blood sugar, and what I can and cannot eat when, so I felt fairly safe overall.

Reverse engineering the FreeStyle Libre CGM, chapter 1

If you’re here looking for information on the FreeStyle Libre 2, please see this other series of posts, and this issue on GitHub. Reverse engineering is proceeding slowly, and collaboration is key.

I have already reviewed the Abbott FreeStyle Libre continuous glucose monitor, and I have hinted that I already started reverse engineering the protocol it uses to communicate with the (Windows) software. I should also point out that for once the software does provide significant value, as they seem to have spent more effort in the data analysis than any other part of it.

Please note that this is just a first part for this device. Unlike the previous blog posts, I have not managed yet to get even partial information downloaded with my script as I write and post this. Indeed, if you, as you read this, have any suggestion of things I have not tried yet, please do let me know.

Since at this point it’s getting common, I’ve started up the sniffer, and sniffed starting from the first transaction. As it is to be expected, the amount of data in these transactions is significantly higher than that of the other glucometers. Even if you were taking seven blood samples a day for months with one of the other glucometers, it’s going to take a much longer time to get the same amount of readings as this sensor, which takes 96 readings a day by itself, plus the spot-checks and added notes and information to comment them.

The device itself presents itself as a standard HID device, which is a welcome change from the craziness of SCSI-based hidden message protocols. The messages within are of course not defined in any standard of course, so inspecting them become interesting.

It took me a while to figure out what the data that the software was already decoding for me meant. At first I thought I would have to use magic constant and libusb to speak raw USB to the device — indeed, a quick glance around Xavier’s work showed me that there were plenty of similarities, and he’s including quite a few magical constants in that code. Luckily for me, after managing to query the device with python-libusb1, which was quite awkward as I also had to fix it to work, I realized that I was essentially reimplementing hidraw access.

After rewriting the code to use /dev/hidraw1 (which makes it significantly simpler), I also managed to understand that the device uses exactly the same initialization procedure as the FreeStyle InsuLinx that Xavier already implemented, and similar but not identical command handling (some of the commands match, and some even match the Optium, at least in format.)

Indeed the device seem to respond to two general classes of commands: text-commands and binary commands, the first device I reverse engineer with such a hybrid protocol. Text commands also have the same checksumming as both the Optium and Neo protocols.

The messages are always transferred in 64-bytes packets, even though the second byte of the message declares the actual significant length, which can be even zero. Neither the software nor the device zero out their buffers before writing the new command/response packets, so there is lots of noise in those packets.

I’ve decided that the custom message framing and its usage of HID is significant enough to warrant being documented by itself so I did that for now, although I have not managed to complete the reverse engineering of the protocol.

The remaining of the protocol kept baffling me. Some of the commands appear to include a checksum, and are ignored if they are not sent correctly. Others actually seem to append to an error buffer that you can somehow access (but probably more by mistake than design) and in at least one case I managed to “crash” the device, which asked me to turn it off and on again. I have thus decided to stop trying to send random messages to it for a while.

I have not been pouring time on this as much as I was considering doing before, what with falling for a bad flu, being oncall, and having visitors in town, so I have only been looking at traces from time to time, particularly recording all of them as I downloaded more data out of it. What still confuses me is that the commands sent from the software are not constant across different calls, but I couldn’t really make much heads or tails of it.

Then yesterday I caught a break — I really wanted to figure out at least if it was encoding or compressing the data, so I started looking for at least a sequence of numbers, by transcribing the device’s logbook into hexadecimal and looking in the traces for them.

This is not as easy as it might sound, because I have a British device — in UK, Ireland and Australia the measure of blood sugar is given in mmol/l rather than the much more common mg/dl. There is a stable conversion between the two units (you multiply the former by 18 to get the latter), but this conversion usually happens on display. All the devices I have used up to now have been storing and sending over the wire values in mg/dl and only converted when the data is shown, usually by providing some value within the protocol to specify that the device is set to use a given unit measure. Because of this conversion issue, and the fact that I only had access to the values mmol/l, I usually had two different options for each of the readings, as I wasn’t sure how the rounding happened.

The break happened when I was going through the software’s interface, trying to get the latest report data to at least match the reading timing difference, so that I could look for what might appear like a timestamp in the transcript. Instead, I found the “Export” function. The exported file is a comma-separated values file, which includes all readings, including those by the sensor, rather than just the spot-checks I could see from the device interface and in the export report. Not only that, but it includes a “reading ID”, which was interesting because it started from a value a bit over 32000, and is not always sequential. This was lucky.

I imported the CSV to Google Sheets, then added columns next to the ID and glucose readings. The latter were multiplied by 18 to get the value in mg/dl (yes the export feature still uses mmol/l, I think it might be some certification requirement), and then convert the whole lot to hexadecimal (hint: Google Sheets and LibreOffice have a DEC2HEX function that do that for you.) Now I had something interesting to search for: the IDs.

Now, I have to point out that the output I have from USBlyzer is a CSV file that includes the hexdump of the USB packets that are being exchanged. I already started writing a set of utilities (too rough to be published though) to convert those into a set of binary files (easier to bgrep or binwalk them) or hexdump-like transcripts (easier to recognize strings.) I wrote both a general “full USB transcript” script as well as a “Verio-specific USB transcript” while I was working on my OneTouch meter, so I wrote one for the Abbott protocol, too.

Because of the way that works, of course, it is not completely obvious if any value which is not a single byte is present, by looking at the text transcript, as it might be found on the message boundary. One would think they wouldn’t, since that means there are odd-sized records, but indeed that is the case for this device at least. Indeed it took me a few tries of IDs found in the CSV file to find one in the USB transcript.

And even after finding one the question was to figure out the record format. What I have done in the past when doing binary format reverse engineering was to print on a piece of paper a dump of the binary I’m looking at, and start doodling on it trying to mark similar parts of the message. I don’t have a printer in Dublin, so I decided to do a paperless version of the same, by taking a screenshot of a fragment of transcript, and loading it into a drawing app on my tablet. It’s not quite as easy, but it does making sharing results easier and thanks to layers it’s even easier to try and fail.

I made a mistake with the screenshot by not keeping the command this was a reply to in the picture — this will become more relevant later. Because of the size limit in the HID-based framing protocol Abbott uses, many commands reply with more than one message – although I have not understood yet how it signals a continuation – so in this case the three messages (separated by a white line) are in response to a single command (which by the way is neither the first or the last in a long series.)

The first thing I wanted to identify in the response was all the reading IDs, the one I searched for is marked in black in the screenshot, the others are marked in the same green tone. As you can see they are not (all) sequential; the values are written down as little-endian by the way. The next step was to figure out the reading values, which are marked in pink in the image. While the image itself has no value that is higher than 255, thus using more than bytes to represent them, not only it “looked fair” to assume little endian. It was also easy to confirm as (as noted in my review) I did have a flu while wearing the sensor, so by filtering for readings over 14 mmol/L I was able to find an example of a 16-bit reading.

The next thing I noted was the “constant” 0C 80 which might include some flags for the reading, I have not decoded it yet, but it’s an easy way to find most of the other IDs anyway. Following from that, I needed to find an important value, as it could allow decoding many other record types just by being present: the timestamp of the reading. The good thing with timestamps is that they tend to stay similar for a relative long time: the two highest bytes are the same for most of a day, and the highest of those is usually the same for a long while. Unfortunately looking for the hex representation of the Unix timestamp at the time yield nothing, but that was not so surprising, given how I found usage of a “newer” epoch in the Verio device I looked at earlier.

Now, since I have the exported data I know not only the reading ID but also the timestamp it reports it at, which does not include seconds. I also know that since the readings are (usually) taken at 15 minutes intervals, if they are using seconds since a given epoch the numbers should be incrementing by 900 between readings. Knowing this and doing some mental pattern matching it became easy to see where the timestamps have been hiding, they are marked in blue in the image above. I’ll get back to the epoch.

At this point, I still have not figured out where the record starts and ends — from the image it might appear that it starts with the record ID, but remember I took this piece of transcript mid-stream. What I can tell is that the length of the record is not only not a multiple of eight (the bytes in hexdump are grouped by eight) but it is odd, which, by itself, is fairly odd (pun intended.) This can be told by noticing how the colouring crosses the mid-row spacing, for 0c 80, for reading values and timestamps alike.

Even more interesting, not only the records can cross the message boundaries (see record 0x8fe0 for which the 0x004b value is the next message over), but even do the fields. Indeed you can see on the third message the timestamp ends abruptly at the end of the message. This wouldn’t be much of an issue if it wasn’t that it provides us with one more piece of information to decode the stream.

As I said earlier, timestamps change progressively, and in particular reading records shouldn’t usually be more than 900 seconds apart, which means only the lower two bytes change that often. Since the device uses little-endian to encode the numbers, the higher bytes are at the end of the encoded sequence, which means 4B B5 DE needs to terminate with 05, just like CC B8 DE 05 before it. But the next time we encounter 05 is in position nine of the following message, what gives?

The first two bytes of the message, if you checked the protocol description linked earlier, describe the message type (0B) and the number of significant bytes following (out of the usb packet), in this case 3E means the whole rest of the packet is significant. Following that there are six bytes (highlighted turquoise in the image), and here is where things get to be a bit more confusing.

You can actually see how discarding those six bytes from each message now gives us a stream of records that are at least fixed length (except the last one that is truncated, which means the commands are requesting continuous sequences, rather than blocks of records.) Those six bytes now become interesting, together with the inbound command.

The command that was sent just before receiving this response was 0D 04 A5 13 00 00. Once again the first two bytes are only partially relevant (message type 0D, followed by four significant bytes.) But A5 13 is interesting, since the first message of the reply starts with 13 A6, and the next three message increment the second byte each. Indeed, the software follows these with 0D 04 A9 13 00 00, which matches the 13 A9 at the start of the last response message.

What the other four bytes mean is still quite the mystery. My assumption right now is that they are some form of checksum. The reason is to be found in a different set of messages:

>>>> 00000000: 0D 04 5F 13 00 00                                 .._...

<<<< 00000000: 0B 3E 10 5F 34 EC 5A 6D  00 00 00 00 00 00 00 00  .>._4.Zm........
<<<< 00000010: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000020: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000030: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

<<<< 00000000: 0B 3E 10 60 34 EC 5A 6D  00 00 00 00 00 00 00 00  .>.`4.Zm........
<<<< 00000010: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000020: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000030: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

<<<< 00000000: 0B 3E 10 61 34 EC 5A 6D  00 00 00 00 00 00 00 00  .>.a4.Zm........
<<<< 00000010: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000020: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000030: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

<<<< 00000000: 0B 3E 10 62 34 EC 5A 6D  00 00 00 00 00 00 00 00  .>.b4.Zm........
<<<< 00000010: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000020: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000030: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................

<<<< 00000000: 0B 3E 10 63 E8 B6 84 09  00 00 00 00 00 00 00 00  .>.c............
<<<< 00000010: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
<<<< 00000020: 00 00 00 00 9A 39 65 70  99 51 09 30 4D 30 30 30  .....9ep.Q.0M000
<<<< 00000030: 30 37 52 4B 35 34 00 00  01 00 02 A0 9F DE 05 FC  07RK54..........

In this set of replies, there are two significant differences compared to the ones with record earlier. The first is that while the command lists 5F 13 the replies start with 10 5F, so that not only 13 becomes 10, but 5F is not incremented until the next message, making it unlikely for the two bytes to form a single 16-bit word. The second is that there are at least four messages with identical payload (fifty-six bytes of value zero). And despite the fourth byte of the message changing progressively, the following four bytes are staying the same. This makes me think it’s a checksum we’re talking about, although I can’t for the life of me figure out which at first sight. It’s not CRC32, CRC32c nor Adler32.

By the way, the data in the last message relates to the list of sensors the devices has seen — 9ep.Q.0M00007RK54 is the serial number, and A0 9F DE 05 is the timestamp of it initializing.

Going back to the epoch, which is essentially the last thing I can talk about for now. The numbers above clearly shower in a different range than the UNIX timestamp, which would start with 56 rather than 05. So I used the same method I used for the Verio, and used a fixed, known point in time, got the timestamp from the device and compared with its UNIX timestamp. The answer was 1455392700 — which is 2012-12-31T00:17:00+00:00. It would make perfect sense, if it wasn’t 23 hours and 43 minutes away from a new year…

I guess that is all for now, I’m still trying to figure out how the data is passed around. I’m afraid that what I’m seeing from the software looks like it’s sending whole “preferences” structures that change things at once, which makes it significantly more complicated to understand. It’s also not so easy to tell how the device and software decide the measure unit as I don’t have access to logs of a mg/dl device.