涉及 配對與綁定 相關知識。
這裏準確的說法應該是叫配對碼,而不是密碼。輸入這個這個配對碼是配對過程中可選的一部分。
我們需要的輸入“密碼”這個功能,其實是配對過程中的一部分。而配對過程又是需要首先交換配對信息,然後協議棧會根據交換的信息才決定是否有輸入密碼這一過程。
無論是靜態密碼還是動態密碼(配對碼,後面統一叫密碼)都是可以看做是配對過程中的一種認證方式即”我是我”,因爲這樣可以一定程度上避免他人連接你的設備,因爲他們看不到設備上顯示的配對碼,而你自己去可以看到。
配對碼的輸入是配對過程中生成TK的一種方式即Passkey Entry。另外還有Just
Works和Out of Band 兩種方式。TK的生成是爲了後續再生成STK用來加密鏈路然後分發LTK,IRK,CSRK。(如果配對信息交換是沒是指明綁定也就不需要後續的這裏密鑰的分發了)。
靜態密碼設置 :
這裏只是演示靜態密碼,不需要綁定
認證方式就是 :passkey entery。
那麼我們要做的有如下幾步:
1: 首先設置要輸入的靜態密碼
2: 設置配對時會交換的信息:根據《配對與綁定》的介紹如果我們需要手機輸入密碼,那麼配對時就要設置只具有顯示器(這樣就會是一端顯示,一端輸入,雖然我們真的沒顯示器,但是設置的是靜態密碼所以也是可以的),設置需要MITM攻擊保護。
3:觸發配對。使用的是配對觸發方式:3 。所以我們將具有notify性質的RX特徵值的cccd(客戶端配置描述符)設置爲需要認證和加密的安全鏈路。因爲手機端使能notify是需要cccd的,那麼當手機連接板子後 點擊rx特徵值的notify按鈕後主機會發一個寫命令 寫板子上rx特徵值的cccd,因爲初試鏈路是不完全的,這時手機就會返回寫出錯,然後啓動配對過程。
//設置靜態密碼步驟 細分詳解:
//步驟一
//定義靜態密碼,配對密碼只能是 6-digit ASII string
//步驟二
//是設置靜態密碼
//步驟三
//設置配對時要交換的信息
//步驟四
//觸發配對信息發給對端設備
//步驟五
//板子回覆配對信息
//步驟一
//定義靜態密碼,配對密碼只能是 6-digit ASII string
#define STATIC_PASSKEY "123456" /**< Static pin. */
//改結構體 可以設置靜態密碼
static ble_opt_t m_static_pin_option;
//定義這兩個參數後,我們需要設置以下靜態密碼,在gap_params_init()函數的最後。
//步驟二 ://以下是設置靜態密碼操作
void gap_params_init(void)
{
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_IO_CAPABILITIES BLE_GAP_IO_CAPS_DISPLAY_ONLY
//不使用帶外數據
#define SEC_PARAM_OOB 0
//鏈路加密密鑰的長度
#define SEC_PARAM_MIN_KEY_SIZE 7
#define SEC_PARAM_MAX_KEY_SIZE 16
//定義全局變量, 設置配對啓動後交換的信息.
ble_gap_sec_params_t m_sec_params;
//初始化 配對啓動後交換的信息.
void sec_params_init(void)
{
m_sec_params.bond = SEC_PARAM_BOND;
m_sec_params.mitm = SEC_PARAM_MITM;
m_sec_params.io_caps = SEC_PARAM_IO_CAPABILITIES;
m_sec_params.oob = SEC_PARAM_OOB;
m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
}
//步驟四 ://觸發配對信息發給對端設備,修改在 ble_nus.c
static uint32_t rx_char_add(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
{
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
ble_gatts_char_md_t char_md;
ble_gatts_attr_md_t cccd_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t ble_uuid;
ble_gatts_attr_md_t attr_md;
memset(&cccd_md, 0, sizeof(cccd_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
//BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
//觸發配對信息發給對端設備
//將上面一行改爲下面一行,這樣手機使能板子的rx特徵值得notify功能時,
//就會因爲因爲沒有寫權限而觸發配對,手機就會發來配對請求,
//然後板子回覆配對信息. 怎麼回覆?看步驟五.
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&cccd_md.write_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = &cccd_md;
char_md.p_sccd_md = NULL;
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint8_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
return sd_ble_gatts_characteristic_add(p_nus->service_handle,
&char_md,
&attr_char_value,
&p_nus->rx_handles);
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
}
//步驟五 ://板子回覆配對信息.
//當手機發來配對請求時,這對板子來說是一個事件,即配對事件。
//最終由dispatch派發函數交給各個服務或模塊的事件處理函數。
//那麼收到這個配對請求後回覆步驟二中設置的配對信息就可以了。
//和判斷配對是否成功,如果不成功斷開連接,從而阻止他人任意連接。
static void on_ble_evt(ble_evt_t * p_ble_evt)
{
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
//err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
sec_params_init();
err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &m_sec_params, NULL);
APP_ERROR_CHECK(err_code);
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("pair success\r\n");
}
else
{
err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
}
break;
}
程序運行,打開lightblue連接板子,點擊listen for notification 就會彈出藍牙配對請求的對話框。正確輸入靜態密碼即可連上。錯誤或超時輸入需要退出重新操作配對。