Getting Bluetooth Done – Part 5 (SMP)

Getting Bluetooth done – Part 5 (SMP)

  • principle
    • Security Manager (SM for short, don’t get it wrong)
    • Secret key
    • pair
    • Key generation
    • Specific key distribution
    • Summary of principles
  • ESP32 program
    • initialization
    • GAP callback function

Principle

Security Manager (SM for short, don’t get it wrong)

According to the previous test, the two devices can communicate through BLE. However, these two demos are equipped with SPP, which means transparent transmission. In other words, the data of the BLE communication between the two devices in the air is Transparent, which means that it will be captured by other devices and then cracked out. If it is used to transmit some private things, it is of course unsafe. Therefore, there is also a protocol in the ble protocol stack that is specifically designed to do this. (Encrypting data transmitted over the air), Security Manager Procotol, referred to as SMP.

Secret key

We know that data encryption requires a set of encryption algorithms, which can not only deduce the encrypted data according to the algorithm, but also decrypt the encrypted data. At this time, the algorithm must have a parameter to modify (if it is fixed, someone else can decrypt the data if it captures it and follow this algorithm). This parameter is called a secret key.

Pairing

So, how does the BLE device that receives the data know the secret key of the BLE that sends the data? At this time, it needs to be negotiated before sending the data. This process is called pairing.
You want to use your mobile phone to connect a Bluetooth bracelet. If the brother next door has the same bracelet as you, and the names of the two devices are the same, then how do you know that the bracelet you are connecting is yours? We can display on the bracelet screen that there is a mobile phone that wants to connect to the bracelet, and then add a button. The user can determine whether he wants to connect. In order to prevent the eldest brother from also connecting to the eldest brother’s bracelet, a string of numbers can be displayed on the phone. The bracelet displays the same number, we only need to determine whether it is the same number. This process is called authentication, which is a small step in pairing. This string of numbers is called key.

There are two types of authentication,

  1. OOB, this kind of thing does not require human participation, for example, the key can be exchanged through the wifi that the two are already connected to.
  2. MITM requires someone to confirm the key. There are several ways:
    A. One device displays the key, and the other device enters the key.
    B. Both devices display the same key, and the user confirms
    C. Both devices need to enter the same key
    D. Neither device requires input. This means there is no authentication.
    Of course, some BLE devices do not have screens or buttons, so you cannot enter the key or view the key. This requires deciding which authentication method to use based on the BLE device, which is called IO Capabilities.

There are these six ways.
NoInputNoOutput
DisplayOnly
NoInputNoOutput1
DisplayYesNo
KeyboardOnly
KeyboardDisplay

We found that to connect our mobile phone to the bracelet, we only need to enter the key for the first time after buying it, and no need to do so later. This is because the secret keys in the ble of the mobile phone and the bracelet have been stored in their respective memories. Use Just use it directly next time. This behavior is called binding.

Secret key generation

The key has been obtained through the above steps, but this key may be peeked by others. This key cannot be directly used as a secret key. At this time, the two BLEs use this key as a temporary secret key to establish a temporary connection. , then use this temporary key to transmit the real secret key generated by each, and finally use this real secret key to encrypt the data to be transmitted.

Specific key distribution

The last step is that other BLE protocols also have some secret keys and some sensitive data, which are later sent through the final truly secure connection, which is called specific key distribution.

Principle summary

To summarize, SMP is a security management protocol that encrypts transmitted data. It is divided into three major parts, pairing, key generation, and specific key distribution. There are actually two pairing methods, LE legacy pairing and LE Secure Connections. The latter is more secure and only available after Bluetooth 4.2. Both parties need to support this. There are two major types of authentication, OOB and MITM. It mainly depends on whether people are required to participate. Of course, the device uses OOB first. Which authentication method is used in MITM depends on whether the two devices can be input and displayed. See the figure below for details.

ESP32 program

Initialization

Open the official demo

The previous initialization part is the same as the previous chapter, and the following initialization is added to the SMP part.

