Introduction

This module will cover the fundamentals of Bluetooth low energy (BLE) security including pairing, bonding & privacy. We will discuss why you might want to add these features in your application and cover basic principles.

The lab activities will walk you through pairing & bonding with Project Zero and how to enable privacy features. After completing this lab, you will be able to pair and bond to a mobile device and resolve the peer's identity address.

The tasks in this lab session will use the CC2640R2 LaunchPad development kit, but can be adapted to work on other TI BLE dev kits. This lab should take about 4 hours to complete.

It is recommended to read the TI BLE-Stack User's Guide alongside this lab for details and further information. Some references will also be made to this document. See the Recommended Reading section for details.

Prerequisites

Software for desktop development

For testing, a Bluetooth client application is required:

  • BTool (located in tools → blestack directory of the SimpleLink CC2640R2 SDK installation) OR
  • A Bluetooth Client mobile app - instructions will use the below mobile apps:
    • Android: BLE Scanner by Bluepixel Technology LLP - available on the Google Play store
    • iOS: LightBlue Explorer - Bluetooth Low Energy by Punch Through - available on the App Store

Hardware required

For testing:

  • Additional CC26xx LaunchPad to run host_test OR a smartphone device

Bluetooth Core Specification v4.2

  • [Vol 1] Part A, Section 5.4 – LE Security
  • GAP Bond Manager & LE Secure Connections
  • LE Privacy 1.2

Security Overview

Definitions

  • Pairing: process to create an encrypted link, this should not be confused with forming or establishing a BLE connection between two devices.
  • Bonding: Storage of keys generated during the pairing process needed to resolve peer addresses or re-store encryption on subsequent connections.
  • Privacy: Ability to use new device addresses generated on a regular basis for the purpose of obscuring your identity address from untrusted devices.
  • Resolvable Private Address (RPA): Bluetooth Device Address that changes periodically.
  • Identity Resolving Key (IRK): Key used for Address Resolution (resolves an RPA).
  • Identity Address: An address associated with an RPA that does not change over time. An IRK is required to resolve an RPA to its Identity Address.

Pairing

Passive Eavesdropping Protection

In Bluetooth low energy, information that is shared over the air can be seen by nearby devices other than the intended recipient. Although this interception of packets can not be avoided, encryption can be used to prevent over the air messages from being understood by unknown devices. In order to use encryption, the devices involved must agree on the encryption keys used.

Pairing is the procedure used to create an encrypted link with a peer device in order to prevent passive eavesdropping. In Bluetooth low energy, there are 2 main types of pairing: LE Legacy and LE Secure Connections. LE Legacy pairing was added in Bluetooth Core Specification v4.0. LE Secure Connections was added in Bluetooth Core Specification v4.2. LE Legacy pairing does not prevent passive eavesdropping if the eavesdropper listens in to the pairing process. However, if the LE Legacy pairing is not captured by a listener, the encryption will be secure.

Man-in-the-Middle (MITM) Attacks

Another attack Bluetooth low energy devices can be vulnerable to is a Man-in-the-Middle (MITM) attack. An MITM attack occurs when a malicious device connects to two unsuspecting devices and intercepts messages sent between the devices. The attacking device can inject its own data before passing the message along, making the two devices think they are communicating securely with each other while the attacker controls the communication. The Out-of-Band (OOB), Passkey Entry, and Numeric Comparison pairing method provide protection against MITM attacks. But for LE Legacy Pairing the two association models Just Works and Passkey Entry do not provide any passive eavesdropping protection.

LE Legacy vs LE Secure Connections Pairing

Bluetooth low energy pairing was introduced in Bluetooth Core Specification v4.0. This feature provided a process for two devices in a connection to generate and exchange keys in order to form an encrypted link. LE Legacy Pairing, as it is known, provides little to no protection against passive eavesdropping during the pairing process except when the Out of Band (OOB) Association Model is used.

In Bluetooth Core Specification v4.2, LE Secure Connections Pairing was introduced. This pairing procedure uses Elliptic Curve Diffie-Hellman cryptography which provides protection against passive eavesdropping. The LE Secure Connections feature also added the Numeric Comparison Association Model. By default, the TI BLE-Stack will request a Secure Connections pairing but will accept a LE Legacy pairing if necessary. The TI BLE-Stack can also be configured to accept exclusively LE Legacy or LE Secure Connections pairings.

Pairing Phase 1: Pairing Feature Exchange

The pairing process begins when the Central device sends a Pairing Request command to the Peripheral. Alternatively, a Peripheral can send the Security Request command to request the Central device begin the pairing process. The Central device can choose whether or not to send a Pairing Request after receiving a Security Request. Not all mobile devices support the Security Request command so it is always best to check with the Android and iOS development guidelines before relying on the Security Request command to initiate pairing or encryption.

Pairing Phase 1: Pairing Feature Exchange

A Pairing Request command contains information about the types of pairing supported by the Central device. The Peripheral will respond with a Pairing Response command containing the security features it supports. The combination of supported features will determine what pairing association models are used to generate the encryption keys in Pairing Phase 2.

Pairing Request Command Format
Pairing Response Command Format
Slave Security Request Command Format
Association Models Conditions for Use
Just Works This model is used when there is no Out of Band (OOB) data available and neither device has input capabilities.
Passkey Entry This model is used when there is no OOB data available, at least one device has the I/O capability to enter a passkey, and the other device has the capability to display a passkey.
Out of Band If OOB data is available on both devices, this model will be chosen.

