Skip to content

Commit 574d85b

Browse files
committed
py: detect BitBox02 Plus
This also introduces new signed firmware magic headers, chosen randomly.
1 parent 23a7d69 commit 574d85b

File tree

4 files changed

+36
-15
lines changed

4 files changed

+36
-15
lines changed

py/bitbox02/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- SD card: Remove API to prompt removal of the microSD card from the device
99
- Add support for regtest (supported from firmware version v9.21.0)
1010
- btc_sign: allow identifying outputs belonging to different accounts of the same keystore
11+
- Detect BitBox02 Plus
1112

1213
# 6.3.0
1314
- Allow infering product and version via API call instead of via USB descriptor

py/bitbox02/bitbox02/bitbox02/bootloader.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@
2323

2424
from bitbox02.communication import TransportLayer
2525

26-
from bitbox02.communication.devices import DeviceInfo, parse_device_version
26+
from bitbox02.communication.devices import (
27+
DeviceInfo,
28+
parse_device_version,
29+
BB02MULTI_BOOTLOADER,
30+
BB02BTC_BOOTLOADER,
31+
BITBOX02PLUS_MULTI_BOOTLOADER,
32+
BITBOX02PLUS_BTC_BOOTLOADER,
33+
)
2734

2835
BOOTLOADER_CMD = 0x80 + 0x40 + 0x03
2936
NUM_ROOT_KEYS = 3
@@ -35,9 +42,10 @@
3542
assert MAX_FIRMWARE_SIZE % CHUNK_SIZE == 0
3643
FIRMWARE_CHUNKS = MAX_FIRMWARE_SIZE // CHUNK_SIZE
3744

38-
SIGDATA_MAGIC_STANDARD = struct.pack(">I", 0x653F362B)
39-
SIGDATA_MAGIC_BTCONLY = struct.pack(">I", 0x11233B0B)
40-
SIGDATA_MAGIC_BITBOXBASE_STANDARD = struct.pack(">I", 0xAB6BD345)
45+
SIGDATA_MAGIC_BITBOX02_MULTI = struct.pack(">I", 0x653F362B)
46+
SIGDATA_MAGIC_BITBOX02_BTCONLY = struct.pack(">I", 0x11233B0B)
47+
SIGDATA_MAGIC_BITBOX02PLUS_MULTI = struct.pack(">I", 0x5B648CEB)
48+
SIGDATA_MAGIC_BITBOX02PLUS_BTCONLY = struct.pack(">I", 0x48714774)
4149

4250
MAGIC_LEN = 4
4351

@@ -69,9 +77,10 @@ def parse_signed_firmware(firmware: bytes) -> typing.Tuple[bytes, bytes, bytes]:
6977
raise ValueError("firmware too small")
7078
magic, firmware = firmware[:MAGIC_LEN], firmware[MAGIC_LEN:]
7179
if magic not in (
72-
SIGDATA_MAGIC_STANDARD,
73-
SIGDATA_MAGIC_BTCONLY,
74-
SIGDATA_MAGIC_BITBOXBASE_STANDARD,
80+
SIGDATA_MAGIC_BITBOX02_MULTI,
81+
SIGDATA_MAGIC_BITBOX02_BTCONLY,
82+
SIGDATA_MAGIC_BITBOX02PLUS_MULTI,
83+
SIGDATA_MAGIC_BITBOX02PLUS_BTCONLY,
7584
):
7685
raise ValueError("invalid magic")
7786

@@ -87,9 +96,10 @@ class Bootloader:
8796
def __init__(self, transport: TransportLayer, device_info: DeviceInfo):
8897
self._transport = transport
8998
self.expected_magic = {
90-
"bb02-bootloader": SIGDATA_MAGIC_STANDARD,
91-
"bb02btc-bootloader": SIGDATA_MAGIC_BTCONLY,
92-
"bitboxbase-bootloader": SIGDATA_MAGIC_BITBOXBASE_STANDARD,
99+
BB02MULTI_BOOTLOADER: SIGDATA_MAGIC_BITBOX02_MULTI,
100+
BB02BTC_BOOTLOADER: SIGDATA_MAGIC_BITBOX02_BTCONLY,
101+
BITBOX02PLUS_MULTI_BOOTLOADER: SIGDATA_MAGIC_BITBOX02PLUS_MULTI,
102+
BITBOX02PLUS_BTC_BOOTLOADER: SIGDATA_MAGIC_BITBOX02PLUS_BTCONLY,
93103
}.get(device_info["product_string"])
94104
self.version = parse_device_version(device_info["serial_number"])
95105
# Delete the prelease part, as it messes with the comparison (e.g. 3.0.0-pre < 3.0.0 is