/* set the security iocap & amp; auth_req & amp; key size & amp; init key response key parameters to the stack*/
    esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication
    esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; //set the IO capability to No output No input
    uint8_t key_size = 16; //the key size should be 7~16 bytes
    uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
    uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
    //set static passkey
    uint32_t passkey = 123456;
    uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE;
    uint8_t oob_support = ESP_BLE_OOB_DISABLE;
    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, & amp;passkey, sizeof(uint32_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, & amp;auth_req, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, & amp;iocap, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, & amp;key_size, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, & amp;auth_option, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, & amp;oob_support, sizeof(uint8_t));
    /* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you,
    and the response key means which key you can distribute to the master;
    If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you,
    and the init key means which key you can distribute to the slave. */
    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, & amp;init_key, sizeof(uint8_t));
    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, & amp;rsp_key, sizeof(uint8_t));

They all use the esp_ble_gap_set_security_param() function to achieve different functions by passing different parameters. Let’s analyze this code.

  1. ESP_BLE_SM_SET_STATIC_PASSKEY sets the static secret key, which is the number displayed on the phone when it is connected to the bracelet.
  2. ESP_BLE_SM_SET_STATIC_PASSKEY Local device authentication requirements, this parameter has the following options
#define ESP_LE_AUTH_NO_BOND 0x00 /*!< 0*/ /* relate to BTM_LE_AUTH_NO_BOND in stack/btm_api.h */
#define ESP_LE_AUTH_BOND 0x01 /*!< 1 << 0 */ /* relate to BTM_LE_AUTH_BOND in stack/btm_api.h */
#define ESP_LE_AUTH_REQ_MITM (1 << 2) /*!< 1 << 2 */ /* relate to BTM_LE_AUTH_REQ_MITM in stack/btm_api.h */
#define ESP_LE_AUTH_REQ_BOND_MITM (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_MITM)/*!< 0101*/
#define ESP_LE_AUTH_REQ_SC_ONLY (1 << 3) /*!< 1 << 3 */ /* relate to BTM_LE_AUTH_REQ_SC_ONLY in stack/btm_api.h */
#define ESP_LE_AUTH_REQ_SC_BOND (ESP_LE_AUTH_BOND | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1001 */ /* relate to BTM_LE_AUTH_REQ_SC_BOND in stack/btm_api.h */
#define ESP_LE_AUTH_REQ_SC_MITM (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY) /*!< 1100 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM in stack/btm_api.h */
#define ESP_LE_AUTH_REQ_SC_MITM_BOND (ESP_LE_AUTH_REQ_MITM | ESP_LE_AUTH_REQ_SC_ONLY | ESP_LE_AUTH_BOND) /*!< 1101 */ /* relate to BTM_LE_AUTH_REQ_SC_MITM_BOND in stack/btm_api.h */

Whether to bind, use MITI, and use Secure Connections mode (SC for short)
3. ESP_BLE_SM_IOCAP_MODE IO Capabilities selection
4. ESP_BLE_SM_MAX_KEY_SIZE This is to set the length of the last two secret keys generated by BLE, rather than the length of the static key that the user sees on the phone. The larger the value, the higher the encryption level, between 7-16
5. ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH Select whether to only receive the specified authentication mode, that is, if you select “Yes”, the device will only accept the authentication mode (MITM mode and binding) set during initialization, otherwise it will not accept the connection. For example, if the parameter ESP_BLE_SM_AUTHEN_REQ_MODE is set to ESP_LE_AUTH_REQ_SC_MITM_BOND, then the parameter of the peer device also needs to be set to ESP_LE_AUTH_REQ_SC_MITM_BOND.
6. ESP_BLE_SM_OOB_SUPPORT whether to enable OOB
7. ESP_BLE_SM_SET_INIT_KEY initializes a specific key
8. ESP_BLE_SM_SET_RSP_KEY distributes a specific key

GAP callback function

After the initialization is completed, other operations are completed in the GAP callback, which has the following code more than the GAP callback in the previous chapter.

