Advanced Security Features#

Introduction#

This lab will go further into the details behind the security protocols found in Bluetooth Low Energy, and in particular how these are implemented in the SimpleLink F3 CC23xx SDK. This lab will focus on the security provided by the specific cryptographic algorithms, and discuss why and in what degree they are secure.

Each algorithm is given a short introduction which should provide an intuitive understanding of their function. The reader is encouraged to continue exploring these algorithms on their own if more knowledge is desired. There is a lot to learn here, and it may take time before you see the complete picture. Most of the algorithms are common on other platforms as well, so taking the time to understand them can be very useful.

The tasks will highlight different aspects of security in Bluetooth LE. The first two tasks will show the use of the security drivers for AES-ECB (encrypt only) and AES-CCM and go through how to encrypt and decrypt a message. Task 3 shows how to implement and use a Filter Accept List. Task 4 and 5 showcases use of the APIs in the GAP Bond Manager, and specifically how to interact with the Simple Non-Volatile (SNV) memory driver to add or remove bonding information for specific devices, and how to use the same key for multiple pairings in a row.

It is recommended to read the TI BLE5-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#

Hardware#

For this lab, you need one or two Bluetooth-enabled development boards. Supported devices are:

Software#

Software and Tools for Development#

For testing, a Bluetooth client application is required:

  • BTool (located in the tools\ble5stack directory of the SimpleLink™ SDK installation) OR

  • A Bluetooth Client mobile app - instructions will use the below mobile apps:

    • Android: TI SimpleLink Connect App - available on the Google Play store

    • iOS: TI SimpleLink Connect App - available on the App Store

Security Overview#

Definitions#

  • Asymmetric key: Two different keys are used for encryption and decryption.

  • Block Cipher: An encryption algorithm that operates on fixed-length group of bits, a block, with an unvarying transformation that is specified by a symmetric key.

  • Cryptographic Nonce: An arbitrary number that can be used just once in a cryptographic communication

  • ECDH: Elliptic-curve Diffie-Hellman key exchange algorithm

  • Hashing algorithm: A one-way function that takes an arbitrarily long block of bits and produces a fixed length output that is seemingly random.

  • Message Authentication Code (MAC): An appended data unit which ensures authentication of the message.

  • Public-Key Cryptography: A system where each device has a public key that everyone knows, and a private key that only they know. This is an asymmetric key system. A message encrypted with a public key can only be decrypted with a private key, and vice versa.

  • Resolvable Private Address: A random, changing address is used by a Bluetooth LE device. If a peer device knows the identity resolving key, it can find the identity address of the device.

  • SHA-256: Secure Hashing Algorithm with 256 bits of output

  • Stream Cipher: An encryption algorithm that encrypts a message one bit at a time, combining each bit with a bit in a pseudo-random cipher digit stream generated with a symmetric key.

  • Symmetric Key: The same key is used for both encryption and decryption.

Random Number Generator (RNG)#

Every security algorithm lays the ability to produce completely random values. If any of the generated numbers are by any means dependent, it would represent a big security risk. The SimpleLink CC2340 MCUs feature a dedicated hardware unit, the CC23xx device integrates an AES-128 cryptography hardware accelerator which reduces code footprint and execution time for cryptographic operations. The AES accelerator also has the benefit of consuming less power, improves availability and, responsiveness of the system because the cryptography operations run in a background hardware thread. The AES hardware accelerators supports the following block cipher modes and message authentication codes:

  • AES ECB encrypt

  • AES CBC encrypt

  • AES CTR encrypt/decrypt

  • AES CFB encrypt/decrypt

  • AES OFB encrypt/decrypt

  • AES CBC-MAC

  • AES CCM (uses a combination of CTR + CBC-MAC hardware with software drivers)

Together with a large selection of open-source cryptography libraries provided with the Software Development Kit (SDK), this allows secure and future proof IoT applications to be smoothly built on top of the platform. The CC23xx device supports Random Number Generation (RNG) using on-chip analog noise as the nondeterministic noise source. The purpose of generating a seed for a cryptographically secure counter deterministic random bit generator (CTR-DRBG) that in turn is used to generate random numbers for keys, initialization vectors (IVs), and other random number requirements. Hardware supports acceleration of AES CTR-CBC-MAC. If you want to learn more about the RNG, consult the Technical Reference Manual.

Cryptographic Algorithms#

Diffie-Hellman#

The Diffie-Hellman algorithm is an effective way of two devices agreeing on a shared secret encryption key that is used for encrypting the data between them. It ensures that a passive listener who listens to all the communication between the devices before the connection is encrypted, cannot calculate their shared secret encryption key.

The basic concept is that every device has a private key, and that there exists a public key for everyone to see. If device A then combines its private key with the public key, it will be computationally very expensive to separate them from one another. A common analogy to this process is shown in the figure below, and involves mixing containers of colored water. This is because one can imagine that separating a mixed container into two different containers with separate and correct colors is nearly impossible. This means that a device now can transmit this “mixture” safely unencrypted. When a device receives a mixture, it adds its own private key, or colored water, so that it ends up with a new color mixture that is equal on both devices. Two devices have now agreed on a common key without the possibility of someone intercepting it.

../../_images/dh_key_ex.png

Diffie-Hellman Key exchange#

In reality, this is done with some clever math. A common way to do this, is with Basic Exponential maths. However, for Bluetooth this is done with Elliptic-curve. For context, both basic exponential maths and Elliptic-Curve will be explained here.

Basic Exponential Maths#

Two devices publicly agree on a modulus p and a base g.

Device A then chooses a secret integer a which is its private key. The “mixing of colors” has the following mathematical formula:

A = g a mod p

Trying to find a when one knows A, p and g is shown to be very computationally expensive. Thus, A is safe to send unencrypted, and it is sent to device B.

Device B does the same, chooses a secret integer b and calculates B = g b mod p. It then sends it unencrypted to device A.

Device A can now calculate the shared private key, s = B a.

Device B also calculates the shared secret key, s = A b.

Both devices now have the same shared secret key. This holds true because:

Ab mod p = g ab mod p = B a mod p

Elliptic-Curve#

Elliptic-Curve Cryptography (ECC) is an alternative approach to public-key cryptography that is widely used. This is because it requires smaller keys compared to non-ECC to provide equivalent security (An ECC key of 256-bits has the same level of security as an RSA key of 3072 bits). In two of the drivers in the SimpleLink CC23xx SDK, Elliptic-Curves are used: Elliptic Curve Digital Signature Algorithm (ECDSA) and Elliptic Curve Diffie-Hellman key exchange algorithm (ECDH). It is thus worth the effort exploring this method a little further.

An elliptic curve is provided (Bluetooth LE uses the P-256 made by the National Security Agency) together with a base point G. We are now going to do operations with this point on the curve to get new values. In the first operation, we need to calculate G + G. This corresponds to making a line from G to G, which becomes the tangent of G, and seeing where it intersects the Elliptic-Curve. This is 2G’. We then mirror that point around the x-axis, and we have 2G.

../../_images/G_2G.png

In the second step, we want to find 3G. This is equal to G + 2G. We take the line through both G and 2G, and see where it intersects the curve. We then mirror that point around the X axis to find 3G.

../../_images/2G_3G.png

In the third step, we do the same thing. G + 3G = 4G is found using the same method as in the previous step.

../../_images/3G_4G.png

