How to enable encrypted link in nRF52832 firmware?

peerManagerInit() has called pm_init() and setting security parameters. But nRF connect shows "Unencrypted link". How can I enabled encrypted link in nRF52832 firmware?

int main(void) {

...

peerManagerInit(true);
gapParamsInit();

...

}

  • #include "sdk_config.h"
    #include "advertising.h"
    #include "ble_conn_state.h"
    #include "error.h"
    #include "fds.h"
    #include "nrf_log.h"
    #include "peer_manager.h"
    #include "peer_manager_handler.h"
    #include "peer_manager_types.h"
    #include "security.h"
    
    #if 0 // nrf51
    #define SEC_PARAM_TIMEOUT               30                                          /**< Timeout for Pairing Request or Security Request (in seconds). */
    #define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
    #define SEC_PARAM_MITM                  1                                           /**< Man In The Middle protection not required. */
    #define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_DISPLAY_ONLY                        /**< No I/O capabilities. */
    #define SEC_PARAM_OOB                   0                                           /**< Out Of Band data not available. */
    #define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE          16 /**< Maximum encryption key size. */
    #define SEC_PARAM_LESC                  0
    #define SEC_PARAM_KEYPRESS              0 
    
    #else
    #define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
    #define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection required (applicable when display module is detected). */
    #define SEC_PARAM_LESC                  0                                           /**< LE Secure Connections not enabled. */
    #define SEC_PARAM_KEYPRESS              0                                           /**< Keypress notifications not enabled. */
    #define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< No I/O capabilities. */
    #define SEC_PARAM_OOB                   0                                           /**< Out Of Band data not available. */
    #define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */
    #endif
    
    static void _pmEvtHandler(pm_evt_t const * pEvt) {
        ret_code_t errCode;
    
        switch (pEvt->evt_id) {
            case PM_EVT_BONDED_PEER_CONNECTED:
            {
                NRF_LOG_INFO("Connected to a previously bonded device.");
            } break;
    
            case PM_EVT_CONN_SEC_SUCCEEDED:
            {
                NRF_LOG_INFO("Connection secured: role: %d, conn_handle: 0x%x, procedure: %d.",
                             ble_conn_state_role(pEvt->conn_handle),
                             pEvt->conn_handle,
                             pEvt->params.conn_sec_succeeded.procedure);
            } break;
    
    
            case PM_EVT_CONN_SEC_FAILED:
            {
                NRF_LOG_INFO("Faield to secure connection with handle 0%x.", pEvt->conn_handle);
                errCode = sd_ble_gap_disconnect(pEvt->conn_handle,
                                          BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                if (errCode != NRF_ERROR_INVALID_STATE)
                {
                    APP_ERROR_CHECK(errCode);
                }
                //pEvt->conn_handle = BLE_CONN_HANDLE_INVALID;
                /* Often, when securing fails, it shouldn't be restarted, for security reasons.
                 * Other times, it can be restarted directly.
                 * Sometimes it can be restarted, but only after changing some Security Parameters.
                 * Sometimes, it cannot be restarted until the link is disconnected and reconnected.
                 * Sometimes it is impossible, to secure the link, or the peer device does not support it.
                 * How to handle this error is highly application dependent. */
            } break;
    
            case PM_EVT_CONN_SEC_CONFIG_REQ:
            {
                // Reject pairing request from an already bonded peer.
                pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
                pm_conn_sec_config_reply(pEvt->conn_handle, &conn_sec_config);
            } break;
    
            case PM_EVT_STORAGE_FULL:
            {
                // Run garbage collection on the flash.
                errCode = fds_gc();
                if (errCode == FDS_ERR_NO_SPACE_IN_QUEUES)
                {
                    // Retry.
                }
                else
                {
                    APP_ERROR_CHECK(errCode);
                }
            } break;
    
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
            {
                NRF_LOG_DEBUG("PM_EVT_PEERS_DELETE_SUCCEEDED");
                advertisingStart();
            } break;
    
            case PM_EVT_PEER_DATA_UPDATE_FAILED:
            {
                // Assert.
                APP_ERROR_CHECK(pEvt->params.peer_data_update_failed.error);
            } break;
    
            case PM_EVT_PEER_DELETE_FAILED:
            {
                // Assert.
                APP_ERROR_CHECK(pEvt->params.peer_delete_failed.error);
            } break;
    
            case PM_EVT_PEERS_DELETE_FAILED:
            {
                // Assert.
                APP_ERROR_CHECK(pEvt->params.peers_delete_failed_evt.error);
            } break;
    
            case PM_EVT_ERROR_UNEXPECTED:
            {
                // Assert.
                APP_ERROR_CHECK(pEvt->params.error_unexpected.error);
            } break;
    
            case PM_EVT_CONN_SEC_START:
            case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
            case PM_EVT_PEER_DELETE_SUCCEEDED:
            case PM_EVT_LOCAL_DB_CACHE_APPLIED:
            case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
                // This can happen when the local DB has changed.
            case PM_EVT_SERVICE_CHANGED_IND_SENT:
            case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
            default:
                break;
        }
    }
    
    
    /**@brief Function for the Peer Manager initialization.
     */
    int peerManagerInit(const bool eraseBonds) {
        ble_gap_sec_params_t secParam;
        ret_code_t errCode;
        
        errCode = pm_init();
        if (errCode != NRF_SUCCESS) {
            NRF_LOG_WARNING("pm_init() failed, errCode=0x%x\n", errCode);
            return ERROR_PEER_MANAGER_INITIALIZE_FAIL;
        }    
         
        if (eraseBonds) {
            errCode = pm_peers_delete();
            if (errCode != NRF_SUCCESS) {
                NRF_LOG_WARNING("pm_peers_delete() failed, errCode=0x%x\n", errCode);
                return ERROR_PEER_MANAGER_INITIALIZE_FAIL;
            } 
        }
        
            memset(&secParam, 0, sizeof(ble_gap_sec_params_t));
        
            // Security parameters to be used for all security procedures.
            secParam.bond           = SEC_PARAM_BOND;
            secParam.mitm           = SEC_PARAM_MITM;
            secParam.lesc           = SEC_PARAM_LESC;
            secParam.keypress       = SEC_PARAM_KEYPRESS;
            secParam.io_caps        = SEC_PARAM_IO_CAPABILITIES;
            secParam.oob            = SEC_PARAM_OOB;
            secParam.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
            secParam.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
            secParam.kdist_own.enc  = 1;
            secParam.kdist_own.id   = 1;
            secParam.kdist_peer.enc = 1;
            secParam.kdist_peer.id  = 1;
        
            errCode = pm_sec_params_set(&secParam);
            if (errCode != NRF_SUCCESS) {
                NRF_LOG_WARNING("pm_sec_params_set() failed, errCode=0x%x\n", errCode);
                return ERROR_PEER_MANAGER_INITIALIZE_FAIL;
            } 
        
            errCode = pm_register(_pmEvtHandler);
            if (errCode != NRF_SUCCESS) {
                NRF_LOG_WARNING("pm_register() failed, errCode=0x%x\n", errCode);
                return ERROR_PEER_MANAGER_INITIALIZE_FAIL;
            } 
    
        return 0;
    }
    
    
    #include "sdk_config.h"
    #include "ble.h"
    #include "ble_conn_params.h"
    #include "ble_gap.h"
    #include "gap.h"
    #include "error.h"
    #include "nrf_log.h"
    
    #define DEVICE_NAME       "ANCS2"                         /**< Name of the device. Will be included in the advertising data. */
    #define STATIC_PASSKEY    "123456"                        /**< Static passkey. */
    #define MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */
    #define MAX_CONN_INTERVAL MSEC_TO_UNITS(30, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */
    #define SLAVE_LATENCY     0                               /**< Slave latency. */
    #define CONN_SUP_TIMEOUT  MSEC_TO_UNITS(3000, UNIT_10_MS) /**< Connection supervisory time-out (4 seconds). */
    
    static ble_opt_t _gStaticPasskeyOption;	/**< Pointer to the struct containing static pin option. */
    
    /**@brief Function for initializing GAP connection parameters.
     *
     * @details Use this function to set up all necessary GAP (Generic Access Profile)
     *          parameters of the device. It also sets the permissions and appearance.
     */
    int gapParamsInit(void) {
        ret_code_t              errCode;
        ble_gap_conn_params_t   gapConnParams;
        ble_gap_conn_sec_mode_t secMode;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&secMode);
    
        errCode = sd_ble_gap_device_name_set(&secMode, (const uint8_t *)DEVICE_NAME, strlen(DEVICE_NAME));
        if (errCode != NRF_SUCCESS) {
            NRF_LOG_WARNING("sd_ble_gap_device_name_set() failed, errCode=0x%x", errCode);
            return ERROR_GAP_INITIALIZE_FAIL;
        }
    
        memset(&gapConnParams, 0, sizeof(gapConnParams));
    
        gapConnParams.min_conn_interval = MIN_CONN_INTERVAL;
        gapConnParams.max_conn_interval = MAX_CONN_INTERVAL;
        gapConnParams.slave_latency     = SLAVE_LATENCY;
        gapConnParams.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
        errCode = sd_ble_gap_ppcp_set(&gapConnParams);
        if (errCode != NRF_SUCCESS) {
            NRF_LOG_WARNING("sd_ble_gap_ppcp_set() failed, errCode=0x%x", errCode);
            return ERROR_GAP_INITIALIZE_FAIL;
        }
    
        uint8_t passkey[] = STATIC_PASSKEY;
    	_gStaticPasskeyOption.gap_opt.passkey.p_passkey = passkey;
    	errCode = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &_gStaticPasskeyOption);
    	if (errCode != NRF_SUCCESS) {
            NRF_LOG_WARNING("sd_ble_opt_set() failed, errCode=0x%x", errCode);
            return ERROR_GAP_INITIALIZE_FAIL;
        }
    
        return 0;
    }
    
    
    
    2577.gap.h2072.security.h

  • Hello,

    Initializing the peer manager is not enough to encrypt the link. I don't know what SDK version you are using, but in SDK17.1.0, you can see how the ble_app_hrs example calls pm_conn_secure() in the BLE_GAP_EVT_CONNECTED event in ble_evt_handler() in main.c.

    BR,

    Edvin

  • I am using SDK 16.0.0. Does SDK 16.0.0 has example for enabling encrypted link?

  • Thanks for your reply! I have checked the ble_app_hrs example SDK17.0.2. But I can find pm_conn_secure() is called.

    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ret_code_t err_code;

        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                NRF_LOG_INFO("Connected.");
                err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
                APP_ERROR_CHECK(err_code);
                m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
                err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
                APP_ERROR_CHECK(err_code);
                break;

            case BLE_GAP_EVT_DISCONNECTED:
                NRF_LOG_INFO("Disconnected, reason %d.",
                              p_ble_evt->evt.gap_evt.params.disconnected.reason);
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
                break;

            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;

            case BLE_GATTC_EVT_TIMEOUT:
                // Disconnect on GATT Client timeout event.
                NRF_LOG_DEBUG("GATT Client Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;

            case BLE_GATTS_EVT_TIMEOUT:
                // Disconnect on GATT Server timeout event.
                NRF_LOG_DEBUG("GATT Server Timeout.");
                err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
                                                 BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                APP_ERROR_CHECK(err_code);
                break;
        
            case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
                NRF_LOG_DEBUG("BLE_GAP_EVT_SEC_PARAMS_REQUEST");
                break;
            
            case BLE_GAP_EVT_AUTH_KEY_REQUEST:
                NRF_LOG_INFO("BLE_GAP_EVT_AUTH_KEY_REQUEST");
                break;

            case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
                NRF_LOG_INFO("BLE_GAP_EVT_LESC_DHKEY_REQUEST");
                break;

             case BLE_GAP_EVT_AUTH_STATUS:
                 NRF_LOG_INFO("BLE_GAP_EVT_AUTH_STATUS: status=0x%x bond=0x%x lv4: %d kdist_own:0x%x kdist_peer:0x%x",
                              p_ble_evt->evt.gap_evt.params.auth_status.auth_status,
                              p_ble_evt->evt.gap_evt.params.auth_status.bonded,
                              p_ble_evt->evt.gap_evt.params.auth_status.sm1_levels.lv4,
                              *((uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status.kdist_own),
                              *((uint8_t *)&p_ble_evt->evt.gap_evt.params.auth_status.kdist_peer));
                break;

            default:
                // No implementation needed.
                break;
        }
    }


    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupt.
     */
    static void ble_stack_init(void)
    {
        ret_code_t err_code;

        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);

        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);

        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);

        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }

Related