The models here are ranked by perceived level of security. Just works is the least secure and OOB is the most secure. The most secure model supported by both devices will be chosen. For full Association Model requirements, refer to Table 2.7 & Table 2.8 in the Bluetooth Core Specification v4.2 [Vol 3] Part H, Section 2.3.5.1.

In this module, we will cover Just Works and Passkey Entry pairing. The other two models cannot be easily demonstrated with mobile devices.

Pairing Phase 2

During the second phase of pairing, keys are generated and shared in order to encrypt the connection. The types of keys that are generated are dependent on whether LE Legacy or LE Secure Connections pairing is used.

LE Legacy Pairing Phase 2

After the Pairing Response has been received by the Central device in LE Legacy Pairing, confirm values are exchanged. Confirm values are generated in accordance with the Bluetooth Core Specification and sent using the Pairing Confirm command. The LE Legacy Confirm Value Generation Function is described in [Vol 3] Part H, Section 2.2.3.

After the Central receives the Pairing Confirm command from the Peripheral device, the Central will send a Pairing Random command to the Peripheral device with the random number that was used to calculate the Pairing Confirm value in the previous step. The Peripheral will respond with the random number it used for its confirm value. The two devices will check the random number against the confirm values previously exchanged and, if the values match, the pairing will continue. If the check fails, a Pairing Failed command will be sent. Pairing Failed commands contain the reason that the pairing failed and can be extremely useful for debugging.

In LE Legacy pairing, if the Pairing Random exchange succeeds, the link will be encrypted by the Central using the Short Term Key (STK). The process to calculate the STK is described in [Vol 3] Part H, Section 2.2.4 of the Bluetooth Core Specification v4.2. The STK is not shared over the air.

LE Legacy Pairing Phase 2: Short Term Key Generation
Pairing Confirm Command Format
Pairing Random Command Format
Pairing Failed Command Format

Pairing Phase 1: Pairing Feature Exchange

The pairing process begins when the Central device sends a Pairing Request command to the Peripheral. Alternatively, a Peripheral can send the Security Request command to request the Central device begin the pairing process. The Central device can choose whether or not to send a Pairing Request after receiving a Security Request. Not all mobile devices support the Security Request command so it is always best to check with the Android and iOS development guidelines before relying on the Security Request command to initiate pairing or encryption.

Pairing Phase 1: Pairing Feature Exchange

A Pairing Request command contains information about the types of pairing supported by the Central device. The Peripheral will respond with a Pairing Response command containing the security features it supports. The combination of supported features will determine what pairing association models are used to generate the encryption keys in Pairing Phase 2.

Pairing Request Command Format
Pairing Response Command Format
Slave Security Request Command Format
Association Models Conditions for Use
Just Works This model is used when there is no Out of Band (OOB) data available and neither device has input capabilities.
Passkey Entry This model is used when there is no OOB data available, at least one device has the I/O capability to enter a passkey, and the other device has the capability to display a passkey.
Numeric Comparison This model is used if both devices support Secure Connections, can display a yes or no message and have some input capability.
Out of Band If OOB data is available on either device, this model will be chosen.

The models here are ranked by perceived level of security. Just works is the least secure and OOB is the most secure. The most secure model supported by both devices will be chosen. For full Association Model requirements, refer to Table 2.7 & Table 2.8 in the Bluetooth Core Specification v4.2 [Vol 3] Part H, Section 2.3.5.1.

In this module, we will cover Just Works and Passkey Entry pairing. The other two models cannot be easily demonstrated with mobile devices.

Pairing Phase 2

During the second phase of pairing, keys are generated and shared in order to encrypt the connection. The types of keys that are generated are dependent on whether LE Legacy or LE Secure Connections pairing is used.

LE Secure Connections Pairing Phase 2

If LE Secure Connections pairing is used, the devices will exchange their Public Keys next. The Public Keys are part of a Elliptic Curve Diffie-Hellman public-private key pair. The public keys are exchanged using the Pairing Public Key command. After the Public Keys are exchanged, each side will compute the Diffie-Hellman Key using the Public Key of the peer device and the Private Key of the local device.

After the Public Key Exchange in LE Secure Connections pairing, confirm values are exchanged. Confirm values are generated in accordance to the Bluetooth Core Specification and sent using the Pairing Confirm command. The LE Secure Connections Confirm Value Generation Function is described in [Vol 3] Part H, Section 2.2.6 of the Bluetooth Core Specification v4.2.

After the Central receives the Pairing Confirm command from the Peripheral device, the Central will send a Pairing Random command to the Peripheral device with the random number that was used to calculate the Pairing Confirm value in the previous step. The Peripheral will respond with the random number it used for its confirm value. The two devices will check the random number against the confirm values previously exchanged and, if the values match, the pairing will continue. If the check fails, a Pairing Failed command will be sent. Pairing Failed commands contain the reason that the pairing failed and can be extremely useful for debugging.

In LE Secure Connections, the Long Term Key (LTK) will be generated in order to encrypt the link. The LTK Generation is performed using the LE Secure Connection Key Generation function which also computes the MAC Key needed for the final step in Secure Connections Pairing. The LTK is not shared over the air in Secure Connections.