This is where the genius part of the algorithm comes in. If someone gave you the coordinates of a point A, it would be extremely time consuming finding out how many times you would have to add G to itself before landing at this point. If we set this up as an equation, A = bG, b would be our private key.

../../_images/g_a.png

This time, the public key is the coordinate of a point A, which is now both X and Y coordinates. The private key is the number of times one has to do a geometric operation to the (publicly available) base G before ending up at the coordinates of A. A is then our water container of mixed colors. As discussed previously, finding the multiplicity of the base G before ending up at the shared point A, is extremely time consuming to calculate.

### Quiz Which statement(s) is true? 1. [ ] The Diffie-Hellman key exchange is an effective way of preventing MITM-attacks 1. [x] Diffie-Hellman prevents anyone eavesdropping on the pairing to intercept the encrypted communication. 1. [ ] Using elliptic curves in Diffie Hellman ensures security at the cost of efficiency

Advanced Encryption Standard#

Advanced Encryption Standard (AES) describes a symmetric encryption algorithm, meaning that the same key is used for encrypting the data as decrypting it. AES can be used for both symmetric data encryption as well as authenticated encryption. A block cipher is a deterministic algorithm transforming a fixed-length group of bits using a symmetric key, which is exactly what AES does.

LE Legacy connections and LE Secure connections collectively use AES in four different variants; AES-ECB, AES-CBC, AES-CTR and AES-CCM. LE Legacy uses AES-ECB for key generation, and AES-CBC and AES-CTR are subroutines in AES-CCM that both LE Secure and LE Legacy connections use.

AES - Electronic Codebook (ECB)

The data to be encrypted is partitioned into blocks of equal sizes that are fed into the encryption algorithm separately with the same key. The disadvantage of this method is that it lacks diffusion. This means that equal plaintext blocks will be encrypted to equal ciphertext blocks, and thus a data pattern can emerge. In the case of AES-128 which is a variant of AES-ECB used for key generation in LE Legacy pairing key generation, the block size is 128-bits. When using AES-128, when you have encrypted a data block of 128 bits you would need to change the key before encrypting a new block of 128-bits to avoid the problem of diffusion. In the key generation step in LE Legacy, only one 128-bit data block is encrypted, and thus the encryption is secure.

../../_images/aes_ecb.png

AES in Electronic Codebook (ECB) mode encryption#

AES - Cipher Block Chaining (CBC)

This method of encrypting makes sure that any data pattern does not persist after the encryption is done. Before the plaintext is fed into the encryption algorithm, it is XORed with the ciphertext of the previous block. This ensures that each ciphertext block depends on all the plaintext blocks processed up to that point, and diffusion is achieved.

../../_images/aes_cbc.png

AES in Cipher Block Chaining (CBC) mode encryption#

AES - Counter (CTR)

Counter mode turns a block cipher into a stream cipher. A stream cipher is a symmetric key cipher where the data to be encrypted is combined with a pseudo-random cipher digit stream. This means that each plaintext digit of our data is encrypted one at a time with the corresponding digit of the keystream.

CTR-mode encrypts a constant random Nonce together with a counter that increases for each block. It then XORs it with the data to be encrypted. The counter ensures that any data patterns are diffused, as two equal blocks of plaintext will be encrypted differently. Since each block of text can be encrypted independently in parallel (as opposed to CBC), this mode is more efficient.

../../_images/aes_ctr.png

AES in Counter (CTR) mode#

AES - Counter with CBC-MAC (AES-CCM)

This is the encryption standard used in Bluetooth LE connections. We first have to introduce the CBC-MAC (Cipher block chaining message authentication code). This is a method of constructing a Message Authentication Code (MAC) from a block cipher. To calculate a CBC-MAC, one first encrypts a message with CBC mode and keeps the last block. This last block is thus our MAC. This method ensures that any changes to the message will alter the MAC in unexpected and seemingly random ways.

Then, both the message and the MAC is encrypted with the CTR mode. This means that when the message is decrypted at the receiver end, the MAC appended in the message can be compared to the calculated MAC of the message. If someone has tampered with the data, these two MACs will not be equal! We now have an algorithm that provides both authentication (Authentication of the data, NOT the sender!) and encryption!

### Quiz Which statement(s) is true? 1. [ ] It is easy to manipulate single bits in encrypted AES-CBC ciphertext without the recipient noticing it 1. [ ] AES-CCM provides authentication using AES-CTR and encryption using AES-CBC 1. [x] AES-ECB is vulnerable if you encrypt more than 128 bits with the same key.

Cipher-Based Message Authentication Code (AES-CMAC)#

This algorithm is frequently used in the key generation process. The core of the CMAC is the previously discussed CBC-MAC. The key difference between these two is that the CMAC works on messages of any bit lengths. The function takes as input a secret key, a message and its length, and returns a 128-bit string which is the MAC. This 128-bit string is now our long term key (LTK)(In LE secure connections. If you need a refresher on how the LTK is used, take a look at the Security Fundamentals lab).

SHA-256#

SHA stands for Secure Hashing Algorithm. A hashing algorithm is a one-way function that takes an arbitrarily long block of bits, and produces a fixed length output that is seemingly random. If you only know the output of the function, it is impossible to calculate the original data block. If one bit in the input changes the output is completely changed, seemingly at random. It is also highly unlikely that two different inputs to the hashing function will produce the same hash. This means that if you receive a message and you know its hash already, you can verify that the integrity of the data is preserved by calculating the hash yourself with the message as input, and comparing it with the stored hash. SHA-256 produces a 256-bit output, which means that there are 2256 different possible outputs to the hashing function. A hash collision happens when to inputs hashes to the same value, but because of the many possible combinations in the output, the probability of this happening is very small.

### Quiz Which statement(s) is true? 1. [ ] SHA is an algorithm used for encrypting sensitive data 1. [x] Any changes to the input triggers a seemingly random change to the output 1. [ ] It is easy to verify a message if you know its hash, because you can re-calculate the original message from the hash.

Keyed-hash Message Authentication Code (HMAC)#

HMAC is a type of Message Authentication Code involving a cryptographic hash function and a secret cryptographic key. It can be used for both verifying data integrity and authenticating a message. Any cryptographic hash function can be used to calculate the HMAC, but Bluetooth LE uses SHA-256.

The main use of this function is when dealing with stream ciphers. Changing a bit in a stream cipher text is an easy way of manipulating the decrypted data, even if you don’t know how to decrypt it. This is in contrast with a block cipher, where changing one bit of the cipher text will ruin the decryption process and thus expose meddling by attackers. The solution is to attach a Message Authentication Code at the end of the data string that verifies the integrity of the data. The naive approach is to attach the hash of the message itself after the message, as a kind of checksum. The downside of this approach is that an attacker can change the message, and recalculate a hash to match it. What we need to do, and what HMAC does, is calculate the hash not only with the message, but with private keys as well. This ensures that an attacker can’t recalculate the hash attached to the message, without also knowing the secret keys. Now the message is both authenticated and verified.

Comparison of Different MAC Algorithms#

Comparing HMAC to the previously discussed CBC-MAC and AES-CMAC they share many similarities. All of them calculate a signature of the message using a one-way function, thus making it impossible to recalculate the original message if one knows the signature. HMAC uses SHA-256, and AES-CMAC and CBC-MAC uses AES-CBC as this one-way function. At the same time, they all try to make it impossible for an attacker to forge the hash if the message is changed. HMAC solves this by signing the MAC with private keys. CBC-MAC is used as a subroutine in AES-CCM, which means that this MAC is encrypted with AES-CTR and thus makes it hard to forge for an attacker. The AES-CMAC is signed with the shared secret Diffie-Hellman key in the key generation procedure, and the output is thus also safe from forging.

