iOS Central with BlueZ Peripheral disconnect due to insufficient auth
This issue started occurring in Bluez v5.48 after the battery GATT characteristic was moved into the DBUS org.bluez.Battery1 interface. When a Pi and iOS device connect, the Pi attempts to read the iOS battery characteristic. A pair request is then triggered because either Apple has protected this characteristic from unpaired reads or something in Bluez erroneously determines that this characteristic is protected. I've found two different ways to fix this issue without recompiling Bluez.
Easy Solution: Prevent the Bluez battery plugin from loading at boot. You will need to modify the bluetooth service file located at the following path: /lib/systemd/system/bluetooth.service . In this file, go to the line that begins with "ExecStart" and make sure that this line has "ExecStart=/usr/lib/bluetooth/bluetoothd -P battery" (without the surrounding quotes). This -P option prevents any listed plugins from loading.
Custom Solution: Write your own custom agent that auto-accepts pairing requests. I used the Bluez simple-agent example and modified it so that the RequestPinCode function always returned successfully instead of asking for input. The downside of this type of approach is that this still asks the iOS user to pair. Although, this can be a positive outcome if you want to have the reliability and encryption access from a fully paired bluetooth connection.
Private vs public addresses in Bluetooth low energy on Android
Since nobody else seems to have an answer to offer I started testing on my own.
I tried making an app that creates a device from a string representation of an address and tried setting up my device with the 48 bit address alternating the public or private bit to see what the Android stack does.
private final BluetoothGattCallback leGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("Fisken", "Gatt connected " + gatt.getDevice().getAddress() + " status " + status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.w("Fisken", "Disconnect and close");
gatt.disconnect();
gatt.close();
}
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("Fisken", "Gatt disconnected " + gatt.getDevice().getAddress() + " status " + status);
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.w("Fisken", "Disconnect and close");
gatt.disconnect();
}
gatt.close();
}
}
};
BluetoothAdapter mBluetoothAdapter = ((BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter();
BluetoothDevice d = mBluetoothAdapter.getRemoteDevice("FF:55:44:33:22:11");
d.connectGatt(this, false, leGattCallback);
With this code, if I start my BLE peripheral with a random address everything works as expected. However, if I try running it with the same address with the public bit set, logcat says "Gatt connected", but that's just not true. And I'm never able to disconnect.
Update: I did some more testing to figure this out. The onConnectionStateChange event I get is just the connection attempt timing out. The status is set to either 133 (if I get STATE_CONNECTED) or 257 (if I get a STATE_DISCONNECTED) and I've seen both. In either case I should (and now do in the sample code) cancel the connection attempt and close the client.
I've also found out that if I do a scan first, so that the device I'm trying to connect to have been seen recently and then do a connect based solely on the device mac address then I am able to connect to both random and public addresses without any trouble.
So this seems to be a bug/and or missing feature in the Android API. It does not allow you to connect to a public address without first having scanned for it. It does however work for random addresses.
Android 5 static bluetooth MAC address for BLE advertising
The MAC Address is a physical address and does not change. In BLE terminology, it is the Public Device Address or BD_ADDR for BR/EDR. I haven't tried it, but reading it with readAddress() should return the same value each time.
What the Android's BLE framework does is NOT use that address when advertising. It rather enables privacy by using Private Resolvable Addresses which may change every few minutes or so but still allow bonded devices to recognize it using the IRK exchanged at bonding.
For obvious privacy reasons, Android's BLE framework does not allow you to set the Controller to use the public address when advertising. So you cannot disable the "address rotating".
Should one create a bond with a Bluetooth LE device
Short answer: the correct, common, and reliable scenario is to bond. Bonding means the connection is secure and the link is trusted. It means that your local device will usually find the remote device even if its address is changing. Pairing/bonding is recommended practice in Bluetooth for security and privacy reasons.
Long answer: since its introduction, incremental versions of the Bluetooth spec have added features to improve the security and privacy of Bluetooth devices. Many devices will not allow you to exchange data or properly track them unless you are paired/bonded (The difference between bonding and pairing is that with bonding, the exchanged keys are stored in the database.)
In Bluetooth Low Energy, the pairing/bonding process consists of three stages:-
Phase 1 - Pairing Feature Exchange
The two connected devices exchange their IO capabilities (e.g. does the device have a keyboard), authentication requirements (e.g. to bond or not to bond) and supported key sizes.
Phase 2 - Authentication and Encryption
Using encryption algorithms a key is generated and used to encrypt the link (this is different for legacy and LESC pairing, but it is beyond the scope of this question).
Phase 3 - Key distribution
Several keys are exchanged between the devices including the CSRK (Connection Signature Resolving Key), the IRK (Identity Resolving Key) and the static address.
Of particular importance to your question is the IRK and the address. Since Bluetooth v4.0, a feature known as LE Privacy allowed the device to continuously change its address to reduce its track-ability. Malicious devices would not be able to track the device implementing this feature, as it actually looks like a series of different devices. In order to resolve the address, the devices need to be previously paired/bonded. If the remote device contains the IRK then it can use that and the random resolvable address to derive the Bluetooth device's original address.
So, going over your criteria:-
- The Bluetooth device is used frequently, but not continuously.
If you are going to disconnect/reconnect frequently, you can pair once with the device and store the keys (i.e. bond). Pairing is no longer needed afterwards as the same keys will be used to encrypt the connection upon disconnection/reconnection.
- Reconnecting should happen as fast as possible
Connection and bonding are two different things. It will take the same amount of time to reconnect regardless of bonding being implemented. However, once the devices are reconnected, it will take some time for the connection to be re-encrypted.
- Bluetooth address changes randomly when the device is powered down
This means that the device is utilising the LE privacy feature. Therefore your device should be bonded with it in order to resolve the private resolvable address.
- The device's name is unknown, null or random
This is usually the case with BLE. The devices are usually identifiable via their address. As such if your devices have previously bonded you will be able to resolve the changing address and identify the remote device.
- The connection is encrypted
You cannot achieve an encrypted connection without pairing first (as per the 3 phases above). With bonding you are storing the keys in your database, therefore ensuring that you can use them in the future to re-encrypt the connection without having to go over the pairing phases.
- The connection uses an overlying API that requires a Bluetooth Device
as parameter for connection.
I am not sure what this means, but is irrelevant to the requirement for bonding.
For further reading on the subject, I recommend visiting the Bluetooth Specification Version 5.0, Vol 3, Part H, Section 2 Security Manager (page 2295)
Related Topics
Running a Program Through Ssh Fails with "Error Opening Terminal: Unknown."
Is There Some Ansible Equivalent to "Failed_When" for Success
What's The Best Way to Move a Directory into Place in a Makefile Install
Debian Sources.List.D Versus Sources.List
Gcc: Linked Libraries in /Usr/Local/Lib Are Not Found, But /Etc/Ld/So.Conf.D/Libc.Conf Lists It
Which Tool Has Replaced Gatttool in Bluez5
What Is Difference Between Sched_Batch and Sched_Other Scheduling
Why Does Sed Leave Many Files Around
What Is The 'Tr' Command in Windows
How to Export Daily Disk Usage to CSV Format in Shell Scripting
Recursively Listing The Contents of a Tar/Zip Archive