Finally, in LE Secure Connections Pairing, the Diffie-Hellman Key Check will occur. The Key Check values are generated using the LE Secure Connections Check Value Generation Functions described in [Vol 3] Part H, Section 2.2.8 of the Bluetooth Core Specification v4.2.

Pairing Phase 2: Secure Connections Key Generation
Pairing Public Key Command Format
Keypress Notification Command Format
Pairing Confirm Command Format
Pairing Random Command Format
Pairing Failed Command Format
Pairing DHKey Check Command Format

Bonding

Bonding is the process of distributing and storing the keys that were generated during the pairing process for the purpose of quickly restoring encryption in a future connection. Bonding information is stored in a bond record in flash so it can be restored when the devices connect again.

Privacy

Anti-Tracking

Active Bluetooth devices can be identified by their Bluetooth device address. This address is necessary for interacting with other Bluetooth devices. However, since this address can be seen by any other nearby Bluetooth device, it could be used to collect information about a given device over time. In order to prevent this tracking, devices can enable Bluetooth privacy features to hide their true Identity Address from untrusted peers. This is done by generating a new address at a given interval instead of using a fixed address.

Bluetooth Address Types

Bluetooth address types as defined by the Bluetooth Core Specification v4.2 are as follows:

  • Public Address - Does not change. Can be used as an Identity Address.
  • Random Static Address - May be regenerated after a power cycle, cannot be regenerated at any other time. Can be used as an Identity Address.
  • Resolvable Private Address (RPA) - Regenerated after a given interval. Generated using Identity Resolving Key (IRK) which can also be used by trusted peers to resolve the Private Address to an Identity Address. A device with a Resolvable Private Address must also have an Identity Address.
  • Non-resolvable Private Address - Regenerated after a given interval. Generated randomly. Cannot be resolved to an Identity Address.

Generating & Resolving Private Addresses

In order to generate Resolvable Private Addresses, a device will use its Identity Resolving Key (IRK) as an input to the Bluetooth defined Random Address Hash function. The output of this function is used as part of the Resolvable Private Address (RPA). A peer without an IRK will be able to determine that the device is using a Resolvable Private Address, but will be unable to determine the true identity of the Peer.

Task 1 – Enable Just Works Pairing

Before beginning, import Project Zero into your workspace. For a refresher on how to import, build and flash Project Zero, please see the Bluetooth 4.2 Basics lab. As a best practice, you should build Project Zero and verify functionality before making any changes.

1. Open project_zero.c and find the GAP Bond Manager initialization in ProjectZero_init():

  // ******************************************************************
  // BLE Bond Manager initialization
  // ******************************************************************
  uint32_t passkey = 0; // passkey "000000"
  uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
  uint8_t mitm = TRUE;
  uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
  uint8_t bonding = TRUE;

  GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                          &passkey);
  GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
  GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
  GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

project_zero.c :: ProjectZero_init() – GAP Bond Manager initialization

2. To start, we will edit bonding to FALSE for now. Then, to enforce Just Works pairing, we will set mitm to FALSE and ioCap to GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT:

  // ******************************************************************
  // BLE Bond Manager initialization
  // ******************************************************************
  uint32_t passkey = 0; // passkey "000000"
  uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
  uint8_t mitm = FALSE;
  uint8_t ioCap = GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT;
  uint8_t bonding = FALSE;

  GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                          &passkey);
  GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
  GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
  GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

project_zero.c :: ProjectZero_init() – GAP Bond Manager initialization modified to use Just Works Pairing

3. Build and flash your CC2640R2 LaunchPad with your modified Project Zero then follow the instructions below for your selected peer.

1. Import the Host Test project in CCS from the blestack example folder in the SDK.

2 In the Stack Library project, open TOOLS → build_config.opt. You will need to enable GAP Bond Manager by defining the following line:

/* Include GAP Bond Manager */
-DGAP_BOND_MGR

build_config.opt – BLE-Stack v3.1.x GAP Bond Manager configuration modifications

3. Build the Stack/Stack Library project and flash the host_test app project.

4. Open BTool and open the COM Port associated with your Host Test device. If you are new to BTool, review the basic usage in the Bluetooth 4.2 Basics lab.

After the intial Host Test setup is done, we will configure the GAP Bond Manager parameters to enable Just Works Pairing.

5. Click the Adv. Commands tab and expand the GAP section. Scroll down the list until you find the GAP_BondSetParam command. Click on the command to display the parameters below.

6. In the paramID field, select GAPBOND_PAIRING MODE. Set value to "02". This is value for GAPBOND_PAIRING_MODE_INITIATE. Using this mode will allow our Central device to send a Pairing Request when a connection has been formed. Hit the "Send Command" button to set this parameter in the GAP Bond Manager.

7. In the paramID field, select GAPBOND_IO_CAPABILITIES. Set value to "03". This is value for GAPBOND_IO_CAP_NO_INPUT_NO_OUTPUT. This will set the IO Capabilities we want to send in our pairing request. Hit the "Send Command" button to set this parameter in the GAP Bond Manager.

8. In the Discover/Connect tab, scan for devices. When the GAP_DeviceDiscoveryDone event is received, look through the list for a device matching the Project Zero address displayed in your PuTTY window.