### Quiz Which statement(s) is true? 1. [x] Signing the hash with the private keys as well as the message ensures that an attacker can't forge the hash 1. [ ] Sending the hash of a message together with the message is a good way of verifying it 1. [ ] If an attacker figures out the message, the private keys can be extracted from the hash

Implementation of Security Protocols in Bluetooth LE Security#

In both LE Legacy pairing and LE secure connections, the actual encryption is done with stream ciphers. This is because a stream cipher is computationally more efficient than block ciphers, and thus block ciphers are only used for key generation and authentication purposes.

Let’s take a look at how everything fits together:

Key Generation#

../../_images/le_key_hierarchy.png

The job of the key generation algorithms is to create a password which is very hard to break, thus rendering the communication useless for anyone without a key. It is a way of ensuring that no attacker can passively listen to a transmission.

LE Legacy and LE Secure Connections both use AES-CCM for encryption. Under FIPS (Federal Information Processing Standards), which is considered a safe encryption algorithm. However, this all depends on the key being securely computed, which brings us to the differences of the two.

LE Legacy Pairing

As we can see in the above illustration, the function s1() that calculates the short-term key (STK) (Short-Term key used for the initial encryption in LE Legacy connections) uses AES-128. This is the AES-ECB that we deemed unsafe for encryption given that the plaintext to be encrypted was longer than 128 bits. However, in this case AES-ECB is only used to encrypt one data block so we can safely say there is no chance of compromising repeating data patterns.

Once the STK is generated, the connection is encrypted using AES-CCM, which is considered a safe encryption algorithm. The LTK is then transferred over the encrypted connection.

The big weak point of the LE Legacy connections is the derivation of the TK, which is thoroughly explained in Bluetooth Low Energy 5 Security Fundamentals.

LE Secure Connections

The big differentiator for LE Secure Connections is the use of Elliptic-Curve Diffie-Hellman method explained earlier. This ensures that a passive listener to the pairing process won’t be able to resolve the shared key between two devices. For MITM-protection, use OOB, Passkey entry or Numeric comparison pairing. For more information, see Bluetooth Low Energy 5 Security Fundamentals.

The key generation algorithm used here is AES-CMAC. The input to this function is the shared secret Diffie-Hellman key, together with the Nonces and the Addresses. Since the Diffie-Hellman key is secret, the LTK is too.

An important distinction between LE Legacy and LE Secure Connections is that in LE Secure Connections the LTK is never shared over the air.

Confirmation Value Algorithms#

The job of the key generation is to ensure no passive listening, Confirmation values help authenticate a connection. This means that an attacker will have a hard time pretending to be someone else, and thus thwart a MITM attack. In the Bluetooth Low Energy 5 Security Fundamentals lab we discussed the vulnerabilities of such attacks using the different Association Models in LE Legacy and LE Secure Connections. However, this assumed that the confirmation value is safely generated, meaning that if someone listens in on the transmission while the confirmation value and the random Nonce are exchanged, they aren’t able to figure out the private keys. These private keys are the TK in the case of LE Legacy, and ra and rb in LE Secure Connections.

In this section, we will discuss which algorithms are used for implementing this one-way function.

LE Legacy connections

To reiterate the core learning goal from Bluetooth Low Energy 5 Security Fundamentals lab, choosing the TK through the different Association Model rules is by far the weakest link in the security chain of LE Legacy pairing. It is no use to have a strong Confirmation Value Algorithm if an attacker already knows the TK. If an attacker can listen in to the connection when the Confirmation Value is being sent, the attacker has probably intercepted the TK as well (if using Just Works or Passkey Entry pairing).

But let’s assume that the TK is not compromised. This is possible either if the attacker didn’t listen in to the transmission early enough to intercept the TK, or the OOB-method with a secure channel was used. The random Nonce generated is encrypted with TK as a key (using AES-128 as the confirmation value algorithm). Again, this is safe because we only encrypt one 128-bit block of data, and any data pattern is thus impossible to detect.

LE Secure Connections

In LE Secure Connections, Confirmation values are calculated and compared twice. Once for the key generation step (Diffie-Hellman), and once for the authentication step.

In the authentication step, the previously discussed HMAC-SHA-256 algorithm is used to calculate:

  • the hash of the random nonce of the device

  • the two public Diffie-Hellman keys exchanged earlier (PKa and PKb)

  • the private key derived through the specific Association Model chosen.

This ensures that this authentication value cannot be forged by anyone unless they also have the private keys (ra and rb derived through the different association models). It also ensures that anyone intercepting the confirmation value won’t be able to figure out what went into the function (including the private key), because of the nature of SHA-256 being a one-way function.

In the key generation step, we need to make sure that both devices are using the same key for encryption. First, we calculate the LTK and MAC-key using AES-CMAC, as described previously. These two should be identical on both devices, and thus we use the second Confirmation value algorithm to check this. The algorithm used here is also the AES-CMAC. It takes the MAC-key and the private key from the previous step as input together with Nonces, addresses, and the bits corresponding to the different IO-capabilities. This creates a confirmation value that can be safely transmitted. Both devices do this, and compare it to their own calculated version. If the check succeeds, the connection is encrypted with the LTK.

### Quiz Which statement(s) is true? 1. [x] HMAC is an algorithm that calculates a MAC by hashing the message together with private variables 1. [ ] We never use AES-ECB for anything because a pattern always is easy to distinguish 1. [x] The greatest vulnerability of LE Legacy pairing is choosing the TK. ### Why is LE Secure connections stronger than LE Legacy Just Works connections? 1. [x] LE Secure connections ensures no passive listening, even if attacker listens to the pairing process. 1. [ ] LE Legacy Just Works pairing uses AES-CCM, so there is no difference in security 1. [x] LE Secure connections provides significantly stronger security than LE Legacy connections

Task 1 – Security Drivers - AES-128#

In this exercise we will take a closer look at the APIs (Application Program Interface) of the some of the drivers provided in the SimpleLink F3 CC23xx SDK. There is a dedicated AES hardware accelerator increasing the speed of the AES operations on these devices.

In this task we will look at the Secure Hashing Algorithm, Random Number Generator, and the driver for the AES-128. We will encrypt a 128-bit string of plaintext with AES-128. A brute force attack on an AES-128 encrypted ciphertext is practically infeasible, as the illustration below shows.

Key size

Number of connections

1-bit

2

2-bit

4

4-bit

16

8-bit

256

16-bit

65536

32-bit

4294967296

64-bit

1.84467 * 1019

128-bit

3.40282 * 1038

Note

The age of the universe

The number of combinations needed to crack a 128-bit key is 3.4 * 1038 which is an insane amount of computations. If you put one of today’s supercomputers on the task it would take it longer than the age of the universe to crack it.

This AES algorithm is the plain vanilla electronic codebook (ECB) method, and is thus only safe for data strings up to 128-bits. If you are encrypting longer strings than 128-bit, remember to use an algorithm that diffuses the output so that any data patterns are obscured.

This is the motivation for using the RNG to generate a key: it will provide a unique random number.

In this task we will use the project example sha2hash located in (SDK  INSTALLATION PATH)\examples\rtos\(YOUR LAUNCHPAD)\drivers\sha2hash.

1) Build and flash the SHA2 example.

