summaryrefslogtreecommitdiffstats
path: root/reversing_tools/abbott/extract_freestyle.py
diff options
context:
space:
mode:
Diffstat (limited to 'reversing_tools/abbott/extract_freestyle.py')
-rwxr-xr-xreversing_tools/abbott/extract_freestyle.py245
1 files changed, 0 insertions, 245 deletions
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()