9. In the Establish Link Slave BDA list, select your Project Zero device and click "Establish". Once a connection is formed, click the Pairing Bonding tab and ensure that the Bonding Enabled and the Authentication (MITM) Enabled box are unchecked. Click Send Pairing request and the devices will begin the pairing process. When the link is encrypted, you will receive a GAP_AuthenticationComplete event with a status of Success in BTool and the Project Zero PuTTY window will display "Pairing completed sucessfully."

10. In BTool, close the Host Test COM Port by selecting Device – Close Device.

1. Using your iOS device, find the LightBlue Explorer app (or any Bluetooth Client application you prefer) & open it.

2. The app should begin scanning for BLE devices automatically but you can refresh the list by pulling down.

3. You should see Project Zero advertising as "Project Zero R2". Connect to the device by clicking on the name.

4. After connecting, your serial window will look something like this:

Great! We've connected. However, this behavior seems identical to the unmodified behavior of Project Zero. So what gives?

iOS devices do not send pairing requests automatically and encryption cannot be requested from the mobile app.

Does this mean iOS devices do not support encryption? No, but it takes a special prompt to get the iOS device to initiate a pairing request. According to the Apple Bluetooth Accessory Design Guidelines for Apple Products in order to prompt the Apple device to send a pairing request:

"the Peripheral should reject [a] ATT request using the Insufficient Authentication error code, as appropriate."

We will go through this exercise in the next task.

1. Start BLE Scanner

Using your Android device, find the BLE Scanner app and open it.

2. Scan for BLE devices

The app should begin scanning for BLE devices automatically but you can toggle scanning on and off by clicking on the magnifying glass in the top right corner of the app. A "Scanning stop" message will appear.

3. Connect to Project Zero

You should see Project Zero advertising as "Project Zero R2". Connect to the device by clicking "Connect".

After connecting, your serial window will look something like this:

Great! We've connected. However, this behavior seems identical to the unmodified behavior of Project Zero. So what gives?

Android Bluetooth behavior varies depending on device and application used.

Some devices allow you to pair directly from the app, some require you to initiate pairing through the Bluetooth settings. Refer to Android development guidelines when you are designing your embedded experience.

Using the slave Security Request procedure may work with some Android devices and not others. To achieve the best interoperability, it is advised to use an characteristic permissions to prompt the Android device to send a Pairing Request.

We will go through this exercise in the next task.

Task 2 – Add Encrypted Characteristic

There may be some characteristics whose values we are unwilling to share with a peer device over an unencrypted link. In order to protect this data, we will require peers to establish an encrypted link before allowing GATT Reads and Writes to the String Characteristic in the Data Service.

1. Open data_service.c (located in the Profiles folder of the application project)

2. Find the String Characteristic Value in the attribute table and change GATT_PERMIT_READ | GATT_PERMIT_WRITE to GATT_PERMIT_ENCRYPT_READ | GATT_PERMIT_ENCRYPT_WRITE

3. Rebuild Project Zero and flash Project Zero LaunchPad.

1. Reopen the connection to your Host Test device in BTool.

2. Without performing any additional setup, scan and connect to Project Zero. This time, the GAP_AuthenticationComplete event does not follow the GAP_EstablishLink event.

3. Perform a GATT Discovery by right-clicking on the Handle in Connection Info and selecting Discover UUIDs.

4. After receiving the ATT_FindInfoRsp event with a status of 0x1A (The Procedure is Completed), scroll through the GATT Table at the bottom of BTool and find the String Char.

5. Read the value of the characteristic by clicking in the Value field for the String Char. An error message stating you have insufficient authentication to read this characteristic will occur.

6. Click the Pairing/Bonding tab. Make sure bonding and MITM are not enabled, then click Send Pairing Request.

7. Single-click on the String Char value field. This time, the message "This is a pretty long string, isn't it!" will display in the value field.

8. In BTool, close the Host Test COM Port by selecting Device – Close Device.

1. Connect to Project Zero using LightBlue Explorer.

2. Find the Characteristic with the Data Service String Characteristic UUID. (For a refresher on this, see Bluetooth 4.2 Basics)

3. Click on the Characteristic with the Data Service String Characteristic UUID.

4. Now a window asking you to pair the devices will pop up. Accept the pairing prompt by clicking "Pair". When the pairing process has completed, the Project Zero terminal window will display "Pairing completed successfully".

5. Click "Read Again". This time, a value will display under "Cloud Connect". Click "Hex" in the top right corner of the app. Now you can switch between display formats. Select UTF-8 to see the value as a string.

1. Connect to Project Zero using BLE Scanner

2. Find the Characteristic with the Data Service String Characteristic UUID. (For a refresher on this, see Bluetooth 4.2 Basics)

3. Click on the circled R next to the Data Service String Characteristic UUID to read the value of the newly encrypted characteristic.

The following message should appear in your terminal window:

4. Now that we have an encrypted link, try reading the characteristic value again by pressing on the R button again. Now the value of the String Characteristic should display in BLE Scanner:

Task 3 – Enable Passkey Entry Pairing

Now that we have gone through a basic pairing exercise and have an encrypted characteristic, we can move on to something more secure. If you want to have an authenticated link, you must add protection against MITM attacks. To do this, we will ask users to enter a passkey before accessing our protected characteristic to make sure we are pairing the right devices.