Now try hashing different strings. There are four things you should remark:

  • The hash looks completely random and unrelated to the input

  • The length of the hash is always the same

  • Even minuscule changes to the input changes the output completely and seemingly at random

  • Two equal strings always produces the same hash.

2) Use the RNG driver to generate a random seed.

We will now use this project as a basis for testing out AES-128, as it contains all the functionality we need.

Open SysConfig and add an instance of the RNG driver (SysConfig → TI DRIVERS → RNG)

../../_images/add_rng.png

Also, turn on the RCL driver (SysConfig → TI DRIVERS → RCL)

../../_images/add_rcl.png

Include the the CryptoKeyPlaintext.h utility in sha2hash.c.

sha2hash.c#
#include <ti/drivers/RNG.h>
#include <ti/drivers/cryptoutils/cryptokey/CryptoKey.h>
#include <ti/drivers/cryptoutils/cryptokey/CryptoKeyPlaintext.h>

Since we will be using 32 bytes buffers for the rest of this task, you can change printHash to only print 32 bytes.

sha2hash.c :: printHash() - Modify this line to use 32 byte buffers#
/*
 *  ======== printHash ========
 */
void printHash(UART2_Handle handle, uint8_t* msg)
{
   .
   .
   .
/* Print result */
UART2_write(handle, formatedMsg, 32, NULL); 
}

The main function will now be changed to generate a random key and print it to the serial monitor. It is worth looking at the header-files RNG.h and CryptoKey.h to understand the APIs and the data structures used below.

For CC23X0 devices, RNG must be initialized by application in a task context with interrupts enabled using the following steps prior to the use of the Radio because CC23X0 uses the ADC samples from radio as noise that is conditioned using CBC MAC to generate seed for RNG driver.

Add the following in the sha2sha.c file:

Step 1: Required header file#
//required for external syscfg variable RNGLPF3RF_noiseInputWordLen
#include <ti/drivers/rng/RNGLPF3RF.h> 
Step 2: External APIs#
// Use the function provided by RCL to read noise input //
extern int_fast16_t RCL_AdcNoise_get_samples_blocking(uint32_t *buffer, uint32_t numWords);
Step 3: Read noise input from RCL using RCL_AdcNoise_get_samples_blocking():#
void GetRCL_ADCNoise (void)
{
        int_fast16_t rclStatus, result;

        // User's global array for noise input based on size provided in syscfg //
        static uint32_t localNoiseInput[80]; //Minimum array size 80 words

        // Clear noise input //
        memset(localNoiseInput, 0, sizeof(localNoiseInput));

        // Fill noise input from RCL //
        //RNGLPF3RF_noiseInputWordLen is external variable from RNGLPF3RF.h
       rclStatus = RCL_AdcNoise_get_samples_blocking(localNoiseInput, RNGLPF3RF_noiseInputWordLen);
            if (rclStatus != 0)
                {
                    //Handle error;
                }

        // Initialize the RNG driver noise input pointer with global noise input array from user //
        result = RNGLPF3RF_conditionNoiseToGenerateSeed(localNoiseInput);
                if ( rclStatus != 0)
                        {
                            //Handle error;
                        }
}
RNG Operation

RNG operation

Before starting a RNG operation, the application must do the following:

  1. Call RNG_init() to initialize the driver’s global instance data.

  2. Call RNG_Params_init() to initialize the RNG_Params to default values.

  3. Modify the RNG_Params as desired.

  4. Call RNG_open() to open an instance of the driver.

Entropy Pool Management

At any time after calling RNG_init(), the application may call RNG_fillPoolIfLessThan() to add entropy to the pool which will then make future requests for entropy execute faster. Note that the driver never automatically refills the pool. However, if the pool is empty, the RNG driver will still generate entropy upon request (for example when RNG_getRandomBits() is called).

The application is responsible for deciding when it is appropriate to spend the time and energy to refill the pool. One suggested location to do so is the idle thread.

RNG operations

Use RNG_getRandomBits() to obtain random bits from the entropy pool and copy them to a buffer/array. The caller must allocate memory sufficient to hold at least the number of bits of random data requested.

After the RNG operation completes

After the RNG operation completes, the application should either start another operation or close the driver by calling RNG_close(). Note that the singleton instance of the driver, along with its associated pool of entropy will still exist and will be used by any future RNG_open() calls. Note that closing the driver instance may not be strictly required, but is good practice.

For more information on the RNG Driver, it is recommended to read RNG.h file reference.

The main function will now be changed to generate a random key and print it to the serial monitor. It is worth looking at the header-files RNG.h and CryptoKey.h to understand the APIs and the data structures used below.

sha2hash::mainThread() – The main function in our project.#
void *mainThread(void *arg0)
{
  .
  .
  .

if (!uart2Handle) {
    /* UART2_open() failed */
    while (1);
}

/* Erase everything under this if-statement in the original project 
 and replace with the following code: */

GetRCL_ADCNoise();

/* RNG variables*/
RNG_Params params;

//Initializing the RNG driver
RNG_init();
RNG_fillPoolIfLessThan(RNG_POOL_BYTE_SIZE);

//Initialize a handle to the RNG driver and a CryptoKey to store random number.
RNG_Handle handle;
CryptoKey entropyKey;

uint8_t entropyBuffer[16];

//Opens an instance of the RNG
handle = RNG_open(0, NULL);

if (!handle) {
    // Handle error
    while(1);
 }

//Initialize entropyKey as a blank CryptoKey
uint16_t keyLength = 16;
CryptoKeyPlaintext_initBlankKey(&entropyKey, entropyBuffer, keyLength);

//Generate the random number and put it in entropyKey
result = RNG_generateKey(handle, &entropyKey);

if (result != RNG_STATUS_SUCCESS) 
{
    // Handle error
    while(1);
}

RNG_close(handle);

// Print out the random key
printHash(uart2Handle, entropyKey.u.plaintext.keyMaterial);
return 0;
}

Now the function will write random numbers to the serial monitors. Press the reset-button and observe that completely new random values are generated each time. (Note that the printHash function will always print out 32 bytes, so you can set keyLength to a different length but it will not necessarily be reflected in the print.)

../../_images/aes_generated_key.png

RNG Generated Key#

Perfect! Now we are able to generate a key with the required level of security for encryption.

3) Now we will use this key to encrypt a string using AES-128.

Keep in mind that this algorithm is only safe for encryption when encrypting data strings of 128 bits (16 bytes) or less, otherwise a pattern may emerge.

Warning

Low-level drivers

Note that the drivers used in this exercise are not thread safe, meaning that if different threads call them at the same time, strange bugs can appear. For the specific thread-safe implementations see (SDK INSTALLATION PATH )/docs/tidrivers/tidriversAPIs.html. We will use a hardware interrupt disable function to make the calling of the drivers critical sections of our code.

Open SysConfig and add and instance of the AESECB driver.

../../_images/add_aesecb.png

Copy the code below to enable encryption, and be sure to look up anything unclear in the documentation.

sha2hash.c - Include drivers and define variables.#
// Import AESECB Driver definitions, function and hardware interrupts
#include <ti/drivers/AESECB.h>
#include <ti/drivers/dpl/HwiP.h>

/* Defines */
#define MAX_MSG_LENGTH 256

/* UART pre-formated strings */
static const char promptSecretInfo[] = "\n\n\rSecret information to encrypt: ";
static const char promptEncrypt[]    =    "\n\n\rEncrypted text:                ";

