Bluetooth dual-booting: Sharing a bluetooth device between linux and windows

If you’ve used Linux for several years across various devices you are going to run into some hazy déja-vus – the feeling that you’ve been here before, facing this problem, getting that error. But it’s been so long that your bookmarks and notes about it are long gone, not to mention any recollection of how or whether you even found a solution.

Sharing a bluetooth device between Windows and Linux is one such experience for me. I had a blutooth keyboard that I never got properly working with both OSes. I eventually spilled sticky, smelly liquid into the keyboard and tossed it. That was years ago. Today, I unpacked a pair of Edifier E25 Bluetooth pc speakers and ran head first into the problem I had faced oh back in 2011, probably:

You can pair the device to your pc in Linux and then pair it in Windows but either OS will render the other’s pairing invalid. Which means that you have to remove the old pairing and ‘repair’ the speakers every time you booted into another OS. Which is so cumbersome you might as well just get a cable out and be done with it.

The reason for this seems to be an attempt at security: The pairing sets a 16/32 character key in the OS’s settings regarding the device which is copied to the device. All Bluetooth devices have a 12 character id, a MAC address like the one on your network adapter, which is public. The shared key seems to be there to prevent that an unknown device steals another’s identity by copying it’s MAC address and presents itself as the known device. On both OSes the shared key is only visible to priviliged system accounts.

Security sidenote: While this is probably sensible, if somewhat doubtful, security it does mean that every time you pair the speakers with one device, it is lost for all other devices. And given that the E25s are apparently permanently set to ‘slutty mode’, i.e. always advertising themselves as available (because God forbid we should have to press a button for that) it seems kinda pointless. What it means for me, is that I cannot accidentally broadcast my music to the wrong device but anybody within range can blast their music to my speakers. Not really helpful.

Back to dual-booting. The solution is fortunately fairly simple and not all that surprising if you’re used to dualbooting: Let Windows have its way and leave it to Linux to be the grownup that adjusts. Basically, you pair the device in linux so that it has an entry, then allow Windows to pair it (thus overwriting Linux’ key on the Bluetooth device with it’s own key), excavate the secret key from the Windows registry and copy it into Linux’ entry for the device. Reboot and the device should work in both OSes without further pairing (note that in Bluetooth parlance ‘pairing’ is the first time you connect two devices and vouch for each to the other).

The top search results for this are getting on in years and are not quite as detailed or correct as could be desired so I’ll recap and update here as well as I can.

1. Linux: Initial setup

This part is simple. Setup your device in linux, using whatever your usually do Bluetooth in – GNOME’s applet, CLI, whatever. Pair it, check to see that it works.

Now we need to make some notes of device ids so that we are sure that we are investigating the same device across OSes. The Bluetooth chip in your computer or BT dongle is known as a controller. Everything else are just ‘devices’. We want the id for your controller and the device you’re trying to setup.

In a terminal start bluetoothctl. This is a shell-like program that allows you to control your bluetooth devices using special commands. On my terminal bluetoothctl immediately lists all controllers and devices and their ids. If not you can get the controllers by issuing the command list and the devices with the devices command:

[bluetooth]# list
Controller 5C:C5:D4:84:8D:0B JAHILIA [default]
[bluetooth]# devices
Device 00:02:3C:39:AB:93 Creative D100
Device 40:EF:4C:C8:76:93 EDIFIER Luna Eclipse

As I said, the id is the 12 character strings (separated by colons every two characters). If you have multiple controllers (e.g. if your computer has an internal Bluetooth chip but you’ve also got a USB Bluetooth dongle) you need to find out which one is used for the connection. Mostly though, you’ll only have the one. Make a note of the controller id and the correct device id. For my E25s the correct id is obviously 40:EF:4C:C8:76:93.

Now we’ll just quickly check in on the Linux Bluetooth entry. On my Fedora 22 system (and in user accounts on the internet stretching back to 2010) it is in a directory structure under /var/lib/bluetooth:

[~] ls -lh /var/lib/bluetooth/
total
drwx------. 5 root root 4096 26 sep 13:39 5C:C5:D4:84:8D:0B

The controller id is a directory. Everything that is connected to this controller will get a listing under this directory. As you can see there is no access here for non-privileged users so we switch to root and investigate the 5C:C5:D4:84:8D:0B directory:

[~] ll /var/lib/bluetooth/5C\:C5\:D4\:84\:8D\:0B/
total 16
drwx------. 2 root root 4096 20 sep 17:17 00:02:3C:39:AB:93
drwx------. 2 root root 4096 26 sep 13:37 40:EF:4C:C8:76:93
drwx------. 2 root root 4096 26 sep 14:10 cache
-rw-------. 1 root root   51 26 sep 13:39 settings

