NRF51822蓝牙服务(7)——静态密码配对

前言

有时候我们希望能够在连接的时候进行密钥的验证,以保障连接的安全。为了保证低功耗蓝牙的绝大多数安全特征,必须完成两个事情。首先是设备必须互相配对;其次,设备必须分配用于加密、保障隐私并对消息进行验证的密钥。这里我们尝试使用静态密码的方式完成蓝牙配对。

实验分析

这里,我们仍然使用前面的串口实验例程。

配对连接过程:

  1. 手机连接上之后立刻调用安全请求API(sd_ble_gap_authenticate),这样手机收到后就会发送配对请求。
  2. 回复手机的配对请求,设置不绑定。这样手机每次收到设备的安全请求就会发送配对请求过去从而启动配对。
  3. 之后的配对过程会自动进行。我们只需要根据收到的BLE_GAP_EVT_AUTH_STATUS事件,判断其状态是否成功,来决定配对是不是成功了,从而决定断不断开连接。

首先,我们先定义静态密码。

#define STATIC_PASSKEY "654321"

注意:官方规定配对密码只能是6位ASCII字符串

#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY     0x01   /**< 6-digit Passkey. */

/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */
typedef struct
{
  uint8_t passkey[BLE_GAP_PASSKEY_LEN];         /**< 6-digit passkey in ASCII ('0'-'9' digits only). */
} ble_gap_evt_passkey_display_t;

接着定义密码操作结构体。

static ble_opt_t m_static_pin_option;

完成以上操作之后,我们需要设置一下静态密码,设置的操作需要在协议栈初始化之后,所以我们将设置密码操作放在gap_params_init()函数的最后:

{
    uint32_t                err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *) DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(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 SEC_PARAM_BOND     0
//因为要输入密码,就是一种MITM攻击保护,所以这里设置MITM
#define SEC_PARAM_MITM     1

完成这些之后。手机将会发来配对请求,之后设备需要回复,因此需要是实现配对回复函数:

#define SEC_PARAM_MIN_KEY_SIZE 7
#define SEC_PARAM_MAX_KEY_SIZE 16
ble_gap_sec_params_t sec_params;

static void resp_pair_request()
{
    uint32_t err_code;	

    sec_params.bond = SEC_PARAM_BOND;
    sec_params.mitm = SEC_PARAM_MITM;
    sec_params.io_caps = SEC_PARAM_IO_CAPABILITIES;
    sec_params.oob = SEC_PARAM_OOB;
    sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
    sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
	
	err_code= sd_ble_gap_sec_params_reply(m_conn_handle,
    BLE_GAP_SEC_STATUS_SUCCESS,&sec_params,NULL);
    APP_ERROR_CHECK(err_code);
}

最后,就是添加上面说的第三个步骤的代码。

static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t                         err_code;
    
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_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;
			//一建立连接就发送安全请求,从而促使手机发送配对请求过来
			ble_gap_sec_params_t params;
			params.bond = SEC_PARAM_BOND;
			params.mitm = SEC_PARAM_MITM;
			sd_ble_gap_authenticate(m_conn_handle, ¶ms);
			//
            break;
            
        case BLE_GAP_EVT_DISCONNECTED:
            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
            APP_ERROR_CHECK(err_code);
            m_conn_handle = BLE_CONN_HANDLE_INVALID;
            break;

        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
        
				   resp_pair_request();
			
            break;
		
		case BLE_GAP_EVT_PASSKEY_DISPLAY:
	
			break;
		
		//判断配对是否成功,如果不成功就断开连接,从而阻止他人任意连接
		case BLE_GAP_EVT_AUTH_STATUS:
			if(p_ble_evt->evt.gap_evt.params.auth_status.auth_status == BLE_GAP_SEC_STATUS_SUCCESS)
			{
				printf("Success!");
			}
			else
			{
				sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
			}
			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;

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

到这里,就完成了所有操作。

最后梳理下流程:手机连接设备后,设备会立即发送安全请求。因为手机和设备没有绑定,所以手机收到设备发送过来的安全请求后就会发送配对请求给设备。设备从而回复配对请求且不绑定,设备后续的配对过程由协议栈自动完成,并最终返回给上层配对完成事件。判断配对是否成功,如果失败就断开连接,从而阻止他人随意连接设备。

结果验证

  • 手机连接蓝牙,我们可以发现弹出密码输入窗口
  • 输入“654321”才能完成蓝牙配对
  • 断开蓝牙重连,发现仍然需要重新输入密码

总结

通过这个实验,我们学会了如何使用静态密码连接蓝牙。

 

你可能感兴趣的:(BLE)