最近答疑碰到幾次都提到 需要實現手機每次連接上設備后,立刻出發配對並要求輸入密鑰的功能。 這里就單獨寫一個教程供大家參考下。
配對的目的是為了對鏈路進行加密。以提高藍牙的傳輸安全。
關於配對的一些相關知識在 靜態密碼/動態隨機密碼教程中有一些介紹。對於使用來說,理解一下配對相關流程就行了。
這里額外說個問道比較多的配對和綁定區別的問題:
關於配對和綁定,一些人可能一直分不清楚他們的區別。配對是為了對提高藍牙鏈路傳輸的安全性。而綁定是配對發起時的一個可選配置。 綁定並不是一個獨立存在的過程。 可以理解成 配對有兩種方式, 沒有設置綁定表示的配對請求和設置綁定標志的配對請求。
對於沒有設置綁定標志的配對請求,配對的過程就是
1,鏈路信息的交換,主要就是兩邊設備的i/o能力,是否需要綁定,鏈路是否需要MITM保護,如果設置綁定分配哪些密鑰 等信息。
2,然后根據配對信息進行一種鏈路認證(以前的靜態密碼,動態密碼,這個輸入密碼的過程就是認證的一種方式),最后鏈路加密
3,最后就是鏈路加密。
對於設置了綁定位的配對:區別就是多了一個在加密鏈路上分發密鑰的過程。
1,鏈路信息的交換,主要就是兩邊設備的i/o能力,設置綁定標志,鏈路是否需要MITM保護,如果設置綁定分配哪些密鑰 等信息。
2,然后根據配對信息進行一種鏈路認證(以前的靜態密碼,動態密碼,這個輸入密碼的過程就是認證的一種方式),最后鏈路加密
3,進行鏈路加密。
4,最后進行主設備和從設備的密鑰分配。
因為配對的過程比較耗時,每次需要加密鏈路都去執行配對的話就比較麻煩。
所以就有了綁定這個過程,如果設置了綁定,配對后就存儲里一些加密密鑰。下次如果再需要加密鏈路時,就可以使用綁定過程中分發的密鑰了(對於鏈路加密來說,並不是直接使用分發的密鑰而是用分發密鑰生成會話密鑰然后再進行鏈路加密,了解下就行了,對於使用來說,底層細節不需要在意,就算在意你也看不到代碼,如果真想細究直接看藍牙規范)。而不要在執行耗時的配對過程。
回到這講的主要目的:實現手機每次連接上設備后,立刻出發配對並要求輸入密鑰的功能。
靜態密碼教程中提高過,對於配對其實有很多種觸發方式。
靜態密碼和動態隨機密碼教程中 使用的是 對某個特征值設置一個安全權限,當手機訪問它時,因為鏈路並未加密不符合安全要求,於是手機會收到 像是權限不足的錯誤返回,之后手機端就會執行配對請求從而使鏈路加密以符合安全要求。
不過對於這里的要求,上面的觸發方式就不符合要求了。因為這里要求的是每次連接后立刻進行配對和密鑰輸入。上面的情況卻是已經連接並發現服務並且執行某些操作后才行的。
這就需要其他觸發方式,配對的其他方式還有:
1主機直接發起配對請求。
2從機直接發安全請求,這時候如果曾經配對綁定過,那么手機會直接用之前配對綁定時保存的 長期密鑰(LTK) 來進行鏈路的加密工作。如果沒有那么手機就會執行配對過程。
對於這里要實現的 每次連接時都要觸發,第一種方式手機端直接發起配對請求,是最直接的。但是這里需要配對和密碼輸入無非是為了提高安全,例如防止別人可以隨便連接的情況。所以肯定不能靠手機端,本身就是為了防止被隨便連,所以肯定是需要在設備這邊做出限制。
所以采用第二種方式,即每次手機連接上設備后,設備發送安全請求,因為不使用綁定。所以手機端沒有保存過綁定信息,於是就會發送配對請求,從而啟動配對過程。
PS:這樣看似乎手機端直接發配對請求這個功能好像沒什么用。
但是考慮下面的情況,app自動掃描某些設備並連接連接(比如特定的設備名字,或者設備地址等),使用配對並且通過設置配對請求中的i/o能力讓手機端顯示配對碼,而設備端來輸入配對碼。這樣如果其他設備如果偽造設備名,或設備地址,即使連接上了。但是連接后手機端立刻直接發送配對請求,因為”別人”看不到你手機上的配對碼,所以配對也就失敗了,手機端就可以讓其斷開連接。
綜上所述,為實現 連接上后 立刻要求配對並輸入配對碼 的功能,我們要添加連接上后 發送 安全請求的代碼,以及判斷配對過程是否成功,如果不成功則斷開連接。 從而實現防止別人隨意連接的目的。所以我們需要做的步驟如下:
1:手機連接上后立刻 調用安全請求api sd_ble_gap_authenticate。
這樣手機收到后就會發送配對請求
2:回復手機的配對請求,設置不綁定。(這樣手機每次收到設備的安全請求就會發配對請求過來從而啟動配對)
3:之后的配對過程會自動進行。我們只需要根據收到的 BLE_GAP_EVT_AUTH_STATUS 事件,判斷其狀態是否是成功,來決定配對是不是成功了,從而決定斷不斷開鏈接。
為了方便我們在靜態密碼的基礎上,添加代碼。從而實現要求功能。這里為了方便沒看過靜態密碼教程的人來理解整體,依舊將靜態密碼需要的相關設置也寫出來。具體的細節看 靜態密碼教程。
首先定義一下相關參數
#define STATIC_PASSKEY "123456"
static ble_opt_t m_static_pin_option;
#define IO_CAPS BLE_GAP_IO_CAPS_DISPLAY_ONLY //只有顯示裝置
#define BOND 0 //不綁定
#define OOB 0
#define MITM 1
在gap_params_init函數最后添加靜態密碼的設置代碼
static 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);
}
手機發來配對請求后,設備需要回復,實現配對回復函數如下:
void resp_pair_request(){
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 = 16;
sec_params.min_key_size = 7;
sec_params.oob = BOND;
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);
}
最后 就是添加上面說的要做的三個步驟的代碼。
修改 main.c中on_ble_evt,添加紅色代碼部分
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;
// 1連接一建立就發送安全請求,從而促使手機發送配對請求過來
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_DISCONNECTED:
err_code = bsp_indication_set(BSP_INDICATE_IDLE);
APP_ERROR_CHECK(err_code);
m_conn_handle = BLE_CONN_HANDLE_INVALID;
break;
// 2回復配對請求
case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
printf("receive pair request\n");
resp_pair_request();
break;
// 3判斷配對是否成功,如果不成功斷開連接,從而阻止他人任意連接。
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{
sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
}
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;
}
}
最后梳理一下流程。
手機連接設備后,設備會立刻發送安全請求。因為手機和設備沒有綁定,所以手機收到設備發過來的安全請求后機會發送配對請求給設備。設備,繼而回復配對請求(沒有設置綁定標志),設備后續的配對過程由協議棧自動完成,並最終返回給上層配對完成事件。判斷配對是否成功,如果失敗就斷開連接,從而阻止他人隨意連接設備。
文字轉載自:http://blog.chinaunix.net/uid-28852942-id-5700019.html