1. In GAP Bond Manager initialization, set mitm to TRUE and ioCaps to GAPBOND_IO_CAP_DISPLAY_ONLY:

  // ******************************************************************
  // BLE Bond Manager initialization
  // ******************************************************************
  uint32_t passkey = 0; // passkey "000000"
  uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
  uint8_t mitm = TRUE;
  uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
  uint8_t bonding = FALSE;

  GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                          &passkey);
  GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
  GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
  GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

project_zero.c :: ProjectZero_init() – GAP Bond Manager initialization modified to use Passkey Entry Pairing

Having a hard coded passkey does not offer true MITM protection if the same passkey is reused. Therefore, we need to randomize the passkey.

In project_zero.c, in the function user_processApplicationMessage(), in the case the type of the application message is APP_MSG_SEND_PASSCODE we will add the following code that will randomize the passkey. This message is triggered when a GAP_PASSKEY_NEEDED_EVENT is generated by the stack during the pairing process. This event is then sent to the GAPBondMgr which calls the applications passcode callback which then enqueues the APP_MSG_SEND_PASSCODE application message.

For a full diagram of how pairing and secure connections works in the BLE Stack, go to the TI BLE-Stack User's Guide and navigate to BLE Stack -> GAP Bond Manager and LE Secure Connections section.

    case APP_MSG_SEND_PASSCODE: /* Message about pairing PIN request */
      {
        uint32_t passcode = 0;
        passcode = Util_GetTRNG();
        passcode %= 1000000;
        passcode_req_t *pReq = (passcode_req_t *)pMsg->pdu;
        Log_info2("BondMgr Requested passcode. We are %s passcode %06d",
                  (IArg)(pReq->uiInputs?"Sending":"Displaying"),
                  passcode);
        // Send passcode response.
        GAPBondMgr_PasscodeRsp(pReq->connHandle, SUCCESS, passcode);
      }
      break;

project_zero.c :: user_processApplicationMessage() – application message used to randomize the passkey

2. Rebuild Project Zero and flash Project Zero LaunchPad.

1. BTool will automatically send the default passkey (000000) to the controller. Therefore you must revert the changes done above in ProjectZero and set the default passkey back to "000000".

    case APP_MSG_SEND_PASSCODE: /* Message about pairing PIN request */
      {
        passcode_req_t *pReq = (passcode_req_t *)pMsg->pdu;
        Log_info2("BondMgr Requested passcode. We are %s passcode %06d",
                  (IArg)(pReq->uiInputs?"Sending":"Displaying"),
                  DEFAULT_PASSCODE);
        // Send passcode response.
        GAPBondMgr_PasscodeRsp(pReq->connHandle, SUCCESS, DEFAULT_PASSCODE);
      }
      break;

project_zero.c :: user_processApplicationMessage() – default passkey

2. Use BTool to discover and connect to Project Zero.

3. In the Pairing/Bonding tab, select "Authentication Enabled", and initiate pairing. Connect to Project Zero device. BTool may automatically send the default passcode (000000) to the controller. If BTool does not automatically send the default passcode, then fill in the Passkey field with the default passcode(000000) and click Send PassKey

1. Connect to Project Zero using LightBlue Explorer.

2. Find the Characteristic with the Data Service String Characteristic UUID.

3. Click on the Characteristic with the Data Service String Characteristic UUID.

4. Now a window asking you to pair the devices will pop up. This time, a passkey entry field will appear. Check the ProjectZero terminal window for the random passcode. Accept the pairing prompt by typing the code in the passkey box. When the pairing process has completed, the Project Zero terminal window will display "Pairing completed successfully".

5. Click "Read Again". This time, a value will display under "Cloud Connect". Click "Hex" in the top right corner of the app. Now you can switch between display formats. Select UTF-8 to see the value as a string.

1. Connect to Project Zero using BLE Scanner

2. Read the Encrypted Data Service String Characteristic as done in Task 2.

3. Now a window asking you to pair the devices will pop up. This time, a passkey entry field will appear. Check the ProjectZero terminal window for the random passcode. Accept the pairing prompt by typing the code in the passkey box as presented in the Project Zero terminal window.

4. When the pairing process has completed, the Project Zero terminal window will display "Pairing completed successfully" and you will be able to read your Encrypted Characteristic as in Task 2.

Task 4 – Enable Bonding

For this exercise, we will continue to use Passkey Entry pairing. Enabling bonding will allow us to bypass the pairing process in future connections. The Controller can use the stored keys supplied by the Host to start encryption.

1. In GAP Bond Manager initialization, use same settings as in previous task but set bonding to TRUE:

  // ******************************************************************
  // BLE Bond Manager initialization
  // ******************************************************************
  uint32_t passkey = 0; // passkey "000000"
  uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
  uint8_t mitm = TRUE;
  uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
  uint8_t bonding = TRUE;

  GAPBondMgr_SetParameter(GAPBOND_DEFAULT_PASSCODE, sizeof(uint32_t),
                          &passkey);
  GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
  GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
  GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

project_zero.c :: ProjectZero_init() – GAP Bond Manager initialization modified to use Passkey Entry Pairing & bond to peer

1. Use BTool to discover and connect to Project Zero

2. In the Pairing/Bonding tab, select "Bonding Enabled", "Authentication Enabled", and initiate pairing. Connect to Project Zero device. BTool will automatically send the correct passcode (000000) to the controller.