//The information to be encrypted and buffer for encrypted information
uint8_t secretInformation[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
                       0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
uint8_t encryptedInformation[sizeof(secretInformation)];

We are still using the code snippet from step 2, so don’t delete it. Add the following in mainThread():

sha2hash. c :: mainThread() – The encryption operation.#
//Printing secretInformation to serial monitor
UART2_write(uart2Handle, promptSecretInfo, strlen(promptSecretInfo), NULL);
printHash(uart2Handle, secretInformation);

// Define name for AESECB channel index
#define AESECB_INSTANCE 0

//Begin Critical section
HwiP_disable();

//Initialize AES ECB driver
AESECB_init();
AESECB_Params aesParams;
AESECB_Params_init(&aesParams);
AESECB_Handle handleAES = AESECB_open(AESECB_INSTANCE, NULL);

// Set up AESECB_Operation
AESECB_Operation encryptOperation;
AESECB_Operation_init(&encryptOperation);

encryptOperation.key               = &entropyKey;
encryptOperation.input             = secretInformation;
encryptOperation.output            = encryptedInformation;
encryptOperation.inputLength       = sizeof(secretInformation);

//Do the encryption
int_fast16_t encryptionResult = AESECB_oneStepEncrypt(handleAES, &encryptOperation);

//Print the encrypted text to serial monitor
UART2_write(uart2Handle, promptEncrypt, strlen(promptEncrypt), NULL);
printHash(uart2Handle, encryptedInformation);

//Close AES operation
AESECB_close(handleAES);
HwiP_enable();

return 0;

// The results should be:
// 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60,
// 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97,

The serial monitor should now print this:

../../_images/aes_encrypted1.png

Superb! You have now safely encrypted some data using a safely generated key.

Warning

Implementation Limitations

  • Decryption is not supported since the AES HW only supports encryption.

  • Only plain text CryptoKeys are supported by this implementation.

Task 2 – Security Drivers - AES-CCM#

In this exercise we will take a look at the Bluetooth LE encryption; AES-CCM. This mode of operation provides both authentication and encryption. This algorithm is a bit more complex than AES-128 from the previous task, so a general understanding of this algorithm is recommended before you begin.

Warning

Application-layer Encryption

In Bluetooth LE connections, packets can be encrypted after pairing as part of the Bluetooth Core Spec as discussed. However, the Bluetooth Core Spec does not contain a mechanism for encrypting advertisement packets.

If you do want to encrypt advertisements, you can do application-level encryption. This will allow you to encrypt a message sent by a beacon, and several Central devices can read the information from the beacon at once. However, it is important to note that you are then not using the built-in security features in pairing and bonding in TI’s BLE5-Stack. It is then your own responsibility that the information is safely encrypted and decrypted. As always the security of a system should be evaluated as one, not just on component level.

If you do decide to use application-layer Encryption, AES-CCM should be your choice. Then the shared secret key of the AES-CCM can be coded into the devices before they are deployed. This makes sense since the process of exchanging keys and authentication are the most vulnerable steps. Remember to change the key before the (counter overflows) (Remember that AES-CTR, which is a subroutine in AES-CCM, uses a counter when encrypting to ensure diffusion.).

If you want to see this algorithm in action in a pairing process, it is highly encouraged to take a look at the aesKeyAgreement driver example ((SDK  INSTALLATION PATH)\examples\rtos\(YOUR LAUNCHPAD)\drivers\aesKeyAgreement).

Having the AESCCM.h File Reference open next to this task is useful. (You can navigate to the AESCCM.h file from the link.)

This exercise will look similar to the previous one, and we will reuse some of the functions. The procedure looks very similar to AES-ECB, with the exception of two new lines: Nonce and Message Authentication Code (MAC). Recall from AES-CTR that the encryption process itself uses a nonce together with a counter, which is then encrypted with the key and XORed with the plaintext to be sent secretly. Because this is now effectively a stream cipher, a MAC is needed for verifying the integrity of the message. Therefore a MAC is calculated first, and then encrypted together with the message. If someone tampers with the message between the transmitting and receiving device, it can be discovered because it is very hard to modify both the message and its MAC correctly.

If you want to hard code a key here instead, please do. If you hard code a key in both the Central and the Peripheral before deploying the devices, you know that no-one can intercept this key (since it’s not being transmitted over the air).

In SysConfig, you can remove the AESECB instance. Add an AESCCM instance.

../../_images/add_aesccm.png

First we print to screen the information that we want to encrypt, thus making it easier to verify whats going on along the way.

sha2hash.c :: mainThread() – The information to be encrypted#
//The information to be encrypted and buffer for encrypted information
uint8_t secretInformation[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                               0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                               0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E};

//Printing secretInformation to serial monitor
UART2_write(uart2Handle, promptSecretInfo, strlen(promptSecretInfo), NULL);
printHash(uart2Handle, secretInformation);

We will now initialize the encryption process and encryption handle.

Add these include statements at the top, together with the rest!#
#include <ti/drivers/AESCCM.h>
#include <ti/drivers/dpl/HwiP.h>
sha2hash.c :: mainThread() – Initialization of the encryption process#
//Encryption

AESCCM_init();
AESCCM_Handle encryptHandle;
CryptoKey cryptoKey;
int_fast16_t encryptionResult;
uint8_t nonce[] = {0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0};
uint8_t mac[8]={0x17, 0xE8, 0xD1, 0x2C, 0xFD, 0xF9, 0x26, 0xE0};
uint8_t aad[8]= {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
uint8_t ciphertext[sizeof(secretInformation)];
uint8_t keyingMaterial[16] = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
                              0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF};


encryptHandle = AESCCM_open(0, NULL);
if (encryptHandle == NULL) {
// handle error
}

CryptoKeyPlaintext_initKey(&cryptoKey, keyingMaterial, sizeof(keyingMaterial));

AESCCM_OneStepOperation encryptOperation;
AESCCM_OneStepOperation_init(&encryptOperation);

encryptOperation.key               = &cryptoKey;
encryptOperation.aad               = aad;
encryptOperation.aadLength         = sizeof(aad);
encryptOperation.input             = secretInformation;
encryptOperation.output            = ciphertext;
encryptOperation.inputLength       = sizeof(secretInformation);
encryptOperation.nonce             = nonce;
encryptOperation.nonceLength       = sizeof(nonce);
encryptOperation.mac               = mac;
encryptOperation.macLength         = sizeof(mac);

In the encrypting function, several exciting things are happening at once. First, the secretInformation is run through the AES-CBC procedure, where the last block is kept as the MAC. Then both the message and the MAC are encrypted using AES-CTR. Later we print the encrypted information to the screen.

sha2hash.c :: mainThread() – Encryption function#
encryptionResult = AESCCM_oneStepEncrypt(encryptHandle, &encryptOperation);

if (encryptionResult != AESCCM_STATUS_SUCCESS) {
//handle error
}

static const char promptEncrypt[]    = "\n\n\rEncrypted text: ";

UART2_write(uart2Handle, promptEncrypt, strlen(promptEncrypt), NULL);
printHash(uart2Handle, encryptOperation.output);

AESCCM_close(encryptHandle);
../../_images/aesccm_encryption.png

The decryption process follows a similar path as encryption, with the exception of the modification of some of the AES-CCM parameters:

sha2hash.c :: mainThread() – Decrypting procedure setup#
//DECRYPTION

uint8_t decryptInfo[sizeof(ciphertext)];
AESCCM_OneStepOperation DecryptOperation;
AESCCM_Handle decryptHandle;
AESCCM_Params decryptparams;
int_fast16_t decryptionResult;

AESCCM_Params_init(&decryptparams);
decryptparams.returnBehavior = AESCCM_RETURN_BEHAVIOR_CALLBACK;
decryptparams.callbackFxn = ccmCallback;

decryptHandle = AESCCM_open(0, &decryptparams);

if (decryptHandle == NULL) {
// handle error
}

AESCCM_OneStepOperation_init(&DecryptOperation);

DecryptOperation.key               = &cryptoKey;
DecryptOperation.aad               = aad;
DecryptOperation.aadLength         = sizeof(aad);
DecryptOperation.input             = ciphertext;
DecryptOperation.output            = decryptInfo;
DecryptOperation.inputLength       = sizeof(ciphertext);
DecryptOperation.nonce             = nonce;
DecryptOperation.nonceLength       = sizeof(nonce);
DecryptOperation.mac               = mac;
DecryptOperation.macLength         = sizeof(mac);

The callback function ccmCallback() must be defined as a function above the main() function:

sha2hash.c :: ccmCallback() declaration – Callback function#
/*
 *  ======== ccmCallback ========
 */
void ccmCallback(AESCCM_Handle handle,
             int_fast16_t returnValue,
             AESCCM_Operation *operation,
             AESCCM_OperationType operationType)
sha2hash.c :: add ccmCallback() at the bottom of the file – Callback function#
/*
 *  ======== ccmCallback ========
 */
void ccmCallback(AESCCM_Handle handle,
             int_fast16_t returnValue,
             AESCCM_Operation *operation,
             AESCCM_OperationType operationType)
{
switch(returnValue){
    case AESCCM_STATUS_SUCCESS:
        // handle decryption success here
        break;
    case AESCCM_STATUS_MAC_INVALID:
        // handle error
        break;
    default:
        break;
}
}

The AES-CCM decrypting function also does many things at the same time. The ciphertext is first decrypted using AES-CTR with the provided nonce and key. Then the MAC code is checked against the last block AES-CBC from the sent message. If these match, we have verified the integrity of the message.

sha2hash.c :: mainThread() – Decrypting function#
decryptionResult = AESCCM_oneStepDecrypt(decryptHandle, &DecryptOperation);

Since we are using callback mode for the decryption operation, the return status for DecryptOperation is sent to the callback (ccmCallback()). Add the following code snippet to print the decrypted message to screen and compare it with the original.

sha2hash.c :: mainThread() – Printing decrypted information to screen#
static const char promptDecrypt[] =    "\n\n\rDecrypted text:  ";

UART2_write(uart2Handle, promptDecrypt, strlen(promptDecrypt), NULL);
printHash(uart2Handle, DecryptOperation.output);

AESCCM_close(decryptHandle);

Run the code and double-check that the string has not changed after going though encryption and decryption. The output should be the secret information.

../../_images/aesccm_decryption.png

Note that at this point there is a high probability to get a stack overflow. The sha2hash example has a 1 kB stack per default, and we have spent it all and more. If this happens, go to main_tirtos.c and increase the size of THREADSTACKSIZE.

main_tirtos.c – Increase the task stack size.#
/* Stack size in bytes */
#define THREADSTACKSIZE    2048

Great! We have now encrypted and decrypted using AES-CCM. If you still want to experiment more, try to tamper with the encrypted message before passing the message to the decrypting function, and see what happens.

Task 3 – Filter Accept List#

A Filter Accept List is a list of devices that the Link Layer (LL) (You can read more about the link layer in the BLE-Stack User’s Guide) can use for filtering advertisers, scanners or initiators. This is a great way of saving power, as the LL will be able to filter packets without awakening the host. Initially, if the peer device is not using privacy, the incoming packets can be filtered in the RF Core without waking up the M4. This will save even more power.

Using a Filter Accept List can be a great security enabler. If you are working with a system built with a fixed set of Bluetooth LE devices, you know all the device addresses and you can add them to the Filter Accept List. Alternatively, you can update the white list at runtime with addresses of Bluetooth LE devices that are paired to your device.

Even when using privacy a Filter Accept List can be useful. The Filter Accept List contains only identity addresses. If a resolvable private address (RPA) is used, one must have the Identity Resolving Key (IRK) to be able to know the identity address of a device. IRKs are exchanged after pairing and bonding, thus it’s not possible to use a pre-programmed Filter Accept List in combination with privacy. In this case, we use the pairing process for authentication and then we can safely add the device to the Filter Accept List.

The GAP Bond Manager can be configured to automatically add bonded devices to the Filter Accept List by setting the GAPBOND_AUTO_SYNC_WL parameter. If you want to know more about Privacy and the Filter Accept List, you can read about it in the TI BLE5-Stack User’s Guide under the “Privacy” section inside “Privacy and the Filter Accept List”.

In this exercise we will implement the Filter Accept List on both the Central and the Peripheral. For this we will use Basic BLE as Central and Peripheral.

1) Flash Basic BLE as a Central and Basic BLE as a Peripheral to two LaunchPads.