py/bitbox02/bitbox02/communication/bitbox_api_protocol.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from .devices import parse_device_version, DeviceInfo
3232

3333
from .communication import TransportLayer
34-
from .devices import BITBOX02MULTI, BITBOX02BTC
34+
from .devices import BITBOX02MULTI, BITBOX02BTC, BITBOX02PLUS_MULTI, BITBOX02PLUS_BTC
3535

3636
try:
3737
from .generated import hww_pb2 as hww
@@ -182,6 +182,7 @@ class Platform(enum.Enum):
182182
"""Available hardware platforms"""
183183

184184
BITBOX02 = "bitbox02"
185+
BITBOX02PLUS = "bitbox02-plus"
185186

186187

187188
class BitBox02Edition(enum.Enum):
@@ -541,9 +542,9 @@ def __init__(
541542

542543
if device_info is not None:
543544
version = device_info["serial_number"]
544-
if device_info["product_string"] == BITBOX02MULTI:
545+
if device_info["product_string"] in (BITBOX02MULTI, BITBOX02PLUS_MULTI):
545546
edition = BitBox02Edition.MULTI
546-
elif device_info["product_string"] == BITBOX02BTC:
547+
elif device_info["product_string"] in (BITBOX02BTC, BITBOX02PLUS_BTC):
547548
edition = BitBox02Edition.BTCONLY
548549
else:
549550
version, _, edition, _, _ = self.get_info(transport)
@@ -696,11 +697,11 @@ def get_info(
696697
version_str = version.rstrip(b"\0").decode("ascii")
697698

698699
platform_byte, response = response[0], response[1:]
699-
platform = {0x00: Platform.BITBOX02}[platform_byte]
700+
platform = {0x00: Platform.BITBOX02, 0x02: Platform.BITBOX02PLUS}[platform_byte]
700701

701702
edition_byte, response = response[0], response[1:]
702703
edition: Union[BitBox02Edition]
703-
if platform == Platform.BITBOX02:
704+
if platform in (Platform.BITBOX02, Platform.BITBOX02PLUS):
704705
edition = {0x00: BitBox02Edition.MULTI, 0x01: BitBox02Edition.BTCONLY}[edition_byte]
705706
else:
706707
raise Exception("Unknown platform: {}".format(platform))

py/bitbox02/bitbox02/communication/devices.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
BITBOX02MULTI = "BitBox02"
2727
BITBOX02BTC = "BitBox02BTC"
2828

29+
BITBOX02PLUS_MULTI_BOOTLOADER = "bb02p-bl-multi"
30+
BITBOX02PLUS_BTC_BOOTLOADER = "bb02p-bl-btconly"
31+
BITBOX02PLUS_MULTI = "bb02p-multi"
32+
BITBOX02PLUS_BTC = "bb02p-btconly"
33+
2934

3035
class TooManyFoundException(Exception):
3136
def __init__(self, count: int) -> None:
@@ -111,6 +116,8 @@ def get_any_bitbox02s() -> List[DeviceInfo]:
111116
"""
112117
devices = get_bitbox02multi_devices()
113118
devices.extend(get_bitbox02btc_devices())
119+
devices.extend(get_devices(BITBOX02PLUS_MULTI))
120+
devices.extend(get_devices(BITBOX02PLUS_BTC))
114121
return devices
115122

116123

@@ -138,6 +145,8 @@ def get_any_bitbox02_bootloaders() -> List[DeviceInfo]:
138145
"""
139146
devices = get_bitbox02multi_bootloaders()
140147
devices.extend(get_bitbox02btc_bootloaders())
148+
devices.extend(get_devices(BITBOX02PLUS_MULTI_BOOTLOADER))
149+
devices.extend(get_devices(BITBOX02PLUS_BTC_BOOTLOADER))
141150
return devices
142151

143152

0 commit comments

Comments
 (0)