3. After receiving the "Bond Save Success" message in your Project Zero terminal window, enable notifications on the Button Service by writing "01:00" to the Button0 Client Characteristic Configuration handle in BTool.

4. Verify that notifications are being sent by pressing the right button on the LaunchPad and observing the Value of the Button0 State characteristic. When the button is pressed, the value should be 01. When the button is released, the value should be 0.

5. Disconnect from Project Zero.

7. Reconnect to the Project Zero device. Now you should receive a "WriteAttrCB (CCCD): param: 1 connHandle: 0 - restoring bonded state" message in your Project Zero terminal window.

8. Press a Button - notification will be sent without having to re-enable.

1. Connect to Project Zero using LightBlue Explorer.

2. Follow steps in Task 3 to pair with Project Zero using the Passkey Entry method.

3. After receiving the "Pairing completed successfully" message, disconnect from Project Zero.

4. Reconnect to Project Zero. This time, the Project Zero terminal window will display a new message: "Re-established pairing from stored bond info."

5. Read the Encrypted Data Service String Characteristic. This time, the value will display without needing to re-enter the passkey.

1. Connect to Project Zero using BLE Scanner

2. Follow steps in Task 3 to pair with Project Zero using the Passkey Entry method.

3. After receiving the "Pairing completed successfully" message, disconnect from Project Zero.

4. Reconnect to Project Zero. This time, the Project Zero terminal window will display a new message: "Re-established pairing from stored bond info."

5. Read the Encrypted Data Service String Characteristic. This time, the value will display without needing to re-enter the passkey.

Task 5 – Using a Resolvable Private Address

The addresses we generally use in privacy discussions are RPAs and Identity Addresses. A device using an RPA periodically changes the address it uses over the air. This happens at a specified timeout interval. The addresses it uses are generated with an Identity Resolving Key (IRK). This key associates the Resolvable Private Address to an Identity Address that remains constant.

RPA's help inhibit tracking from untrusted peer devices. However, some devices may need the ability to recognize, and be recognized by, their peer devices after their RPA has changed. Since RPAs are associated with an identity address, they can be resolved to that fixed address, if a peer device has the right key.

Below, we will work on configuring the device to use an RPA and learn how to work with it.

1. Use GAP_ConfigDeviceAddr to configure Project Zero to use a Resolvable Private Address. GAP_ConfigDeviceAddr must be called after receiving the GAP_DEVICE_INIT_DONE_EVENT but before any BLE activity. A good place for this is in the gapRole_processGAPMsg function of peripheral.c after gapRole_state = GAPROLE_STARTED;:

    gapRole_state = GAPROLE_STARTED;

    stat = GAP_ConfigDeviceAddr(ADDRMODE_PRIVATE_RESOLVE, NULL);

    if (stat != SUCCESS)
    {
        gapRole_state = GAPROLE_ERROR;
    }

    // Update the advertising data
    stat = GAP_UpdateAdvertisingData(selfEntity,
                        TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);

peripheral.c :: gapRole_processGAPMsg() – Set Address Type as Resolvable Private Address

2. To change the timeout value between address changes, use GAP_SetParamValue to set the TGAP_PRIVATE_ADDR_INT parameter. The value is in minutes:

    //Set timeout value to 5 minute
    GAP_SetParamValue( TGAP_PRIVATE_ADDR_INT , 5);

peripheral.c :: gapRole_processGAPMsg() – Modify address change interval

3. In GAP Bond Manager initialization, use same settings as in previous task:

  // ******************************************************************
  // BLE Bond Manager initialization
  // ******************************************************************
  uint32_t passkey = 0; // passkey "000000"
  uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
  uint8_t mitm = TRUE;
  uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
  uint8_t bonding = TRUE;

  GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
  GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
  GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

project_zero.c :: ProjectZero_init() – GAP Bond Manager initialization modified to use Passkey Entry Pairing & bond to peer

4. Use BTool to discover Project Zero. The ProjectZero now use a resolvable private address generated from its Identity Address and it's local IRK. The address presented on the ProjectZero terminal window is the identity address. We don't know the generated RPA used, therefore you must search through the BTool log to find the GAP_ADTYPE_LOCAL_NAME_COMPLETE that is sent in the ProjectZero advertising payload and find the corresponding matching random address. This is illustrated in the screen shot below where "Project Zero R2" is found in the advertising payload.

5. Use BTool to connect to Project Zero. Make sure to select the address found from the step above and select the correct address type as shown below (0x01 ADDRTYPE RANDOM). If you try to connect with the wrong AddrType you might have to restart BTool and start over. You may also have to restart Project Zero.

6. In BTool, Send pairing request with Bonding Enabled and Authentication (MITM) Enabled checked. The default Passkey should be sent automatically. If not, enter the correct passkey and press "Send Passkey".

7. In your Project Zero terminal window, the "Pairing completed successfully." message will display. In BTool, you will receive GAP_AuthenticationComplete with a status of SUCCESS. In the Long-Term Key Data section, save the data to a file and disconnect from Project Zero.

8. Scan again for device. This time, the Address Type shown in BTool should be Public ID - which indicates that the controller has resolved the private address to an identity address by using the stored IRK.

9. Reconnect to the Project Zero device. Remember to make sure the correct Address Type is set (0x02 ADDRTYPE PUBLIC ID).