Open serial windows for both. If you need a refresher on how to do this, see the BLE Scanning and Advertising. Do a scan with Basic BLE Central, and note how many devices show up:

../../_images/basic_ble_scan.png

(Note that the number of discovered devices will depend on your environment.)

2) Add a device to the Filter Accept List.

We now need to add the identity address of our Basic BLE Peripheral to the white list of the Basic BLE Central. For simplicity we will switch Basic BLE Peripheral to use ADDRMODE_PUBLIC on the peripheral device, since this will make Basic BLE Peripheral advertise with its identity address.

Open basic_ble.syscfg for the Basic BLE Peripheral and go to BLE → General Configuration and change the Address mode to Public Address.

../../_images/adv_security_basicble_addrmode.png

Reprogram the peripheral device and start the program. The addresses of the peripheral device is now written in the serial monitor.

../../_images/peripheral_address.png

We will now add this address to a Filter Accept List on the central side. An important thing to keep in mind when we insert the address is the endianness. In the serial window, the address is written in the big-endian format, however the function adding the address needs it in the little-endian format. In our example, the address 0xA434F1AED765 is transformed to [0x65, 0xD7, 0xAE, 0xF1, 0x34, 0xA4]. A good place to add this is in the function Menu_scanStartCB() in app_menu.c, as this function deals with the scanning of other devices. First we update the scan filter policy to use a Filter Accept List filter, then we add the address of our peripheral device as demonstrated in the code snippet below: (Remember to change the address to your own!)

app_menu.c :: Menu_scanStartCB() – Enable Filter Accept List scanning and add peripheral to Filter Accept List#
/*********************************************************************
 * @fn      Menu_scanStartCB
 *
 * @brief   A callback that will be called once the scan item in
 *          the scanningMenu is selected.
 *          Sets the parameters needed for a scan and starts the scan.
 *
 * @param   index - the index in the menu
 *
 * @return  none
 */