case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT");
        /* Call the following function to input the passkey which is displayed on the remote device */
        //esp_ble_passkey_reply(heart_rate_profile_tab[HEART_PROFILE_APP_IDX].remote_bda, true, 0x00);
        break;
    case ESP_GAP_BLE_OOB_REQ_EVT: {<!-- -->
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_OOB_REQ_EVT");
        uint8_t tk[16] = {<!-- -->1}; //If you paired with OOB, both devices need to use the same tk
        esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk));
        break;
    }
    case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_LOCAL_IR_EVT");
        break;
    case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_LOCAL_ER_EVT");
        break;
    case ESP_GAP_BLE_NC_REQ_EVT:
        /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability.
        show the passkey number to the user to confirm it with the number displayed by peer device. */
        esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true);
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_NC_REQ_EVT, the passkey Notify number:%d", param->ble_security.key_notif.passkey);
        break;
    case ESP_GAP_BLE_SEC_REQ_EVT:
        /* send the positive(true) security response to the peer device to accept the security request.
        If not accept the security request, should send the security response with negative(false) accept value*/
        esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
        break;
    case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
        ///show the passkey number to the user to input it in the peer device.
        ESP_LOGI(GATTS_TABLE_TAG, "The passkey Notify number: d", param->ble_security.key_notif.passkey);
        break;
    case ESP_GAP_BLE_KEY_EVT:
        //shows the ble key info share with peer device to the user.
        ESP_LOGI(GATTS_TABLE_TAG, "key type = %s", esp_key_type_to_str(param->ble_security.ble_key.key_type));
        break;
    case ESP_GAP_BLE_AUTH_CMPL_EVT: {<!-- -->
        esp_bd_addr_t bd_addr;
        memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
        ESP_LOGI(GATTS_TABLE_TAG, "remote BD_ADDR: x x",\
                (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
                (bd_addr[4] << 8) + bd_addr[5]);
        ESP_LOGI(GATTS_TABLE_TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);
        ESP_LOGI(GATTS_TABLE_TAG, "pair status = %s",param->ble_security.auth_cmpl.success ? "success" : "fail");
        if(!param->ble_security.auth_cmpl.success) {<!-- -->
            ESP_LOGI(GATTS_TABLE_TAG, "fail reason = 0x%x",param->ble_security.auth_cmpl.fail_reason);
        } else {<!-- -->
            ESP_LOGI(GATTS_TABLE_TAG, "auth mode = %s",esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode));
        }
        show_bonded_devices();
        break;
    }
    case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: {<!-- -->
        ESP_LOGD(GATTS_TABLE_TAG, "ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT status = %d", param->remove_bond_dev_cmpl.status);
        ESP_LOGI(GATTS_TABLE_TAG, "ESP_GAP_BLE_REMOVE_BOND_DEV");
        ESP_LOGI(GATTS_TABLE_TAG, "-----ESP_GAP_BLE_REMOVE_BOND_DEV----");
        esp_log_buffer_hex(GATTS_TABLE_TAG, (void *)param->remove_bond_dev_cmpl.bd_addr, sizeof(esp_bd_addr_t));
        ESP_LOGI(GATTS_TABLE_TAG, "----------------------------------------");
        break;
    }
    case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT:
        if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS){<!-- -->
            ESP_LOGE(GATTS_TABLE_TAG, "config local privacy failed, error status = %x", param->local_privacy_cmpl.status);
            break;
        }

        esp_err_t ret = esp_ble_gap_config_adv_data( & amp;heart_rate_adv_config);
        if (ret){<!-- -->
            ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret);
        }else{<!-- -->
            adv_config_done |= ADV_CONFIG_FLAG;
        }

        ret = esp_ble_gap_config_adv_data( & amp;heart_rate_scan_rsp_config);
        if (ret){<!-- -->
            ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret);
        }else{<!-- -->
            adv_config_done |= SCAN_RSP_CONFIG_FLAG;
        }

Mostly just print some information.
ESP_GAP_BLE_SEC_REQ_EVT indicates that a protection connection request from the peer is received. Use esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); if the device accepts it, the security request is enabled.
ESP_GAP_BLE_NC_REQ_EVT, ESP_GAP_BLE_PASSKEY_NOTIF_EVT, ESP_GAP_BLE_KEY_EVT, these three are entered based on the IO Capabilities of this device and the peer device.
ESP_GAP_BLE_AUTH_CMPL_EVT, after completing the security authentication, you will enter this event, and then call a function show_bonded_devices(); mainly display the device information on the screen after the authentication is completed and bound.
ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT, when esp_ble_gap_config_local_privacy() is called to configure the privacy mode of the local device, this event will be called back to the application after the operation is completed. At this time, a random address will be generated, and then the random address will be used to configure the broadcast data. This address is automatically changed every once in a while, and the ESP_GAP_BLE_LOCAL_IR_EVT event will occur after the change.