iOS does not display peer address information at the application level. In order to complete this exercise, we will switch our Project Zero device to run the Host Test application and use our iOS device in peripheral mode to demonstrate RPA usage.

1. Import the Host Test project from <SDK_INSTALL_PATH> → examples → rtos → CC2640R2_LAUNCHXL → blestack → host_test into CCS

2. The Host Test project does not use the GAP Bond Manager by default. To enable the Bond Manager, open TOOLS → build_config.opt in the Host Test Stack Library project. Uncomment the -DGAP_BOND_MGR line as shown below:

/* Include GAP Bond Manager */
-DGAP_BOND_MGR

build_config.opt – BLE-Stack v3.1.x GAP Bond Manager configuration modifications

3. Build the Stack Library project then build and flash the Host Test app project.

4. Open BTool located in the <SDK_INSTALL_PATH> → tools → blestack → btool directory.

5. Open the COM port for your LaunchPad. If you still have a terminal window open from a previous task, you will need to close it first.

6. In your iPhone settings, clear bonds from the previous task by going to Settings → Bluetooth. Remove the bond by tapping the info button next to the "Project Zero R2" device listing and selecting Forget This Device.

7. Open LightBlue and create a Virtual Peripheral with a Characteristic that has a Notify property. We will demonstrate with the default Heart Rate Peripheral. Start advertising by clicking the circle to the left of the Peripheral name.

8. In order to keep the connection to the iOS device alive, we will need to quickly encrypt the connection. However, to avoid a Link Layer collision with an iOS control procedure (Version Exchange), we cannot initiate encryption immediately upon connection. This means we cannot use the GAPBOND_PAIRING_MODE_INITIATE setting. Instead, we will initiate the pairing process by using the GAP_Authenticate command. We will set the GAP_Authenticate parameters as follows:

9. Use the Scan button in the Discover/Connect tab to discover your mobile device. The scan results will display in the log section of BTool. Find the entry that shows the name of the Peripheral you are advertising as in the Rx dump.

Warning!

The next few steps must be done quickly to prevent the iOS device from disconnecting. If only empty packets are being sent, the iOS device will terminate the connection. Enabling notifications from BTool will allow the connection to remain active.

If you do not perform the steps in time, rediscover and connect to the device and try steps 10 through 15 again.

10. In the Link Control section, select the Slave BDA (Bluetooth Device Address) that is in the GAP_DeviceInformation Event.

11. When the connection has established, go to the Adv. Commands tab and issue the GAP_Authenticate command that you set up in step 11.

12. When the the Connection Info will appear in the right-pane of the BTool window. Right-click on the Handle and select Discover UUIDs.

13. The Service Discovery will take place and the GATT table for the Peripheral will appear in the bottom of the BTool window.

14. Double click on the last characteristic handle for the Heart Rate Measurement CCCD and write a value of 01:00 to enable notifications. If notifications are successfully enabled, the BTool log will begin reporting the current Heart Rate Measurement value as shown below:

15. Save the BTool log to retrieve the LTK that will be used to restore encryption by right-clicking in the BTool log window and selecting "Save Log".

16. Open the btool log in your favorite text editor and search for the string "GAP_AuthenticationComplete". This event contains the LTK that you will need to restore encryption upon a reconnection as well as the Identity Address that can now be resolved. If your BTool log does not contain this string, repeat steps 10-15 again.

17. Disconnect from the iOS device by clicking the Terminate button in the Discover/Connect tab.

18. To restore encryption without pairing, we will need to issue the GAP_Bond command after connecting. In order to do this quickly, we will pre-set the parameters using what was given to us in the GAP_AuthenticationComplete event:

19. We will also want to write to the previously discovered CCCD to keep the connection alive. You can preset the values in the Read/Write tab to quickly issue this command.

20. Discover devices by clicking the Scan button in the Discover/Connect tab. Now, the results will display using the Identity Address and Address Type exchanged during the pairing process.

21. Reconnect by selecting the corresponding Slave BDA and clicking Establish.

22. After the connection has established, go to the Adv. Commands tab and restore encryption by issuing the GAP_Bond command as set up in Step 19.

23. Re-enable notifications by writing to the Heart Rate Measurements CCCD as set up in Step 20.

24. If everything was issued correctly, you should begin receiving ATT_HandleValueNotifications with the current value of the Heart Rate Measurement characteristics.

1. Use GAP_ConfigDeviceAddr to configure Project Zero to use a Resolvable Private Address. GAP_ConfigDeviceAddr must be called after receiving the GAP_DEVICE_INIT_DONE_EVENT but before any BLE activity. A good place for this is in the gapRole_processGAPMsg function of peripheral.c (in the Profiles folder) after gapRole_state = GAPROLE_STARTED;:

    gapRole_state = GAPROLE_STARTED;

    stat = GAP_ConfigDeviceAddr(ADDRMODE_PRIVATE_RESOLVE, NULL);

    if (stat != SUCCESS)
    {
        gapRole_state = GAPROLE_ERROR;
    }

    // Update the advertising data
    stat = GAP_UpdateAdvertisingData(selfEntity,
                        TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);

peripheral.c :: gapRole_processGAPMsg() – Set Address Type as Resolvable Private Address