void Menu_scanStartCB(uint8 index)
{
    bStatus_t status;
    const BLEAppUtil_ScanStart_t centralScanStartParams =
    {
        /*! Zero for continuously scanning */
        .scanPeriod     = DEFAULT_SCAN_PERIOD, /* Units of 1.28sec */

        /*! Scan Duration shall be greater than to scan interval,*/
        /*! Zero continuously scanning. */
        .scanDuration   = DEFAULT_SCAN_DURATION, /* Units of 10ms */

        /*! If non-zero, the list of advertising reports will be */
        /*! generated and come with @ref GAP_EVT_SCAN_DISABLED.  */
        .maxNumReport   = APP_MAX_NUM_OF_ADV_REPORTS
    };

    //ADD LINE START

    //Update the scan filter policy
    uint8_t whitelistfilter = SCAN_FLT_POLICY_AL;
    GapScan_setParam(SCAN_PARAM_FLT_POLICY, &whitelistfilter);

    //Adding an address to the white list
    static uint8_t bdAddressPeer[6] = {0x65, 0xD7, 0xAE, 0xF1, 0x34, 0xA4};
    HCI_LE_ClearAcceptListCmd(""); //Clear the accept list
    HCI_LE_AddAcceptListCmd (ADDRMODE_PUBLIC, bdAddressPeer); //Add a accept list entry

    //ADD LINE END

    status = BLEAppUtil_scanStart(&centralScanStartParams);

    // Print the status of the scan
    MenuModule_printf(APP_MENU_GENERAL_STATUS_LINE, 0, "Call Status: ScanStart = "
                      MENU_MODULE_COLOR_BOLD MENU_MODULE_COLOR_RED "%d" MENU_MODULE_COLOR_RESET,
                      status);
}

3) Flash your Basic BLE Central Device and do a new scan.

Now only your peripheral device should show up. (If you are getting 0 discovered devices, double-check that you added the correct address and that your peripheral device is advertising.)

../../_images/discovery_with_AL.png

Great! Now only the correct peripheral will show up in the scan, and thus only the central will only connect to this device. Next, we want to activate white list in the Peripheral device as well. This will ensure that only the intended Central device will be able to connect.

4) Add a Filter Accept List on the peripheral side.

Again, for this to work, set Simple Central to use a public address. Open the central basic_ble.syscfg and go to BLE → General Configuration and change the Address mode to Public Address.

For Basic BLE peripheral, we will first configure the filter policy for advertisement set 1. Open the peripheral basic_ble.syscfg and go to BLE → Broadcaster Configuration and go to BLE → Advertisement set 1 → Advertisement Parameters and set Filter Policy to Process requests only from devices in AL.

../../_images/set_advfilter.png

We will also need to add a Filter Accept List to the peripheral device. Add the code snippet below in app_main.c on the App_StackInitDoneHandler() function. Remember again to change to the address of the Central device, and the endianness of it.

app_main.c :: App_StackInitDoneHandler() – Add Filter Accept List#
/*********************************************************************
 * @fn      App_StackInitDone
 *
 * @brief   This function will be called when the BLE stack init is
 *          done.
 *          It should call the applications modules start functions.
 *
 * @return  none
 */
void App_StackInitDoneHandler(gapDeviceInitDoneEvent_t *deviceInitDoneData)
{
    bStatus_t status = SUCCESS;

    // Menu
    Menu_start();

   //ADD LINE START

    //Add the central device to the white list
    static uint8_t bdAddressPeer[6] = {0x52, 0xD3, 0xAE, 0xF1, 0x34, 0xA4};
    HCI_LE_ClearAcceptListCmd(""); //Clear the accept list
    HCI_LE_AddAcceptListCmd (ADDRTYPE_PUBLIC, bdAddressPeer); //Add a accept list entry

    //ADD LINE END

   .
   .
   .
    }

Try to connect and make sure it connects with your Central device.

../../_images/connection_central.png

Central connected to the Peripheral’s address#

../../_images/connection_peripheral.png

Peripheral connected to the Central’s address#

5) Now try changing the address in the Filter Accept List, and connect again.

Now you will not be able to make a connection. Alternatively, try to connect to the peripheral with a different device. You will get a timeout on your connection request since this peripheral now only accepts connections from the device with the correct address.

Task 4 – Bonding and the SNV#

When two devices are bonded, the bonding information is stored in the Non-Volatile (NV) memory area. This means that if the unit resets or the power is toggled, the bonding information is still stored. This is handled through the Simple Non-Volatile (SNV) driver. It is therefore useful to know how to manipulate and interact with the SNV. Luckily, the GAP Bond Manager has exactly the right APIs to use.

Warning

Re-flashing the device

Keep in mind that when you reprogram your device from Code Composer Studio, the SNV will be overwritten and all the bonds deleted.

Error

Privacy and Addresses

Smart phones usually use private addresses, meaning the device address of a smart phone will change from time to time. This means hard-coding a smart phone address is often a bad idea.

For this task use a device you can configure to use a public address, such as BTool, if possible.

1) Take a look at the chapter on the GAP Bond Manager

in the TI BLE5-Stack User’s Guide and find all the macros used to set parameters related to the bond information and describes the full API including commands, configurable parameters, events, and callbacks.

APIs for Stored Bonding Information

GAPBOND_COUNT: This Read-only Macro will return the number of devices currently bonded to the device.

GAPBOND_BONDING_ENABLED: Whether or not the device accepts bonding.

GAPBOND_LRU_BOND_REPLACEMENT: When the maximum number of bonds is reached, you will need to delete a bond before adding a new one. Instead of deleting all bonds, or deleting a specific bond, this parameter enables the device to delete the Least Recently Used (LRU) one.

GAPBOND_ERASE_ALLBONDS: This will erase all the bonds stored in the SNV.

GAPBOND_ERASE_SINGLEBOND: This macro lets you delete a bond with a specific device address.

GAPBOND_BOND_FAIL_ACTION: If the bonding fails, this macro will let you decide what the device should do next. Choose between do nothing (GAPBOND_FAIL_NO_ACTION), re-start the pairing process (GAPBOND_FAIL_INITIATE_PAIRING) and terminate the connection (GAPBOND_FAIL_TERMINATE_LINK).

2) Program Basic BLE as peripheral on one device

Use a second device (BTool, iOS or Android phone) to connect, pair and bond with this device. First we want to know how many peer devices are bonded to the device. One way to do this is by simply requesting a pair request to the peripheral.

Pairing and Bonding
  1. Flash a Basic BLE project as peripheral to a device.

  2. Connect the BTool, iOS or Android phone to the peripheral device. Open a serial terminal, you can do this through CCS or PuTTY. You can use the Environment Setup SimpleLink Academy to configure the Serial Terminal.

../../_images/serialt_peri.png

Serial terminal from Peripheral#

For this example, an iOS Phone will be used. Connect from the SimpleLink Connect App to the peripheral device.

../../_images/app_mobileconnect.png

SimpleLink Connect App: Connected to the Peripheral#

../../_images/serialt_conn.png

Serial Terminal Connected to the SimpleLink Connect App#

  1. From the app, once connection has been established: TI Simple Peripheral Service → Characteristic 5 → Read. This will allow request to Pair with the peripheral device and will prompt to enter the default Key 123456 and click Pair.

  2. In the terminal window, Pairing Status line will show Starting and once the key has been entered the status will show Complete to Encrypted to Bond saved to indicate a successful bond. The pairing and bonding is completed.

../../_images/pair_completed.png

Pairing Completed#

Great! Now observe that the device has been bonded with the peripheral and do not change if you hit the reset button on the device. This is because the bonds are saved in Non-volatile memory, and is thus safe from resets and power cuts.

../../_images/pairing_encrypted.png

Pairing Encrypted#

3) Delete a bond.

Let’s now say that we have reached the maximum number of bonded devices, and need to delete old bonding information to make room for a new device. First, we will delete all the bonded devices. To do this, we will apply a Button Function to delete the bond between the device. The following code will be used until the end of Task 4.

