nrf52832 学习笔记配对和绑定
Posted 不咸不要钱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nrf52832 学习笔记配对和绑定相关的知识,希望对你有一定的参考价值。
nrf52832 学习笔记(六)配对和绑定
蓝牙在配对之前都是明文通信的,也就是说主从机之间传输的数据包可以被第三方抓取分析逆向,而且如果没有配对,谁都可以无密码连接,显然是不安全的。
配对
nrf52832 支持主从机配对和绑定操作的,但是做主机时配对和绑定没用过(官方论坛找到一个demo),下面的都是针对nrf52832做从机时的配对操作。
静态密码
日常使用蓝牙对从机进行连接时,会提示输入密码,这个其实就是一种配对过程.
- 蓝牙从机中存在一个静态密码.
- 主机连接到从机后,从机启动安全连接认证
- 主机接收到安全连接认证请求后,产生一个随机数,根据随机数和主机的静态密码计算出一个确认值
- 从机同样产生一个随机数,根据随机数和从机的静态密码计算出一个确认值,主从机交换随机数和确认值.
- 主从机通过自己的静态密码和交换来的随机数,计算确认值和交换来的确认值对比,如果一致则配对成功,不一致则断开连接
- 配对成功后,主从机根据两个随机数和静态密码 生成一个临时密匙,后面蓝牙通信都会经过该密匙加密处理
nrf52832 sdk中添加配对处理,首先在gap初始化中添加静态密码设置
#define STATIC_PASSKEY "123456"
static ble_opt_t m_static_pin_option;
/**@brief Function for the GAP initialization.
*
* @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
* device including the device name, appearance, and the preferred connection parameters.
*/
static void gap_params_init(void)
ret_code_t err_code;
//....其他初始化
//设置万能钥匙的存放区
uint8_t passkey[] = STATIC_PASSKEY;
m_static_pin_option.gap_opt.passkey.p_passkey = passkey;
err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
APP_ERROR_CHECK(err_code);
然后在协议栈回调函数的连接事件中添加启动安全连接认证函数,同时添加安全参数交换函数和认证失败断开连接处理.
#define IO_CAPS BLE_GAP_IO_CAPS_DISPLAY_ONLY //只有显示装置
#define BOND 0 //不绑定
#define OOB 0 //没有外带认证数据 例如使用NFC或者二维码交换一些信息
#define MITM 1 //中间人保护
#define MIN_KEY_SIZE 7 //密匙最小长度
#define MAX_KEY_SIZE 16 //密匙最大长度
//配对请求函数,交换配对信息
void pairng_request(void)
ble_gap_sec_params_t sec_params;
uint32_t err_code;
memset(&sec_params,0,sizeof(ble_gap_sec_params_t));
sec_params.bond = BOND;
sec_params.io_caps = IO_CAPS;
sec_params.max_key_size = MAX_KEY_SIZE;
sec_params.min_key_size = MIN_KEY_SIZE;
sec_params.oob = OOB ;
sec_params.mitm = MITM;
err_code=sd_ble_gap_sec_params_reply(m_conn_handle,BLE_GAP_SEC_STATUS_SUCCESS,&sec_params,NULL);
APP_ERROR_CHECK(err_code);
/**@brief Function for handling BLE events.
*
* @param[in] p_ble_evt Bluetooth stack event.
* @param[in] p_context Unused.
*/
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");
bsp_board_led_on(CONNECTED_LED);
bsp_board_led_off(ADVERTISING_LED);
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);
err_code = app_button_enable();
APP_ERROR_CHECK(err_code);
ble_gap_phys_t const phys =
.rx_phys = BLE_GAP_PHY_2MBPS,
.tx_phys = BLE_GAP_PHY_2MBPS,
;
err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
//启动连接后,连接成功,启动本次连接的安全认证
ble_gap_sec_params_t params;
params.bond = 0;
params.mitm = 1;
sd_ble_gap_authenticate(m_conn_handle,¶ms);
break;
case BLE_GAP_EVT_PHY_UPDATE_REQUEST://PHY更新请求
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_GAP_EVT_PHY_UPDATE: //PHY更新完成
NRF_LOG_INFO("tx: %d, rx: %d",
p_ble_evt->evt.gap_evt.params.phy_update.tx_phy,
p_ble_evt->evt.gap_evt.params.phy_update.rx_phy
);
break;
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected");
bsp_board_led_off(CONNECTED_LED);
m_conn_handle = BLE_CONN_HANDLE_INVALID;
err_code = app_button_disable();
APP_ERROR_CHECK(err_code);
advertising_start();
break;
case BLE_GAP_EVT_SEC_PARAMS_REQUEST: //安全参数交换请求
pairng_request();
break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
// No system attributes have been stored.
err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
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_CONN_PARAM_UPDATE:
NRF_LOG_INFO("conn_Param Update: %d,%d,%d,%d",
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.slave_latency,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.conn_sup_timeout
);
break;
case BLE_GAP_EVT_AUTH_STATUS:
//认证,如果认证失败,则断开连接
if(p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
else
sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
default:
// No implementation needed.
break;
动态密码
动态密码和静态密码基本类似,只是不用在gap初始化时设置静态密码
//#define STATIC_PASSKEY "123456"
//static ble_opt_t m_static_pin_option;
/**@brief Function for the GAP initialization.
*
* @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
* device including the device name, appearance, and the preferred connection parameters.
*/
static void gap_params_init(void)
ret_code_t err_code;
//....其他初始化
//设置万能钥匙的存放区
//uint8_t passkey[] = STATIC_PASSKEY;
//m_static_pin_option.gap_opt.passkey.p_passkey = passkey;
//err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
//APP_ERROR_CHECK(err_code);
在协议栈回调者函数中添加一个事件处理将随机密码输出.
case BLE_GAP_EVT_PASSKEY_DISPLAY:
NRF_LOG_INFO("passkey: %c,%c,%c,%c,%c,%c",
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[0],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[1],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[2],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[3],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[4],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[5]
);
break;
绑定
绑定是将第一次配对后产生的长期密匙信息和对应MAC存储在flash中,下次再遇到对应MAC地址就不需要进行配对输入密码操作,直接交换密匙信息即可。配对和绑定整个流程十分复杂,nordic 的SDK中也给了对应的驱动库,和上面的配对不同,下面使用sdk中的pm库文件进行配对绑定操作。
添加库文件
-
开启SDK配置项
-
添加库文件
-
添加文件路径
从机
如果使用静态密码,仍然在gap初始化时设置静态密码
#define STATIC_PASSKEY "123456"
static ble_opt_t m_static_pin_option;
/**@brief Function for the GAP initialization.
*
* @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
* device including the device name, appearance, and the preferred connection parameters.
*/
static void gap_params_init(void)
ret_code_t err_code;
//....其他初始化
//设置万能钥匙的存放区
uint8_t passkey[] = STATIC_PASSKEY;
m_static_pin_option.gap_opt.passkey.p_passkey = passkey;
err_code = sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
APP_ERROR_CHECK(err_code);
然后在主函数中进行pm管理器初始化
#include "peer_manager.h"
#include "peer_manager_handler.h"
#define SEC_PARAM_BOND 1 /**< Perform bonding. */
#define SEC_PARAM_MITM 1 /**< Man In The Middle protection is enabled. */
#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_DISPLAY_ONLY /**< Display Only. */
#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. */
/**@brief Function for handling Peer Manager events.
*
* @param[in] p_evt Peer Manager event.
*/
static void pm_evt_handler(pm_evt_t const * p_evt)
pm_handler_on_pm_evt(p_evt);
pm_handler_flash_clean(p_evt);
switch (p_evt->evt_id)
case PM_EVT_PEERS_DELETE_SUCCEEDED:
advertising_start();
break;
default:
break;
///Added for bonding
/**@brief Function for the Peer Manager initialization.
*/
static void peer_manager_init(void)
ret_code_t err_code;
err_code = pm_init();
APP_ERROR_CHECK(err_code);
err_code = pm_register(pm_evt_handler);
APP_ERROR_CHECK(err_code);
ble_gap_sec_params_t sec_param;
memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
sec_param.bond = SEC_PARAM_BOND;
sec_param.mitm = SEC_PARAM_MITM;
sec_param.lesc = SEC_PARAM_LESC;
sec_param.keypress = SEC_PARAM_KEYPRESS;
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
sec_param.oob = SEC_PARAM_OOB;
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 1;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 1;
err_code = pm_sec_params_set(&sec_param);
APP_ERROR_CHECK(err_code);
最后在连接后启动配对绑定处理函数,也可以由主机启动配对绑定处理函数
/**@brief Function for handling BLE events.
*
* @param[in] p_ble_evt Bluetooth stack event.
* @param[in] p_context Unused.
*/
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");
bsp_board_led_on(CONNECTED_LED);
bsp_board_led_off(ADVERTISING_LED);
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);
err_code = app_button_enable();
APP_ERROR_CHECK(err_code);
ble_gap_phys_t const phys =
.rx_phys = BLE_GAP_PHY_2MBPS,
.tx_phys = BLE_GAP_PHY_2MBPS,
;
err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
/启动配对绑定处理函数
err_code = pm_conn_secure(p_ble_evt->evt.gap_evt.conn_handle, false);
if (err_code != NRF_ERROR_BUSY)
APP_ERROR_CHECK(err_code);
/Added for bonding
break;
case BLE_GAP_EVT_PHY_UPDATE_REQUEST://PHY更新请求
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_GAP_EVT_PHY_UPDATE: //PHY更新完成
NRF_LOG_INFO("tx: %d, rx: %d",
p_ble_evt->evt.gap_evt.params.phy_update.tx_phy,
p_ble_evt->evt.gap_evt.params.phy_update.rx_phy
);
break;
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected");
bsp_board_led_off(CONNECTED_LED);
m_conn_handle = BLE_CONN_HANDLE_INVALID;
err_code = app_button_disable();
APP_ERROR_CHECK(err_code);
advertising_start();
break;
case BLE_GAP_EVT_SEC_PARAMS_REQUEST: //安全参数交换请求
//pairng_request();
break;
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
// No system attributes have been stored.
err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
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_CONN_PARAM_UPDATE:
NRF_LOG_INFO("conn_Param Update: %d,%d,%d,%d",
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.slave_latency,
p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.conn_sup_timeout
);
break;
case BLE_GAP_EVT_PASSKEY_DISPLAY:
NRF_LOG_INFO("passkey: %c,%c,%c,%c,%c,%c",
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[0],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[1],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[2],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[3],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[4],
p_ble_evt->evt.gap_evt.params.passkey_display.passkey[5]
);
break;
case BLE_GAP_EVT_AUTH_STATUS:
//认证,如果认证失败,则断开连接
if(p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
else
sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION)nrf52832 学习笔记蓝牙主从机连接和连接参数更新