2. To change the timeout value between address changes, use GAP_SetParamValue to set the TGAP_PRIVATE_ADDR_INT parameter. The value is in minutes:

    //Set timeout value to 5 minute
    GAP_SetParamValue( TGAP_PRIVATE_ADDR_INT , 5);

peripheral.c :: gapRole_processGAPMsg() – Modify address change interval

3. In GAP Bond Manager initialization, use same settings as in previous task:

  // ******************************************************************
  // BLE Bond Manager initialization
  // ******************************************************************
  uint32_t passkey = 0; // passkey "000000"
  uint8_t pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
  uint8_t mitm = TRUE;
  uint8_t ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
  uint8_t bonding = TRUE;

  GAPBondMgr_SetParameter(GAPBOND_PAIRING_MODE, sizeof(uint8_t), &pairMode);
  GAPBondMgr_SetParameter(GAPBOND_MITM_PROTECTION, sizeof(uint8_t), &mitm);
  GAPBondMgr_SetParameter(GAPBOND_IO_CAPABILITIES, sizeof(uint8_t), &ioCap);
  GAPBondMgr_SetParameter(GAPBOND_BONDING_ENABLED, sizeof(uint8_t), &bonding);

project_zero.c :: ProjectZero_init() – GAP Bond Manager initialization modified to use Passkey Entry Pairing & bond to peer

4. Rebuild the project and flash your LaunchPad

5. Open BLE Scanner and look for Project Zero advertising. This time, you will notice that the address that is advertised does not match what is in the Project Zero terminal window. In BLE Scanner, you see the Random Private Address that the CC2640R2 is currently using. In the terminal window, you see the same address from the previous tasks.

6. Hit the LaunchPad reset button. You will see a new Project Zero R2 device advertise. After a few seconds, the old Project Zero address will disappear as the scanner no longer sees the old RPA. You can also refresh the scan list manually by pulling down on the device list. Notice, the Identity Address displayed in the Project Zero terminal window does not change.

7. Connect and bond to Project Zero using the process detailed in Task 4.

8. Disconnect and return to the Near By devices view. Now, if you hit the reset button on the LaunchPad, the device continues to display the same address. This is because, no matter what address the LaunchPad uses, the phone is able to resolve the Private Address to its Identity Address using the IRK exchanged during bonding. It is able to recognize and remember the device, even after the RPA has changed.

9. Reconnect to Project Zero and disconnect a couple times. Observe the Peer Address in the terminal window on the initial connection, before bonding, to the Peer Address on the connections after bonding. Project Zero is also able to resolve the RPA that the phone is using to its Identity Address after bonding.

10. Depending on your mobile device and OS, you may be able to confirm the Bluetooth Identity Address being used. Look up the instructions for finding the Bluetooth device address on your device.

Congrats! You have created a Project Zero that cannot be tracked except by the phone you have bonded to. Look up device specific instructions to clear BLE bonding information from your phone if you wish to try this task again.

In the BTool and Android instructions, Privacy and RPA is enabled on ProjectZero. It is possible to read the local address with HCI_LE_ReadLocalResolvableAddressCmd. Please refer to the TI BLE-Stack for Bluetooth 4.2 API Documentation for more information. The code snippets below will print the first RPA used after boot.

// Display device address
char *cstr_ownAddress = Util_convertBdAddr2Str(ownAddress);
Log_info1("GAP is started. Our address: \x1b[32m%s\x1b[0m", (IArg)cstr_ownAddress);

HCI_LE_ReadLocalResolvableAddressCmd();

project_zero.c :: user_processGapStateChangeEvt() – Add HCI_LE_ReadLocalResolvableAddressCmd at end of case GAPROLE_STARTED

// Process HCI message
switch(pMsg->status)
{
    case HCI_COMMAND_COMPLETE_EVENT_CODE:
    // Process HCI Command Complete Event
    Log_info0("HCI Command Complete Event received");

    hciEvt_CmdComplete_t *pMsgHci = (hciEvt_CmdComplete_t*) pMsg;

    //Find which command this command complete is for
    switch (pMsgHci->cmdOpcode)
    {
        case HCI_LE_READ_LOCAL_RESOLVABLE_ADDRESS:

        if (pMsgHci->pReturnParam[0] == HCI_SUCCESS)
        {
            // Copy RPA.
            uint8_t localRpa[6];
            memcpy(localRpa, &(pMsgHci->pReturnParam[1]), 6);
            uint8_t *pLocalRpa = localRpa;

            // Convert byte array to string START
            uint8_t charCnt;
            char hex[] = "0123456789ABCDEF";
            static char str[(2 * 6) + 3];
            char *pStr = str;

            *pStr++ = '0';
            *pStr++ = 'x';

            // Start from end of addr
            pLocalRpa += 6;

            for (charCnt = 6; charCnt > 0; charCnt--)
            {
                *pStr++ = hex[*--pLocalRpa >> 4];
                *pStr++ = hex[*pLocalRpa & 0x0F];
            }
            // Convert byte array to string STOP

            Log_info0("RPA read SUCCESS");
            Log_info1("Local RPA: \x1b[32m%s\x1b[0m",
                    (IArg )str);
        }
        else
        {
            Log_info0("RPA read FAIL");
        }
        break;

        default:
        break;
    }
    break;

    default:
    // do nothing
    break;
}

project_zero.c :: ProjectZero_processStackMsg() – Place in case HCI_GAP_EVENT_EVENT

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.