We are designing a small hardware device (call it the "puck") that communicates over BLE, and an app for Android & iOS to talk to it. We have an app (written in C#/Xamarin) that is connecting to the puck and they are connecting and sending data back and forth.
According to this web site, when the Bluetooth connection is first made, the two devices "pair" which just means they exchange security information.
Question 1: Am I correct in my understanding that the exchange of security information takes place automatically, there's nothing I have to do in my code to cause it to happen?
Question 2: Am I guaranteed that the communication (after the initial exchange of security information, including keys) will be encrypted?
Question 3a: On an Android device, how can I query the connection to find out what security features were agreed upon by the two BLE devices?
Question 3b: Same as 3a but on an iOS device
The puck has no display to speak of (a couple of LEDs and a button) so can't display a PIN for bonding. The plan is to have the user initiate bonding in the mobile app, sending some command over the BLE connection; in response the puck will flash its lights in some pattern and wait for the user to press the button. If the button is pressed within some timeout, bonding should take place.
Question 4: What are the "best practices" for bonding, in order to keep the BLE connection as secure as possible?
1) BLE Security is a complicated thing, and if you are no expert at this, it is best to ensure that the stack on which you build the application is doing this for you. On Android (and also on iOS, I suppose) the built-in stack will do the pairing for you as soon as you have started it, but on your custom built "puck" you will have to ensure this for yourself - or implement a Bluetooth stack that does this correctly (recommended).
2) If implementation is correct, encryption is ensured, yes.
3) I can't tell you this in detail, but when you initiate pairing, there should be a response from the Bluetooth stack; maybe in the return parameters, you can find this information (but I don't know that, and it strongly depends on the API you are using).
4) If the puck has no display and no input possibility except from a button (that can be seen as a Yes/No option, where "Yes" is pressing the button and "No" is not pressing it), your possibilities for pairing are very limited. Expressed as I/O capabilities, this is defined as "NoInputNoOutput" (see CoreSpec v4.2, Vol.3, Part H, chap. 2.3.2), and thus it will always result in an unauthenticated connection (see table 7 in CoreSpec v4.2, Vol.3, Part C, chap. 5.2.2.6). This does not mean that the connection is not encrypted (in fact it is), but you have no protection against Man-in-the-Middle attacks.
Checking if a button is pressed on the puck may be an additional safety measure, but note that an attacker can fake the "Button pressed" message if s/he wants to pair with your app.
Related
I'm working with app development for a HW-driven device company. Our current (BLE) HW-devices communicates with the phone, and when the HW is considered "active" (triggered by a physical activation on the HW), the phone retrieves continuous data from said HW.
In order for the application to be ready for the HW to become active, it is holding a permanent "binding" to the HW. On Android, the application holds a permanent ("sticky") notification, that prevents the app from being killed, and lets the background process stay alive at all times and listens for the HW to announce that it is active. On iOS, I believe that the HW is spamming "ping-requests" to the app in order to keep it alive.
All in all, the setup works, but is not ideal. I've tried to wrap my head around the different "peripheral modes" and master/slave-setups, but have yet to understand how to setup a relationship between phone and HW that behaves as we would like:
We would like to have the HW to behave like (for instance) BT-headphones work, i.e. when I open the case for my headphones, the application starts up (in the case of my earplugs, a battery status notification is shown) and communication starts. When I put the plugs back in the case, the application closes (at least as far as the user can tell). Once the HW is in range again and is activated (i.e. equivalent to opening the case) the app/communication is ready/resumed.
Is the described functionality reserved for headphones only, or is this a setup that can be achieved by any BLE-device?
tl;dr I don't want to have a persistent notification on Android to make sure that the app is always ready when the device is "active", but without it, the app is easily killed in the background.
It is tricky when you ask a question that covers both Android and iOS as both platforms will have different approaches.
I will answer for iOS as that is what I know, but I presume there is something similar on Android.
First, a little on how the BLE GATT service works in simple terms;
In BLE there are two roles; central and peripheral. 99% of the time, the peripheral advertises services and the central discovers peripherals advertising the services it is interested in. The central can then connect to the peripheral.
Once connected, the central can initiate reads from and writes to the peripheral. The central can also register for notifications from the peripheral. This allows the peripheral to send new data when it has it, rather than waiting until the central reads it.
Now, for how you can use all of this in iOS Core Bluetooth.
Your initial task is to discover the peripheral you are interested in. You do this by scanning for a peripheral advertising your specific service. You typically need to provide some sort of UI to show what has been discovered and allow the user to select the device to which they want to connect, but this depends on your specific use case.
Once you have discovered (and the user has selected) a peripheral, you can store the identifier that Core Bluetooth provides. This is a unique value for this peripheral on this iOS device; It is not the peripheral MAC address and it cannot be used on a different iOS device to identify the same peripheral.
In future you can use this identifier to try and retrieve a CBPeripheral object from Core Bluetooth without needing to scan for it.
Once you have a CBPeripheral you can issue a connect. Once the connect completes you can read/write data or register for notifications.
If you have enabled Core Bluetooth background mode in your app then the connect and notification events will be delivered to your app even when it is in the background. You can also issue read and write commands in the background in response to the connect and notification events, although you only have a few seconds execution time.
At some point it is likely that the peripheral will go out of range/be turned off and the connection will disconnect. Again, this event may be delivered in the background or foreground.
In response your app should immediately issue a new connect. If the device is not currently available then this connect will be pending and will complete when/if the peripheral is seen again. iOS will deliver this to your app in the foreground or background.
The final point to consider is the case where your app is not currently in the suspended state; Perhaps the iOS device has been rebooted or your app has been offloaded from memory by iOS because it hasn't been active for some time.
Your app can opt in to Core Bluetooth State Restoration by providing a n identifier parameter when it creates its CBCentralManager. This will relaunch your app.
On relaunch you need to re-establish your CBCentralManager with the same identifier and then you will receive the connect callback that triggered your apps relaunch. From this point you can proceed normally.
This is an article from Apple that, while old, explains Core Bluetooth background and state restoration pretty well.
Note that all of this can happen without pairing/bonding. If your peripheral requires encryption for any of its attributes then iOS will automatically present a pairing dialog the first time you connect. Once this pairing is in place it is not required again. Pairing/bonding only exchanges keys for encryption. It is not explicitly required to allow future connections.
I'm studying the Bluetooth Low Energy (BLE) protocol (v4.2), and in particular its security features.
I'm trying to understand how the encryption of data transmitted between a mobile App and a BLE device works.
The official documentation (v4.2) specifies the methods to encrypt data, authenticate the devices, generate the keys used in the encryption and pairing phase, etc..
First doubt (I want to be sure to have understood some concepts):
all these functions are implemented in the host level, so if I want to encrypt data transmitted between an App (Android) and a BLE device (like a fitness tracker),
do I have to implement (or enable) these methods on the BLE device?
In this way, the developer should only care about the implementation of these features on the BLE device, since the Android Bluetooth stack just support these features. Am I right?
If I'm wrong, what is the right way to implement these features (on both mobile app and BLE device)?
Second doubt:
Why some BLE devices, implement their own cryptography, on top the GATT protocol, instead using the security features provided by the SIG?
Third and last doubt:
Are the security features specified by the SIG mandatory or are optional?
As you can see I have some doubts, and maybe some questions could be silly, so if someone could clarify how the security mechanisms (like encryption) can be implemented between an App and a BLE device,
and at which levels these features are implemented (OS or application level), I will appreciate a lot.
If you use the standard BLE encryption, it is actually the link layer at the controller that does the encryption/decryption/verifying auth tags. But it's the host layer (SMP) that defines how two devices pair, bond and exchange keys. It's also that layer that tells the link layer to start encryption using the exchanged keys. On Android and iOS, it's the OS that manages the pairing and bonding and implements the SMP. Whether or not Bluetooth pairing/bonding/encryption is used is fully up to the device, and is optional. If it's not supported it must still support to send the error code "Pairing Not Supported"
The Bluetooth standard only has one "use case". This use case is to provide a method for securing the link between two devices so that, after bonding, no one should be able to impersonate a device or be able to manipulate or decrypt the traffic. As you might know, the "LE Legacy Pairing" which is the only pairing method specified up to Bluetooth v4.1, has several flaws that makes it unsecure if the attacker sniffs the traffic during pairing (both for "Just works" and "MITM/passkey entry", but not OOB). The new "LE Secure Connections" defined by Bluetooth v4.2 however uses Diffie Hellman to make it more secure.
Even though Bluetooth pairing itself provides security, there are some flaws in both the Android API and the iOS API that still may not be enough for an app developer if good security is needed. Notably, iOS does not provide any API whatsoever to detect if a given device is actually bonded or if a link is encrypted. It does however show a popup to the user when the pairing starts, but the app knows nothing about that pairing. So, from an iOS app's point of view, you don't know:
If you have paired to the device.
If you talk to a genuine device or a chinese copy.
The security level, i.e. if the pairing used Just Works, MITM legacy pairing or LE Secure Connections.
If the current link is encrypted.
Android is a little bit better. There the app can at least know if the device is bonded or not (but not the other three). There is also an API "createBond" to start the bonding process. The Windows API is much better here, since you can enforce encrypted link when doing GATT operations.
Any of these reasons may be enough for a developer to implement the security from scratch on top of GATT instead. In particular one often common use case is that the developer wants the use case "log in to the peripheral" with a PIN or password. The Bluetooth standard does not support that use case in any way (and no, using "MITM protected pairing with static passkey" doesn't work, since that protocol by design reveals the passkey after one or a few tries).
Anyway, if you develop your own peripheral with your own hardware and want to use the Bluetooth standard's pairing/bonding/encryption, the SDKs by the manufacturers of the BLE chips have usually already implemented this. However, you still need to set it up correctly for it to work. Usually you only have to configure some parameters (like if you have a display or the user can enter a passkey) and then the rest is automatically handled internally by their SDK.
UPDATE:
Source code for Android can be found at https://android.googlesource.com/platform/system/bt/, https://android.googlesource.com/platform/packages/apps/Bluetooth/ and https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/bluetooth.
Is it possible to set up the Android Bluetooth Chat sample app to connect more than one person at a time, and have a mini chat room? What would that entail?
tl;dr version: Bluetooth sucks for this, don't use it, use wifi instead, probably backed by a web backend.
I have investigated this issue thoroughly throughout the years in the interests of a social wireless network research project. My general advice is: it doesn't work with more than two / three people. Bluetooth just isn't designed with wireless peer to peer networks in mind.
In general, it seems that the cheap Bluetooth controllers included on Android devices (especially HTC's devices, iirc) don't really handle any more than two or three connections at a time. I'm unsure if this is a hardware or firmware problem, but I can recount some basic anecdotes. I was working to implement this idea at the SDK level (i.e., without firmware modifications) around the beginning of 2011, and was able to get a peer to get two additional connections (i.e., three devices, each connecting to the other two) to work for a period of a few minutes to an hour before the connections would suddenly die and the socket would become unusable, requiring reconnection. Unfortunately, 20 minutes was an upper bound, and generally it was impossible to get connections to more than one other device at all reliably.
The goal of the project was to support multiple people interacting with each other silently in the background, but this never materialized, instead we ditched Bluetooth and went with wifi instead, which worked much much better. In the abstract, I think people view Bluetooth as a possible medium for reliable peer to peer communication, but it wasn't really designed that way: it's more of a medium used for short range communication between small devices (think headsets).
Be aware that if you want to do this, the maximum number of devices to which you can connect is fixed, because as per the Bluetooth spec, a piconet supports a maximum of seven devices. (See the wikipedia article.)
The required change is simple: you use a different UUID for each device. This can be implemented a number of ways, using an out of band exchange mechanism, or simple scheme where you assign UUIDs in an increasing fashion and when connecting to the network, try each in succession.
Here are some relevant Google groups threads:
Bluetooth peer to peer networks
Multiple connections on Android Bluetooth
I remember posting a more elaborate one detailing how to do this (with code) that I might dig up as well.., if I can find it. It should be from late 2010 or early 2011.
So the answer is, in the abstract, yes, you can try to do this, by using multiple UUIDs (after you use one, that's it, and you have to try another using some assignment protocol). However, in practice, after a lot of trial and error, this doesn't really work for what you probably want to use it for, and it's a lot better to go with an internet backend instead. By the way, this is also good for another reason, most users don't really like to turn on their Bluetooth for fear of their battery being drained..
Leaving this here, in case it helps someone else.
I was able to make my custom chat room following official bluetooth tutorial and modifying it a little.
Unfortunately, I cannot provide most of my code, but main idea is:
Every device is acts both as server and as a client. When Chat is started, device starts its server thread. Server thread is the same as official but doesn't ends when accept connection. It just keep listening.
Client thread is identical as in tutorial.
Both server and client thread manages connection same. I created separated threads for accepting messages following this tutorial and one for sending them.
private void manageConnectedSocket(BluetoothSocket socket) {
//create thread responsible for sending messages.
SendingThread w = new SendingThread(socket);
MainActivity.addSendingThread(w);
//Creates listener for messages to accept.
MainActivity.addListener(socket);
}
Now in main activity always when user click send button, for each worker (sending thread) send message to remote device. Listening is running asynchronously.
IMPORTANT:
You need to handle exceptions when message send fails and remove sending and recieving thread for device when you detect it is disconected. In my case I used well known UUID "00001101-0000-1000-8000-00805f9b34fb". For every device.
You need to wait 3 second between atempts to connect as client because some devices has weak bluetooth hardware and it is refusing connect as client.
Bt connection is supporting up to 7 -10 connections. So you will be limited in that range. I think it is designed for extensions of main device and not for random comunication
Source: search "bluetooth programming" on google
I am developing an application which connects devices over bluetooth and exchanges messages. It works fine for paired devices, but I would also like it to automatically pair devices that are not paired. Like for example it could store and use the same PIN for pairing requests, I just dont know how to manage this request programatically in my applciation, how to automatically set and send the PIN when you get a pairing request and how to initiate such a request with the predefined PIN code.
Any snippets or thoughts would be highly appreciated! :)
EDIT:
I know its risky, I am developing this app for emergency situations only where no other means but bluetooth is available. Also is there maybe a way of premature pairing with devices without even connecting to them? Like lets say there is a list of MAC Addresses of those devices and I can use them to generate a bond with that devices so that they appear paired on my device?
You can't do this. To do what you want to do would create a huge security risk. Think about it, my device just comes anywhere in bluetooth range of yours and now I can send you anything I want without you knowing? You can't really do this and I highly recommend not trying to subvert it.
Reflecting the setPin method allowed me to send the pin automatically to the other device. I had to implement it in a broadcast receiver that is listening for pairing requests. Although I cant get rid of the dialog it just stucks there on the screen and I dont know how to close it (programatically) and continue the bonding procedure since this dialog is called from inside connect() which is a blocking method. I am not giving up on it yet though :)
With Bluetooth version 2.1 and above there is a method of pairing called the 'just works' association model. This is the lowest security method of pairing and has no protection against man-in-the-middle attacks.
However, this will provide a secure, encrypted link without the need to exchange pin numbers or verify device ID.
The API on different platforms may differ but the underlying HCI messages require that you indicate that your device (or one of the devices) has the following IO capabilities:
No Keyboard, No Display.
As you might have guessed, this is a mode for very
simple devices that use Bluetooth, such as a speaker or headphones.
If you can find the API to configure that, then the 'just works' association mode of Secure Simple Pairing will be used for pairing.
The next step is to store the link keys e.g. bonding. Many devices e.g. mobile phones, will still create a dialogue box to the user to ask if they want to 'remember this device', as user authorisation is specified by the BT specifications... but that's another problem.
I'm aware that Android 2.3 has the methods: createInsecureRfcommSocket() and createInsecureRfcommSocketToServiceRecord(). I've been searching for a way to exchange data between devices, both using my application, without the need for pairing/bonding and user confimation. Will these methods allow me to, say, connect to a brand new device never before paired, and exchange data without prompting the user in any way?
Thanks. I was unable to find a specific answer to this question elsewhere.
The pairing process will still happen, except that if Devices are 2.1 and above, then the user will not be prompted for confirmation or for entering passkey during the pairing process. This is called using the "just works" model for pairing.