We go into the the directory for the relevant device id (“40:EF:4C:C8:76:93”) and peek at the info file therein:

[~] ll /var/lib/bluetooth/5C\:C5\:D4\:84\:8D\:0B/40\:EF\:4C\:C8\:76\:93/
total 4
-rw-------. 1 root root 333 26 sep 13:37 info
[~] cat /var/lib/bluetooth/5C\:C5\:D4\:84\:8D\:0B/40\:EF\:4C\:C8\:76\:93/info
[LinkKey]
Key=76D1A2A7C99D9E258B189039CAD51325
Type=4
PINLength=0

[General]
Name=EDIFIER Luna Eclipse
Class=0x240428
SupportedTechnologies=BR/EDR;
Trusted=true
Blocked=false
Services=0000110b-0000-1000-8000-00805f9b34fb;0000110c-0000-1000-8000-00805f9b34fb;0000110d-0000-1000-8000-00805f9b34fb;0000110e-0000-1000-8000-00805f9b34fb;

As you can see linux has set a ‘Key’ value that identifies the speakers to it (“76D1A2A7C99D9E258B189039CAD51325”). This is the one we will overwrite with whatever Windows decides on in a minute.

2. Windows: Pairing

Again, this should be fairly simple (though the Bluetooth setup in anything before Windws 8 is pretty terrible AFAIR). Boot into Windows and pair the device with Windows. You may have to turn the device off and on again. For whatever reasons Bluetooth connections can be kinda ‘sticky’: Even after the connecting device has called it quits the passive device seems reluctant to accept new connections. So if you’re having problems, always turn off and on again.

You can try to find the device in the Windows registry but Windows is even more protective of these keys than Linux and so will normally deny access even to administrators. We will find the Windows key when we’re back in Linux but here’s the registry address on Windows 8 if you want to try:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BTHPORT\Parameters
3. Linux: Key extraction

Reboot into Linux and mount your Windows partition. Then copy the file containing the system registry to /tmp (we don’t want to risk inadvertently writing to the Windows registry when all we need to do is read):

cp /[Windows partition mount]/Windows/System32/config/SYSTEM /tmp/

Install chntpw using your package manager. In Fedora the package was simply called chntpw (which I take to mean CHange NT PassWord and is probably originally a Windows users’ tool to get back into Windows after forgetting the password).

Now we use the chntpw tool on our new registry copy in the /tmp directory. We navigate the registry using the familiar shell tree navigation tools ls and cd. And seeing as we start at the SYSTEM part of the registry tree we don’t need to go into HKEY_LOCAL_MACHINE or the like.  I cd’ed my way to ControlSet001\Services\BTHPORT\Parameters\Keys. Here I cd’ed into the controller id ” 5cc5d4848d0b” (note: lowercase, no colons). Here we ls to list the devices:

(...)\BTHPORT\Parameters\Keys\5cc5d4848d0b> ls
Node has 0 subkeys and 2 values
  size     type            value name             [value if type DWORD]
    16  REG_BINARY        <00023c39ab93>
    16  REG_BINARY        <40ef4cc87693>

Recognizing “40ef4cc87693” as my device id, I read the key using the hex command:

(...)\BTHPORT\Parameters\Keys\5cc5d4848d0b> hex 40ef4cc87693
Value <40ef4cc87693> of type REG_BINARY, data length 16 [0x10]
:00000  76 D1 A2 A7 C9 9D 9E 25 8B 18 90 39 CA D5 13 25 Y#....L.....}..#

And there’s the key we need (highlighted in bold).

4. Linux: Key insertion

All we need now is to overwrite the key Linux used when pairing the device with the key that Windows issued. Open the info file we looked at earlier as root, delete the old key and copy-paste the new one in:

sudo nano /var/lib/bluetooth/[controller id]/[device id]/info

Find the ‘Key=’-line and insert the key without the spaces:

[LinkKey]
Key=76D1A2A7C99D9E258B189039CAD51325
Type=4
PINLength=0

Save, exit and reboot.

5. Linux and Windows: Daily usage

I have found that while I do not need to remove and redo the pairing, the handover when dualbooting isn’t as smooth as all that. Windows will grab the speakers regardless of previous connections but when I need to connect in Linux, I have to power off the device after it has been connected in Windows. Maybe it’s a GNOME thing but in order for it to work consistently I leave the speakers on when I boot into Linux. Only when GNOME is done starting up do I power them off and on – and only then do they connect. Turning them off and on mid-reboot is apparently not enough though whether that has anything to do with dual-booting is debatable.

Ressources:

Photo by Nationalmuseet

Leave a Reply

Your email address will not be published. Required fields are marked *