Solution delete all bonds

First we need to remove the functions of the buttons in the basic_ble as the default button function is to navigate through the Basic BLE menu.

  1. Open Sysconfig → TI Driver Apps → Button. Select the hardware use to None.

../../_images/button_config.png

SysConfg: Button#

  1. Sysconfig → GPIO. Add two GPIOs: CONFIG_GPIO_BUTTON_0 and CONFIG_GPIO_BUTTON_1 and select the Use hardware to LaunchPad Button BTN-1 (Left) and LaunchPad Button BTN-2 (Right).

../../_images/gpio_config.png

SysConfg: GPIO Buttons#

  1. Add the following code in the app_main.c file. For this exercise, we will use gpioButtonFxn1 and the gpioButtonFxn0 will be used in the next following task.

app_main.c :#
/* Driver Header files */
#include <ti/drivers/GPIO.h>

/* Driver configuration */
#include "ti_drivers_config.h"

#include "gap.h"
#include "gapbondmgr.h"

/*
 *  ======== gpioButtonFxn0 ========
 *  Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_0.
 *
 *  Note: GPIO interrupts are cleared prior to invoking callbacks.
 */
void gpioButtonFxn0(uint_least8_t index)
{
    uint8_t deviceAddress[B_ADDR_LEN + 1] = {ADDRTYPE_PUBLIC, 0xA4,0x34,0xF1,0xAE,0xD7,0x65};

    /* Toggle an LED */
    GPIO_toggle(CONFIG_GPIO_LED_RED);
    /* Delete a single Bond */
    GAPBondMgr_SetParameter(GAPBOND_ERASE_SINGLEBOND, B_ADDR_LEN + 1, deviceAddress);

} //this function will be used in the next task

/*
 *  ======== gpioButtonFxn1 ========
 *  Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_1.
 *  This may not be used for all boards.
 *
 *  Note: GPIO interrupts are cleared prior to invoking callbacks.
 */
void gpioButtonFxn1(uint_least8_t index)
{
    /* Toggle an LED */
    GPIO_toggle(CONFIG_GPIO_LED_GREEN);
    /*Deleting all bonded device*/
    GAPBondMgr_SetParameter(GAPBOND_ERASE_ALLBONDS, 0, 0);
}
app_main.c :: in the appMain function, add the following code to init GPIO interrupts/callbacks#
/* Call driver init functions */
    GPIO_init();

    /* Configure the LED and button pins */
    GPIO_setConfig(CONFIG_GPIO_LED_RED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    GPIO_setConfig(CONFIG_GPIO_LED_GREEN, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    GPIO_setConfig(CONFIG_GPIO_BUTTON_0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);

    /* Turn on user LED */
    //GPIO_write(CONFIG_GPIO_LED_RED, CONFIG_GPIO_LED_ON);

    /* Install Button callback */
    GPIO_setCallback(CONFIG_GPIO_BUTTON_0, gpioButtonFxn0);
    GPIO_setCallback(CONFIG_GPIO_BUTTON_1, gpioButtonFxn1);

    /* Enable interrupts */
    GPIO_enableInt(CONFIG_GPIO_BUTTON_0);

    /*
     *  If more than one input pin is available for your device, interrupts
     *  will be enabled on CONFIG_GPIO_BUTTON1.
     */
    if (CONFIG_GPIO_BUTTON_0 != CONFIG_GPIO_BUTTON_1)
    {
         //Configure BUTTON1 pin
        GPIO_setConfig(CONFIG_GPIO_BUTTON_1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);

         //Install Button callback
        GPIO_setCallback(CONFIG_GPIO_BUTTON_1, gpioButtonFxn1);
        //Button_setCallback(CONFIG_GPIO_BUTTON_1, gpioButtonFxn1);
        GPIO_enableInt(CONFIG_GPIO_BUTTON_1);
    }

Rebuild the program and flash to the device.

Perfect. Now connect, pair (Follow steps again to pair with basic_ble using Characteristic 5 and click on the ‘Read’ button) and bond the Basic BLE peripheral and Central device. GAPBOND_ERASE_ALLBONDS cannot delete the bonding information while the device is in a connection, so terminate the connection and delete the bonding information.

4) Delete just one bond.

Sometimes deleting all the bonded devices is a bit too drastic, and we only want to remove one bond to make room for a new one. The GAPBOND_LRU_BOND_REPLACEMENT command is really useful for this purpose, as it will enable the device to delete the least recently used bond when a new device wants to bond and the Bond list is full. But we will instead demonstrate the GAPBOND_ERASE_SINGLEBOND-command for practical purposes. This command will delete the bond with a specific device (LRU bond replacement can also be configured in SysConfig.).

Solution Delete Single Bond

Configure the Button_0 to delete the bond from the from the CC2340R5 LaunchPad. We are using the code from the previous task, remember to replace the address with the one of your Central device.

app_main.c :: Using the following function#

/*
 *  ======== gpioButtonFxn0 ========
 *  Callback function for the GPIO interrupt on CONFIG_GPIO_BUTTON_0.
 *
 *  Note: GPIO interrupts are cleared prior to invoking callbacks.
 */
void gpioButtonFxn0(uint_least8_t index)
{
    uint8_t deviceAddress[B_ADDR_LEN + 1] = {ADDRTYPE_PUBLIC, 0xA4,0xF8,0xF2,0x21,0x2B,0x0B};

    /* Toggle an LED */
    GPIO_toggle(CONFIG_GPIO_LED_RED);
    /* Delete a single Bond */
    GAPBondMgr_SetParameter(GAPBOND_ERASE_SINGLEBOND, B_ADDR_LEN + 1, deviceAddress);

}

Reset the peripheral device and connect, pair and bond the central device to the peripheral to add it to the list of bonded devices. Now press Button_0 and the central will timeout and when you hit the reset button in the peripheral, we have successfully deleted a bond from the SNV.

Task 5 – Key Regeneration Policy#

Warning

This task is only applicable to LE Secure Connections as LE Legacy pairing does not use the ECC procedure.

Generating ECC keys is a time consuming endeavor (The time it takes to generate one key is ~160 ms, compare this to the connection interval you are using), and thus the ability to generate these keys beforehand and reusing them for several connections translates to more responsive systems. A way to minimize this time usage is to use the same private keys for multiple consecutive connections. This will free the computational resources. Keep in mind that the Bluetooth core spec recommends not using the same password for more than 10 consecutive connections. To do this, we will reuse Project Zero and the GAP Bond Manager. Take a look in the TI BLE5-Stack User’s Guide’s chapter about the GAP Bond Manager to find how to configure this.

Solution

Open SysConfig → BLE → Bond Manager and set ECC Key Generation Policy to the number of times you want to reuse the key. Every time the device pairs with a new device, the counter is decremented by 1, or 3 if the pairing fails. When the counter reaches zero, the key is regenerated. Choose a value for this parameter that suits your security needs.

../../_images/set_keygenpolicy.png

It is worth noting that this parameter has no effect if you are manually specifying the keys.

References#

Bluetooth Core Specification Version 5.3

TI BLE5-Stack User’s Guide

BLE5-Stack API Documentation

AESECB.h File Reference

AESCCM.h File Reference

NIST: Guide to Bluetooth Security

Bluetooth Low Energy 5 Security Fundamentals

BLE Scanning and Advertising

Technical Reference Manual

RNG.h file reference