nrf51822靜態密碼設置教程

1 前言

    本文介紹配對的一些相關理論知識,並且介紹如何實現”靜態密碼”的設定。這裏準確的說法應該是叫配對碼,而不是密碼。輸入這個這個配對碼是配對過程中可選的一部分介紹如何設置靜態密碼前先介紹一下配對的相關知識(後面都直接叫密碼,而不是配對碼)起初未提供安全性的兩個設備如果希望做一些需要安全性的工作,就必須先配對。配對涉及兩個設備的身份認證,鏈路加密。如果配對時設置了綁定位,隨後還會有一個祕鑰分配。分配的祕鑰用戶可以存儲在flash中這樣兩個設備再第二次重連時的安全啓動會更快。而不需要像第一次一樣需要再啓動整個配對過程。配對的第一個過程首先是配對信息的交換,這些信息用於確定認證方式,以及後續是否需要分配密鑰以及分配哪些密鑰。

2 配對理論知識

交換的信息包括:

兩端設備的輸入輸出能力如:是否有顯示屏,鍵盤等。

是否需要綁定(如果設置了綁定位配對的)。

是否需要MITM,是否使用OOB等

這些信息會讓BLE協議棧確定一種認證方式:

比如:

1:如果兩端設備的輸入輸出能力有限,比如都沒有鍵盤和顯示器,認證方式就是just work,這其實就是沒有認證,

2:如果兩端設備一個有顯示頻,而另一個有鍵盤,而配對中設置了MITM保護。那麼認證方式就是passkey entery。
一端會顯示一個配對碼,另一需要輸入這個配對碼。之後的配對才能正確進行下去。

3:如果設置了OOB,那麼這個配對碼就是通過另外的通信方式(如NFC)來發送的,而不是像上面一樣一端顯示一端輸入。

nrf51822中設置如下:

#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. */
/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities
 * @{ */
#define BLE_GAP_IO_CAPS_DISPLAY_ONLY      0x00   /**< Display Only. */
#define BLE_GAP_IO_CAPS_DISPLAY_YESNO     0x01   /**< Display and Yes/No entry. */
#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY     0x02   /**< Keyboard Only. */
#define BLE_GAP_IO_CAPS_NONE              0x03   /**< No I/O capabilities. */
#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY  0x04   /**< Keyboard and Display. */
/**@} */

本文的密碼設置就是第二種情況。顯示的密碼是可以隨機的也可以是靜態的。由於設備並沒有顯示器。但是我們仍然可以設置輸入輸出能力爲有顯示器,因爲我們使用的是靜態密碼。

配對的過程不僅只是輸入配對碼這樣,後續還會根據輸入的配對碼,以及兩端設備交換的隨機數來生成鏈路密鑰來加密鏈路以及分配後續的長期密鑰,身份解析密鑰等需要的密鑰配對相關的理論比較多,上面的描述只是一個大概的過程。配對過程的詳細介紹在藍牙規範的 安全章節中。

根據上面的理論描述,我們來總結一下:

我們需要的輸入“密碼”這個功能,其實是配對過程中的一部分。而配對過程又是需要首先交換配對信息,然後協議棧會根據交換的信息才決定是否有輸入密碼這一過程。

那麼我們要做的有如下幾步:

1: 首先設置要輸入的靜態密碼
       2: 設置配對時會交換的信息:根據上面的介紹如果我們需要手機輸入密碼,那麼配對時就要設置只具有顯示器(這樣就會是一端顯示,
一端輸入,雖然我們真的沒顯示器,但是設置的是靜態密碼所以也是可以的),設置需要MITM攻擊保護。

3:觸發配對。


給一個本來不使用passkey的例子增加該功能,需要完成5件事情:

1. 設置ble_gap_sec_params_t 結構中的mitm爲1;

2. 設置ble_gap_sec_params_t 結構中的io_caps(輸入輸出功能)變量爲display 或者keyboard;

   具體可以參考藍牙核心文檔中的table2.4  該表位於第三卷,H部分,2.3.5.1節。

3. 根據第二步驟的選擇。

a) 如果選擇了keyboard,當接收到BLE_GAP_EVT_AUTH_KEY_REQUEST 後需要使用sd_ble_gap_auth_key_reply()函數把認證密碼回覆給你的用戶;

b)如果選擇了display,在用戶終端顯示密碼輸入框,便於用戶輸入密碼。

4.  認證密碼可以用戶指定或者隨機生成,默認是隨機生成,需要指定,

a)在main.c(gap_params_init()在的文件) 增加ble_opt_t 全局變量

static ble_opt_t   m_static_pin_option;/**< Pointer to the struct containing static pin option. */

b)gap_params_init()函數的最後添加:

uint8_t passkey[] = STATIC_PASSKEY;
m_static_pin_option.gap.passkey.p_passkey = passkey;
err_code =  sd_ble_opt_set(BLE_GAP_OPT_PASSKEY, &m_static_pin_option);
APP_ERROR_CHECK(err_code);

其中 STATIC_PASSKEY 就是認證密碼。

5. 爲需要passkey才能訪問服務設置相應權限,如下面藍色加粗部分。

<span style="color:#373737;">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);
</span><span style="color:#3333ff;"><strong>    BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&cccd_md.write_perm);</strong></span><span style="color:#373737;">

    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));


</span><span style="color:#000099;"><strong>    BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.write_perm);</strong></span><span style="color:#373737;">
    
    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] */
}</span>

3 nrf51822 配對過程及設置靜態密碼

//首先定義一下靜態密碼,配對密碼只能是 6-digit ASCII string

#defineSTATIC_PASSKEY "123456" /**< Static pin. */

//改結構體中可以設置靜態密碼

staticble_opt_t m_static_pin_option;

