Synchronize Bluetooth LE and Classic bond keys between Windows and Linux in dual-boot setups
Project description
btkey_sync
Syncs Bluetooth LE bonding (LTK / EDIV / ERand) from BLE devices between any two "sides": dual-boot operating systems, two partitions/installs of the same OS, or two separate physical machines — without having to re-pair the physical device on every switch.
See
REQUIREMENTS.mdfor the full functional scope andAGENTS.mdif you're using an AI agent (Claude Code, etc.) to maintain/extend this project.
Why this exists
Some budget BLE devices (mice, keyboards) use private MAC addresses that rotate between pairing sessions (RPA). Windows and Linux store bonding data in completely different formats and paths:
| Windows | Linux (BlueZ) | |
|---|---|---|
| Location | HKLM\SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters\Keys |
/var/lib/bluetooth/<adapter>/<device>/info |
| Required access | SYSTEM account (Administrator is not enough) | root |
| EDIV/ERand format | Hexadecimal | Decimal |
| Hot reload | — | No: requires systemctl restart bluetooth |
This project automates extraction, conversion, and writing on both sides,
leaving the exchangeable files in an exports/ folder intended to be copied
manually between partitions (there's no way to sync this live without a
daemon running on both OSes simultaneously).
Installation
No external dependencies required for normal use (only Python ≥3.10 stdlib).
git clone <this-repo>
cd btkey_sync
# Optional, only if running tests with pytest:
pip install -e ".[dev]" --break-system-packages
Usage
Export (on the system where the device IS connecting successfully)
Linux:
sudo python3 -m btkey_sync
Windows (PowerShell or CMD as Administrator):
python -m btkey_sync
Interactive flow:
- Detects the OS automatically.
- Lists BLE devices with bonding found.
- You choose which one to export.
- Generates
exports/<MAC>__<os>__<timestamp>.reg+.jsonwith the same info in plain text.
Copy the file to the destination
Copy the generated .reg file (USB, shared partition, local network,
whatever you have at hand) to the exports/ folder of the target
installation — this can be the other OS (dual boot), another
partition/install of the same OS, or the equivalent on another machine.
Import (on the system that needs the bonding)
sudo python3 -m btkey_sync --import filename.reg
Shows locally known devices, lets you confirm or change the destination MAC (important if the device rotated its RPA address since last time), writes the bonding, and automatically restarts the Bluetooth stack.
Project structure
btkey_sync/
├── cli.py # orchestrates the 4-step flow
├── models.py # BondKey: OS-agnostic bonding representation
├── platform_detect.py # Windows/Linux detection + environment validation
├── storage.py # manages the exports/ folder and naming convention
├── backends/
│ ├── base.py # interface all backends must implement
│ ├── windows_backend.py # Windows registry via SYSTEM scheduled task
│ └── linux_backend.py # BlueZ info files in /var/lib/bluetooth
├── exporters/reg_exporter.py # BondKey -> .reg content
└── importers/reg_importer.py # .reg -> BondKey
Testing
python3 tests/test_parsing.py
# or, if you installed pytest:
pytest
Tests use data from a real confirmed-working migration
(tests/fixtures/sample_mouse.reg), including the round-trip case with
a MAC change (rotated RPA).
To test a backend without touching your real system, inject a temporary directory:
from pathlib import Path
from btkey_sync.backends.linux_backend import LinuxBluetoothBackend
backend = LinuxBluetoothBackend(bluetooth_dir=Path("/tmp/fake_bluetooth"))
Known limitations
- No automatic/live sync between the two sides — always requires a manual step of copying the exported file to the destination.
- BLE only (SMP/LTK). Does not cover Bluetooth Classic (BR/EDR).
- If the device uses RPA and rotates its address, the export→copy→import cycle must be repeated; this project does not resolve IRK automatically.
- Windows and Linux only. No macOS backend (see
AGENTS.mdif you want to add one).
License / use
Personal project for managing your own equipment. Use at your own discretion; you are touching internal structures not officially documented by Microsoft or the BlueZ project.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file btkey_sync-0.1.1.tar.gz.
File metadata
- Download URL: btkey_sync-0.1.1.tar.gz
- Upload date:
- Size: 42.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd71c0dbc5e556b7d0b9f69c0b823ed437ff2e42b926d280d897697c85c4c506
|
|
| MD5 |
9be822168b899dab514533c118f1d1b8
|
|
| BLAKE2b-256 |
5703638ba67d3906473622acc9b56ce90e3bba882eee3a0788b09f8193db85c9
|
Provenance
The following attestation bundles were made for btkey_sync-0.1.1.tar.gz:
Publisher:
workflow.yml on netssv/btkey_sync
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
btkey_sync-0.1.1.tar.gz -
Subject digest:
dd71c0dbc5e556b7d0b9f69c0b823ed437ff2e42b926d280d897697c85c4c506 - Sigstore transparency entry: 2011410362
- Sigstore integration time:
-
Permalink:
netssv/btkey_sync@b82a8cb4b152e7b07b689f7c3e37d6341acbc6d7 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/netssv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@b82a8cb4b152e7b07b689f7c3e37d6341acbc6d7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file btkey_sync-0.1.1-py3-none-any.whl.
File metadata
- Download URL: btkey_sync-0.1.1-py3-none-any.whl
- Upload date:
- Size: 54.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61a16cb23d95b2d15b76c8f5990ff3fbdbbe16edc7dfc48e34fd570b8dc1be0c
|
|
| MD5 |
98130a0f2f57b0fc1e67ace803f81770
|
|
| BLAKE2b-256 |
5631f45c4a3936cd8b7246a5bf17000a28b5db04f6e80d30e490b1f2bef0737a
|
Provenance
The following attestation bundles were made for btkey_sync-0.1.1-py3-none-any.whl:
Publisher:
workflow.yml on netssv/btkey_sync
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
btkey_sync-0.1.1-py3-none-any.whl -
Subject digest:
61a16cb23d95b2d15b76c8f5990ff3fbdbbe16edc7dfc48e34fd570b8dc1be0c - Sigstore transparency entry: 2011410531
- Sigstore integration time:
-
Permalink:
netssv/btkey_sync@b82a8cb4b152e7b07b689f7c3e37d6341acbc6d7 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/netssv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@b82a8cb4b152e7b07b689f7c3e37d6341acbc6d7 -
Trigger Event:
push
-
Statement type: