summaryrefslogtreecommitdiffstats
path: root/reversing_tools/abbott
diff options
context:
space:
mode:
authorDiego Elio Pettenò <flameeyes@flameeyes.com>2020-10-04 16:12:44 +0200
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2020-10-04 21:47:57 +0200
commit81d4e308a36cd06f5e7bac30d2af10145c8f193a (patch)
treeacf5314486de90f79ec4b77b423f282e7a9afaa4 /reversing_tools/abbott
parenttd4277: update dependency information for pyserial. (diff)
downloadglucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.tar
glucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.tar.gz
glucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.tar.bz2
glucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.tar.lz
glucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.tar.xz
glucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.tar.zst
glucometerutils-81d4e308a36cd06f5e7bac30d2af10145c8f193a.zip
Diffstat (limited to '')
-rw-r--r--reversing_tools/abbott/__init__.py3
-rw-r--r--reversing_tools/abbott/encrypted_setup_extractor.py179
-rwxr-xr-xreversing_tools/abbott/extract_freestyle.py245
-rwxr-xr-xreversing_tools/abbott/freestyle_hid_console.py69
-rw-r--r--reversing_tools/abbott/known-commands.txt48
-rw-r--r--reversing_tools/abbott/known-commands.txt.license3
6 files changed, 0 insertions, 547 deletions
diff --git a/reversing_tools/abbott/__init__.py b/reversing_tools/abbott/__init__.py
deleted file mode 100644
index 4b386c3..0000000
--- a/reversing_tools/abbott/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-FileCopyrightText: 2013 The glucometerutils Authors
-#
-# SPDX-License-Identifier: Unlicense
diff --git a/reversing_tools/abbott/encrypted_setup_extractor.py b/reversing_tools/abbott/encrypted_setup_extractor.py
deleted file mode 100644
index cc57f0f..0000000
--- a/reversing_tools/abbott/encrypted_setup_extractor.py
+++ /dev/null
@@ -1,179 +0,0 @@
-#!/usr/bin/env python3
-#
-# SPDX-FileCopyrightText: © 2019 The usbmon-tools Authors
-# SPDX-FileCopyrightText: © 2020 The glucometerutils Authors
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import argparse
-import logging
-import sys
-
-import construct
-import usbmon
-import usbmon.pcapng
-
-_SERIAL_NUMBER_RESPONSE_TYPE = 0x06
-_ENCRYPTION_SETUP_REQ_TYPE = 0x14
-_ENCRYPTION_SETUP_RESP_TYPE = 0x33
-
-
-_START_AUTHORIZE_CMD = 0x11
-_CHALLENGE_CMD = 0x16
-_CHALLENGE_RESPONSE_CMD = 0x17
-
-
-_ABBOTT_VENDOR_ID = 0x1A61
-_LIBRE2_PRODUCT_ID = 0x3950
-
-_SERIAL_NO = construct.Struct(
- message_type=construct.Const(_SERIAL_NUMBER_RESPONSE_TYPE, construct.Byte),
- length=construct.Const(14, construct.Byte),
- serial_number=construct.PaddedString(13, "ascii"),
- termination=construct.Const(0, construct.Byte),
-)
-
-_CHALLENGE = construct.Struct(
- message_type=construct.Const(_ENCRYPTION_SETUP_RESP_TYPE, construct.Byte),
- length=construct.Const(16, construct.Byte),
- subcmd=construct.Const(_CHALLENGE_CMD, construct.Byte),
- challenge=construct.Bytes(8),
- iv=construct.Bytes(7),
-)
-
-_CHALLENGE_RESPONSE = construct.Struct(
- message_type=construct.Const(_ENCRYPTION_SETUP_REQ_TYPE, construct.Byte),
- length=construct.Const(26, construct.Byte),
- subcmd=construct.Const(_CHALLENGE_RESPONSE_CMD, construct.Byte),
- challenge_response_encrypted=construct.Bytes(16),
- const=construct.Const(1, construct.Byte),
- mac=construct.Bytes(8),
-)
-
-
-def main():
- if sys.version_info < (3, 7):
- raise Exception("Unsupported Python version, please use at least Python 3.7.")
-
- parser = argparse.ArgumentParser()
-
- parser.add_argument(
- "--device_address",
- action="store",
- type=str,
- help=(
- "Device address (busnum.devnum) of the device to extract capture"
- " of. If none provided, device descriptors will be relied on."
- ),
- )
-
- parser.add_argument(
- "--vlog",
- action="store",
- required=False,
- type=int,
- help=(
- "Python logging level. See the levels at"
- " https://docs.python.org/3/library/logging.html#logging-levels"
- ),
- )
-
- parser.add_argument(
- "pcap_files",
- action="store",
- type=argparse.FileType(mode="rb"),
- help="Path to the pcapng file with the USB capture.",
- nargs="+",
- )
-
- args = parser.parse_args()
-
- logging.basicConfig(level=args.vlog)
-
- for pcap_file in args.pcap_files:
- session = usbmon.pcapng.parse_stream(pcap_file, retag_urbs=False)
-
- if not args.device_address:
- for descriptor in session.device_descriptors.values():
- if (
- descriptor.vendor_id == _ABBOTT_VENDOR_ID
- and descriptor.product_id == _LIBRE2_PRODUCT_ID
- ):
- if (
- args.device_address
- and args.device_address != descriptor.address
- ):
- raise Exception(
- "Multiple Libre2 devices present in capture, please"
- " provide a --device_address flag."
- )
- device_address = descriptor.address
- else:
- device_address = descriptor.address
-
- descriptor = session.device_descriptors.get(device_address, None)
- if descriptor:
- assert descriptor.vendor_id == _ABBOTT_VENDOR_ID
- assert descriptor.product_id == _LIBRE2_PRODUCT_ID
-
- serial_number = "UNKNOWN"
- challenge = "UNKNOWN"
- iv = "UNKNOWN"
- encrypted_challenge = "UNKNOWN"
- mac = "UNKNOWN"
-
- for first, second in session.in_pairs():
- # Ignore stray callbacks/errors.
- if not first.type == usbmon.constants.PacketType.SUBMISSION:
- continue
-
- if not first.address.startswith(f"{device_address}."):
- # No need to check second, they will be linked.
- continue
-
- if first.xfer_type == usbmon.constants.XferType.INTERRUPT:
- pass
- elif (
- first.xfer_type == usbmon.constants.XferType.CONTROL
- and not first.setup_packet
- or first.setup_packet.type == usbmon.setup.Type.CLASS
- ):
- pass
- else:
- continue
-
- if first.direction == usbmon.constants.Direction.OUT:
- packet = first
- else:
- packet = second
-
- if not packet.payload:
- continue
-
- assert len(packet.payload) >= 2
-
- message_type = packet.payload[0]
-
- if message_type == _SERIAL_NUMBER_RESPONSE_TYPE:
- obj = _SERIAL_NO.parse(packet.payload)
- serial_number = obj.serial_number
- elif (
- message_type == _ENCRYPTION_SETUP_RESP_TYPE
- and packet.payload[2] == _CHALLENGE_CMD
- ):
- obj = _CHALLENGE.parse(packet.payload)
- challenge = obj.challenge.hex()
- iv = obj.iv.hex()
- elif (
- message_type == _ENCRYPTION_SETUP_REQ_TYPE
- and packet.payload[2] == _CHALLENGE_RESPONSE_CMD
- ):
- obj = _CHALLENGE_RESPONSE.parse(packet.payload)
- encrypted_challenge = obj.challenge_response_encrypted.hex()
- mac = obj.mac.hex()
-
- print(f"{serial_number},{challenge},{iv},{encrypted_challenge},{mac}")
-
-
-if __name__ == "__main__":
- main()
diff --git a/reversing_tools/abbott/extract_freestyle.py b/reversing_tools/abbott/extract_freestyle.py
deleted file mode 100755
index 0c0888a..0000000
--- a/reversing_tools/abbott/extract_freestyle.py
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/usr/bin/env python3
-#
-# SPDX-FileCopyrightText: © 2019 The usbmon-tools Authors
-# SPDX-FileCopyrightText: © 2020 The glucometerutils Authors
-#
-# SPDX-License-Identifier: Apache-2.0
-
-import argparse
-import logging
-import sys
-import textwrap
-
-import construct
-import usbmon
-import usbmon.chatter
-import usbmon.pcapng
-
-_KEEPALIVE_TYPE = 0x22
-
-_UNENCRYPTED_TYPES = (
- 0x01,
- 0x04,
- 0x05,
- 0x06,
- 0x0C,
- 0x0D,
- 0x14,
- 0x15,
- 0x33,
- 0x34,
- 0x35,
- 0x71,
- _KEEPALIVE_TYPE,
-)
-
-_ENCRYPTION_SETUP_TYPES = (0x14, 0x33)
-
-_START_AUTHORIZE_CMD = 0x11
-_CHALLENGE_CMD = 0x16
-_CHALLENGE_RESPONSE_CMD = 0x17
-_CHALLENGE_ACCEPTED_CMD = 0x18
-
-_ABBOTT_VENDOR_ID = 0x1A61
-_LIBRE2_PRODUCT_ID = 0x3950
-
-_ENCRYPTED_MESSAGE = construct.Struct(
- message_type=construct.Byte,
- encrypted_message=construct.Bytes(64 - 1 - 4 - 4),
- sequence_number=construct.Int32ul,
- mac=construct.Int32ul,
-)
-
-
-def main():
- if sys.version_info < (3, 7):
- raise Exception("Unsupported Python version, please use at least Python 3.7.")
-
- parser = argparse.ArgumentParser()
-
- parser.add_argument(
- "--device_address",
- action="store",
- type=str,
- help=(
- "Device address (busnum.devnum) of the device to extract capture"
- " of. If none provided, device descriptors will be relied on."
- ),
- )
-
- parser.add_argument(
- "--encrypted_protocol",
- action="store_true",
- help=(
- "Whether to expect encrypted protocol in the capture."
- " Ignored if the device descriptors are present in the capture."
- ),
- )
-
- parser.add_argument(
- "--verbose-encryption-setup",
- action="store_true",
- help=(
- "Whether to parse encryption setup commands and printing their component"
- " together with the raw messsage."
- ),
- )
-
- parser.add_argument(
- "--vlog",
- action="store",
- required=False,
- type=int,
- help=(
- "Python logging level. See the levels at"
- " https://docs.python.org/3/library/logging.html#logging-levels"
- ),
- )
-
- parser.add_argument(
- "--print_keepalive",
- action="store_true",
- help=(
- "Whether to print the keepalive messages sent by the device. "
- "Keepalive messages are usually safely ignored."
- ),
- )
-
- parser.add_argument(
- "pcap_file",
- action="store",
- type=argparse.FileType(mode="rb"),
- help="Path to the pcapng file with the USB capture.",
- )
-
- args = parser.parse_args()
-
- logging.basicConfig(level=args.vlog)
-
- session = usbmon.pcapng.parse_stream(args.pcap_file, retag_urbs=False)
-
- if not args.device_address:
- for descriptor in session.device_descriptors.values():
- if descriptor.vendor_id == _ABBOTT_VENDOR_ID:
- if args.device_address and args.device_address != descriptor.address:
- raise Exception(
- "Multiple Abbott device present in capture, please"
- " provide a --device_address flag."
- )
- args.device_address = descriptor.address
-
- descriptor = session.device_descriptors.get(args.device_address, None)
- if not descriptor:
- logging.warning(
- "Unable to find device %s in the capture's descriptors."
- " Assuming non-encrypted protocol.",
- args.device_address,
- )
- else:
- assert descriptor.vendor_id == _ABBOTT_VENDOR_ID
-
- if descriptor and descriptor.product_id == _LIBRE2_PRODUCT_ID:
- args.encrypted_protocol = True
-
- for first, second in session.in_pairs():
- # Ignore stray callbacks/errors.
- if not first.type == usbmon.constants.PacketType.SUBMISSION:
- continue
-
- if not first.address.startswith(f"{args.device_address}."):
- # No need to check second, they will be linked.
- continue
-
- if first.xfer_type == usbmon.constants.XferType.INTERRUPT:
- pass
- elif (
- first.xfer_type == usbmon.constants.XferType.CONTROL
- and not first.setup_packet
- or first.setup_packet.type == usbmon.setup.Type.CLASS
- ):
- pass
- else:
- continue
-
- if first.direction == usbmon.constants.Direction.OUT:
- packet = first
- else:
- packet = second
-
- if not packet.payload:
- continue
-
- assert len(packet.payload) >= 2
-
- message_type = packet.payload[0]
-
- if message_type == _KEEPALIVE_TYPE and not args.print_keepalive:
- continue
-
- message_metadata = []
-
- if args.encrypted_protocol and message_type not in _UNENCRYPTED_TYPES:
- # With encrypted communication, the length of the message is also encrypted,
- # and all the packets use the full 64 bytes. So instead, we extract what
- # metadata we can.
- parsed = _ENCRYPTED_MESSAGE.parse(packet.payload)
- message_metadata.extend(
- [f"SEQUENCE_NUMBER={parsed.sequence_number}", f"MAC={parsed.mac:04x}"]
- )
-
- message_type = f"x{message_type:02x}"
- message = parsed.encrypted_message
- elif args.verbose_encryption_setup and message_type in _ENCRYPTION_SETUP_TYPES:
- message_length = packet.payload[1]
- message_end_idx = 2 + message_length
- message = packet.payload[2:message_end_idx]
-
- if message[0] == _START_AUTHORIZE_CMD:
- message_metadata.append("START_AUTHORIZE")
- elif message[0] == _CHALLENGE_CMD:
- message_metadata.append("CHALLENGE")
- challenge = message[1:9]
- iv = message[9:16]
- message_metadata.append(f"CHALLENGE={challenge.hex()}")
- message_metadata.append(f"IV={iv.hex()}")
- elif message[0] == _CHALLENGE_RESPONSE_CMD:
- message_metadata.append("CHALLENGE_RESPONSE")
- encrypted_challenge = message[1:17]
- challenge_mac = message[18:26]
- message_metadata.append(
- f"ENCRYPTED_CHALLENGE={encrypted_challenge.hex()}"
- )
- message_metadata.append(f"MAC={challenge_mac.hex()}")
- elif message[0] == _CHALLENGE_ACCEPTED_CMD:
- message_metadata.append("CHALLENGE_ACCEPTED")
-
- message_metadata.append(f"RAW_LENGTH={message_length}")
- message_type = f" {message_type:02x}"
- else:
- message_length = packet.payload[1]
- message_metadata.append(f"LENGTH={message_length}")
- message_end_idx = 2 + message_length
- message_type = f" {message_type:02x}"
- message = packet.payload[2:message_end_idx]
-
- if message_metadata:
- metadata_string = "\n".join(
- textwrap.wrap(
- " ".join(message_metadata), width=80, break_long_words=False
- )
- )
- print(metadata_string)
-
- print(
- usbmon.chatter.dump_bytes(
- packet.direction,
- message,
- prefix=f"[{message_type}]",
- print_empty=True,
- ),
- "\n",
- )
-
-
-if __name__ == "__main__":
- main()
diff --git a/reversing_tools/abbott/freestyle_hid_console.py b/reversing_tools/abbott/freestyle_hid_console.py
deleted file mode 100755
index 18df89c..0000000
--- a/reversing_tools/abbott/freestyle_hid_console.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python3
-# SPDX-FileCopyrightText: © 2019 The glucometerutils Authors
-# SPDX-License-Identifier: MIT
-"""CLI tool to send messages through FreeStyle HID protocol."""
-
-import argparse
-import logging
-import sys
-
-from glucometerutils import exceptions
-from glucometerutils.support import freestyle
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "--text_cmd_type",
- action="store",
- type=int,
- default=0x60,
- help="Message type for text commands sent to the device.",
- )
- parser.add_argument(
- "--text_reply_type",
- action="store",
- type=int,
- default=0x60,
- help="Message type for text replies received from the device.",
- )
- parser.add_argument(
- "device", action="store", help="Path to the HID device to open."
- )
-
- parser.add_argument(
- "--vlog",
- action="store",
- required=False,
- type=int,
- help=(
- "Python logging level. See the levels at "
- "https://docs.python.org/3/library/logging.html#logging-levels"
- ),
- )
-
- args = parser.parse_args()
-
- logging.basicConfig(level=args.vlog)
-
- session = freestyle.FreeStyleHidSession(
- None, args.device, args.text_cmd_type, args.text_reply_type
- )
-
- session.connect()
-
- while True:
- if sys.stdin.isatty():
- command = input(">>> ")
- else:
- command = input()
- print(f">>> {command}")
-
- try:
- print(session.send_text_command(bytes(command, "ascii")))
- except exceptions.InvalidResponse as error:
- print(f"! {error}")
-
-
-if __name__ == "__main__":
- main()
diff --git a/reversing_tools/abbott/known-commands.txt b/reversing_tools/abbott/known-commands.txt
deleted file mode 100644
index be3f9f0..0000000
--- a/reversing_tools/abbott/known-commands.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-$getrmndrst,0
-$getrmndr,0
-$rmdstrorder?
-$actthm?
-$wktrend?
-$gunits?
-$clktyp?
-$alllang?
-$lang?
-$inslock?
-$actinscal?
-$iobstatus?
-$foodunits?
-$svgsdef?
-$corsetup?
-$insdose?
-$inslog?
-$inscalsetup?
-$carbratio?
-$svgsratio?
-$mlcalget,3
-$cttype?
-$bgdrop?
-$bgtrgt?
-$bgtgrng?
-$ntsound?
-$btsound?
-$custthm?
-$taglang?
-$tagsenbl?
-$tagorder?
-$result?
-$gettags,2,2
-$frststrt?
-$marketlev?
-$brandname?
-$uom?
-$temp?
-$cksm?
-$vrom?
-$sn?
-$serlnum?
-$history?
-$ptname?
-$swver?
-$date?
-$time?
-$ptid?
diff --git a/reversing_tools/abbott/known-commands.txt.license b/reversing_tools/abbott/known-commands.txt.license
deleted file mode 100644
index c662d53..0000000
--- a/reversing_tools/abbott/known-commands.txt.license
+++ /dev/null
@@ -1,3 +0,0 @@
-SPDX-FileCopyrightText: 2013 The glucometerutils Authors
-
-SPDX-License-Identifier: MIT