Android Bluetooth Low Energy Pairing
Asked Answered
B

3

36

How to pair a Bluetooth Low Energy(BLE) device with Android to read encrypted data.

Using the information in the Android BLE page, I am able to discover the device, connect to it, discover services and read un-encrypted characteristics.

When I try to read an encrypted characteristic (one that will cause iOS to show a popup asking to pair and then complete the read) I am getting an error code 5, which corresponds to Insufficient Authentication.

I am not sure how to get the device paired or how to provide the authentication information for the read to complete.

I toyed with BluetoothGattCharacteristics by trying to add descriptors, but that did not work either.
Any help is appreciated!

Brookebrooker answered 12/8, 2013 at 22:5 Comment(3)
Any updates on this? I am facing same issue.Caelian
I have yet to find a solution to this. I do know that if you set the auto-connect flag in the connectGatt function to true you will find that the device shows up in the paired list, but because of other connect bugs I have not been able to test and see if this actually allows encryption.Brookebrooker
@Zomb- I am working on same in which I am trying to scan the BLE devices but fails to achieve it. Please if you have any idea how to scan the BLE device, please assist.Caskey
D
25

When you get the GATT_INSUFFICIENT_AUTHENTICATION error, the system starts the bonding process for you. In the example below I'm trying to enable notifications and indications on glucose monitor. First I'm enabling the notifications on Glucose Measurement characteristic which can cause the error to appear.

@Override
    public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
                mCallbacks.onGlucoseMeasurementNotificationEnabled();

                if (mGlucoseMeasurementContextCharacteristic != null) {
                    enableGlucoseMeasurementContextNotification(gatt);
                } else {
                    enableRecordAccessControlPointIndication(gatt);
                }
            }

            if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
                mCallbacks.onGlucoseMeasurementContextNotificationEnabled();
                enableRecordAccessControlPointIndication(gatt);
            }

            if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) {
                mCallbacks.onRecordAccessControlPointIndicationsEnabled();
            }
        } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) {
            // this is where the tricky part comes

            if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
                mCallbacks.onBondingRequired();

                // I'm starting the Broadcast Receiver that will listen for bonding process changes

                final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
                mContext.registerReceiver(mBondingBroadcastReceiver, filter);
            } else {
                // this situation happens when you try to connect for the second time to already bonded device
                // it should never happen, in my opinion
                Logger.e(TAG, "The phone is trying to read from paired device without encryption. Android Bug?");
                // I don't know what to do here
                // This error was found on Nexus 7 with KRT16S build of Andorid 4.4. It does not appear on Samsung S4 with Andorid 4.3.
            }
        } else {
            mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status);
        }
    };

Where the mBondingBroadcastReceiver is:

private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(final Context context, final Intent intent) {
        final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
        final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1);

        Logger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState);

        // skip other devices
        if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress()))
            return;

        if (bondState == BluetoothDevice.BOND_BONDED) {
            // Continue to do what you've started before
            enableGlucoseMeasurementNotification(mBluetoothGatt);

            mContext.unregisterReceiver(this);
            mCallbacks.onBonded();
        }
    }
};

Remember to unregister the broadcast receiver when exiting the activity. It may have not been unregistered by the receicver itself.

Detraction answered 20/11, 2013 at 10:43 Comment(12)
Thanks for the answer! On a 4.3 Nexus 7, the problem is that there is no callback when the read fails due to authentication. It just prints status 5 to the console and dies. I will check and see if I can get the BondStateChanged intent even though there was no callback from the read. I suspect I might have to call create bond (4.4 API) at the beginning to kick of the process, which I will try when my Nexus 7 gets updated.Brookebrooker
I can confirm that this now works with 4.4. When I try to read an encrypted char, the bonding and key exchange is kicked off. While I do not get back status 5, I do get back a status 137 (not sure what this is) as a response to the char read when the bonding is complete. I can then read the encrypted char again to retrieve the data. The paired device also shows up in the Bluetooth device list.Brookebrooker
Yes, it was fixed on Nexuses with Android 4.4.1. Right now the error NO 5 (insufficient authentication) does not came at all so you have to register the bonding broadcast listener earlier (f.r before calling connectGatt(..). Here you can find more error numbers: android.googlesource.com/platform/external/bluetooth/bluedroid/…Detraction
What is mCallbacks? Is there an implementation for onBonded()? Also, mContext? Is this just getApplicationContext()?Bugger
yup @Detraction i am also getting this error .device are already bonded while connecting second time while writing descriptor value can any work around for this? this happen only when i use createBond() method which are available in kitkat seriously this is bull shit.Illailladvised
I was getting this error when reading characteristic, without createBond(). However since 4.4.1 I never got that error again (tested on Nexus 4,5,7).Detraction
I'm getting gatt error 15 (GATT_INSUFFICIENT_ENCRYPTION) while try read characteristic on Samsung S4 (4.4.2). What is that?Missioner
It means that the device requires bonding (encrypted transmission). Usually after few moments the phone will automatically bond to the device, or you may call createBond() on Android 4.4+ after connecting, f.e before service discovery.Detraction
Does anyone know what should be done if you can get to the insufficient authentication error, but bonding never succeeds? I start createBond(), and then get two callbacks, one with BOND_BONDING and the second with BOND_NONE, followed by GATT_DISCONNECT. it seems the BT tries to write my characteristic, and then a second one with an all 0's uuid. I've tried setWriteType to all three, and get three different results, but none are successful. (NEXUS 4, android 4.4)Look
What is the mCallbacks variable?Diablerie
Just a way to propagate the information to other layer (UI, service, etc). Have a look at the current implementation here: github.com/NordicSemiconductor/Android-nRF-Toolbox/blob/master/…. It's a base class that handles all the BLE events and can be used with a simple API. There are examples how to use it in different profiles in this app.Detraction
Why register the receiver when getting GATT_INSUFFICIENT_AUTHENTICATION instead of waiting for having a bond before starting the connection?Laclair
P
0

You might need to check the Kernel smp.c file, which method of paring it invoke for paring. 1) passkey 2)Just work or etc . i guess if it will be able to invoke MIMT and passkey level of security , there will not be any authentication issue. Make sure all flags is set to invoke the SMP passkey methods. track by putting some print in smp.c file.

A solution which works in ICS : with btmgmt tool in android and hooking it in encryption APIs. with passkey or any other methods. it works. You might need to add the passkey APIs in btmgmt from latest bluez code.

Porphyry answered 1/10, 2013 at 7:25 Comment(4)
I am not sure if I understand this. Are you talking about enabling encryption on the Android side or the BLE device side? Because Android for starters uses bluedroid and not bluez for BLE. Making changes to the kernel and recompiling Android to detect how to enable encryption is something I was hoping to avoid.Brookebrooker
Here is some check point , which you need to make sure, 1) Verify your android device support BLE security eg. setting encryption and setting passkey or OOB or just work. If it support passkey, every thing is possible. you in that case you need to enter the correct passkey as mentioned on BLE sensor, for which you will get a pop up on android to enter passkey.Porphyry
2) kernel side , which u do not want to change , security should be enable , let me know which kernel version are you using ?Porphyry
@Porphyry How to perform OOB from android side. Any sample codesCelebrity
I
0

i think new android 4.4 provide pairing method. same problem already i am facing so wait for update and hope over problem solved createBond() method .

http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#setPairingConfirmation%28boolean%29

Illailladvised answered 3/11, 2013 at 13:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.