定義了這兩個參數後,我們需要設置一下靜態密碼,設置的操作需要在協議棧初始化之後 所以我們將設置密碼操作放在 gap_params_init()函數的最後

如下:

static void gap_params_init(void)
{
    //前面都是設置一些設備名以及一些後續需要協商的連接參數
    //詳細解釋在 串口透傳剖析 中有說明

<span style="white-space:pre">	</span>uint32_t err_code;
<span style="white-space:pre">	</span>ble_gap_conn_params_tgap_conn_params;
<span style="white-space:pre">	</span>ble_gap_conn_sec_mode_t sec_mode;

<span style="white-space:pre">	</span>BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
<span style="white-space:pre">	</span>err_code=sd_ble_gap_device_name_set(&sec_mode,
<span style="white-space:pre">	</span>(constuint8_t*DEVICE_NAME,trlen(DEVICE_NAME));
<span style="white-space:pre">	</span>APP_ERROR_CHECK(err_code);

<span style="white-space:pre">	</span>memset(&gap_conn_params, 0,sizeof(gap_conn_params));

<span style="white-space:pre">	</span>gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
<span style="white-space:pre">	</span>gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
<span style="white-space:pre">	</span>gap_conn_params.slave_latency= SLAVE_LATENCY;
<span style="white-space:pre">	</span>gap_conn_params.conn_sup_timeout= CONN_SUP_TIMEOUT;
<span style="white-space:pre">	</span>err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
<span style="white-space:pre">	</span>APP_ERROR_CHECK(err_code);
//以下是設置靜態密碼操作
<span style="white-space:pre">	</span>uint8_tpasskey[] = STATIC_PASSKEY; m_static_pin_option.gap_opt.passkey.p_passkey= passkey;
//該系統調用執行密碼的設置操作。
<span style="white-space:pre">	</span>err_code=sd_ble_opt_set(BLE_GAP_OPT_PASSKEY,&m_static_pin_option)
<span style="white-space:pre">	</span>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


定義了宏之後我們需要在設置參數,寫一個如下的函數。

m_sec_params 是一個全局變量

ble_gap_sec_params_t m_sec_params;

static 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;
}

將該函數放在 main函數的初始化流程中的conn_params_init(); 函數之後。

設置的這個全局變量會在配對啓動後的信息交換中使用(因爲其內部值就是要交換的信息)。

到這裏我們設置完了配對啓動後會交換的信息。但是怎麼把這個信息給對端設備呢? 先看完最後一步的觸發配對的問題,再來解決將配對信息發給對端設備的問題。


最後一步觸發配對:

配對的觸發有以下幾種情況:

1:主機直接發起。

2:從機發起安全請求,如果之前綁定過,那麼主機會直接用用保存的LTK加密鏈路,如果沒有那麼主機會發起配對請求。

3:BLE中的有一個安全模式的概念。當某個屬性被設置爲需要認證的加密鏈路訪問時,那麼當在主機訪問從機的屬性器時,如果鏈路是不安全的就會返回錯誤,然後主機會發起配對請求從而實現安全要求。

我們採用的就是第三種 被動等待主機觸發的方式,那麼首先要做的就是將一些屬性設置爲需要安全的鏈路才能訪問,那麼手機在訪問時就會觸發配對過程了。

因爲手機端使能notify是需要寫CCCD的,所以我們將具有notify 性質RX 特徵值的 cccd(客戶端配置描述符)設置爲需要認證和加密的安全鏈路。那麼當手連上板子後 點擊rx特徵值的notify 按鈕後主機會發一個 寫命令寫板子上的rx特徵值的cccd,因爲初試鏈路是不完全的,那麼這時手機就會返回寫出錯,然後啓動配對過程。


設置如下:

在添加RX特徵值的函數中做如下的簡單就可以了。


這裏只截取部分代碼:

static uint32_t rx_char_add(ble_nus_t * p_nus, constble_nus_init_t * p_nus_init)

{

/**@snippet [Addingproprietary characteristic to S110 SoftDevice] */

ble_gatts_char_md_tchar_md;

ble_gatts_attr_md_tcccd_md;

ble_gatts_attr_t attr_char_value;

ble_uuid_t ble_uuid;

ble_gatts_attr_md_tattr_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);

//將上面的一行修改成下面這行

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));

··············

··············

············

}

這樣當對端設備(如手機)使能開發板的上rx特徵值的notify功能時,就會因爲沒有寫權限而觸發配對,手機會發來配對請求,然後板子回覆配對信息,怎麼回覆? 這就是第二步中最後留下的問題。如何將配對信息交給對端設備(手機)。


當手機發來配對請求時,這對板子來說是一個事件,即配對事件。最終由dispatch派發函數交給各個服務或模塊的事件處理函數。那麼我們要做的就是在收到這個配對請求事件後回覆第二步中設置的配對

信息就可以了。在main.c 文件中的的on_ble_evt做如下修改

staticvoidon_ble_evt(ble_evt_t * p_ble_evt)

{

uint32_terr_code;

switch(p_ble_evt->header.evt_id)

{

caseBLE_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;

break;


caseBLE_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:

//註釋掉原本的不支持配對的函數,改爲如下的配對回複函數

//err_code= sd_ble_gap_sec_params_reply(m_conn_handle,

//BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);

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_GATTS_EVT_SYS_ATTR_MISSING:

// No system attributes have beenstored.

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;

}

}

到這裏所有需要配置的都設置完了。程序運行後。手機連接上板子,然後訪問rx特徵值。因爲該特徵值是用來將板子數據通過Notify方式傳給手機的,那麼首先要點擊手機上的notify按鈕去使能板子的notify功能。當我們點擊該按鈕時就會彈出輸入密碼的配對框。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章