关于配对绑定的一些原理内容这里不再重复介绍,看之前的几篇文档,静态密码,动态密码,连接时触发配对就可以了。

配对绑定的内容可能比较难懂,升入的学习需要去看规范,将前面的几篇相关文档看一遍实验一边再去看规范能更好理解相关理论。

配对绑定是一个完整的过程,只是绑定是可选的,绑定简单来说就是存储一个长期秘钥LTK,以方便以后加密。当然还分配了其他秘钥,这里不涉及。

绑定是在配对之后,要明确 所谓配对 目的就是加密链路,以让数据能加密传输,所以绑定肯定是在配对之后,因为绑定就是分发各种秘钥,所以肯定要加密传输不然被别人窃听到了,以后用 分发的秘钥 再加密链路就不安全了。

总之 配对的目的 就是单纯的加密链路,但是配对过程比较耗时(包括配对信息交换,用户输入配对码或带外传输配对码,协议层的配对确认交换和随机数交换以及确认验证,都没问题后才会生成链路加密秘钥来加密链路),如果为了数据始终都是加密传输而每次连接都去配对的话就比较麻烦,所以又定义了一个绑定过程,绑定过程是在 配对后链路加密的情况下 分发一个 LTK(其他秘钥这里不涉及),这个LTK就可以供以后直接加密链路,而不用进过繁琐的配对过程。

PS:其实LTK分配之后,每次重新连接时的加密并不是用LTK直接加密链路,而是双方交换一些信息(称为会话秘钥分散器),然后利用这些信息和LTK最终生成一个会话秘钥,真正的加密是用这个会话秘钥。

这里我实现一个 从机显示配对码,主机输入配对码的配对方式,配对码为随机的,从机的配对码从串口打印出来。

主机输入配对码这个配对方式由配对信息交换时是否存在MITM标志以及从机是否有显示装置决定,所以我们配对信息中需要设置MITM标志,以及将I/O能力设置为有显示。

绑定过程是否存在 取决于配对信息交换中是否设置了Bond标志,这里我们也要设置。

我们这里测试绑定时在绑定阶段只分发LTK,其他秘钥这里不涉及

配对绑定大致分为3个阶段:

1:配对信息的交换

2:生成STK(短期秘钥)加密链路

3:链路加密后就可以安全分发各种秘钥了。

大致的过程图如下所示

 

大部分的工作协议栈都做好了,上层要处理的就是设置一些 参数以及处理几个事件。

首先要处理 BLE_GAP_EVT_SEC_PARAMS_REQUEST 事件,当手机发来配对请求时就会收到这个事件。 需要调用 回复api回复配对参数。

简要代码如下。

case BLE_GAP_EVT_SEC_PARAMS_REQUEST:

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("receive pair req\r\n");

init_sec();

err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &g_pair_params, &keyset);

printf("err_code :%d\r\n",err_code);

break;

sd_ble_gap_sec_params_repl 的第三个参数g_pair_params参数就是要回复的配对绑定参数设置

具体设置如下

ble_gap_sec_params_t  g_pair_params;

void init_sec(void){

g_pair_params.bond = 1;

g_pair_params.io_caps = 0;

g_pair_params.oob = 0;

g_pair_params.mitm = 1;

g_pair_params.min_key_size = 7;

g_pair_params.max_key_size = 16;

g_pair_params.kdist_central.enc = 1;

g_pair_params.kdist_central.id = 0;

g_pair_params.kdist_central.sign = 0;

g_pair_params.kdist_periph.enc = 1;

g_pair_params.kdist_periph.id = 0;

g_pair_params.kdist_periph.sign = 0;

}

IO能力及设备的输入输出能力,有以下几个值

#define        BLE_GAP_IO_CAPS_DISPLAY_ONLY   0x00

#define        BLE_GAP_IO_CAPS_DISPLAY_YESNO   0x01

#define        BLE_GAP_IO_CAPS_KEYBOARD_ONLY   0x02

#define        BLE_GAP_IO_CAPS_NONE   0x03

#define        BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY   0x04

设置了MITM为1和io能力设置为0,这个组合表示配对过程中 设备会显示配对码,主机需要输入对应配对码。

Bond 设置为1表示需要绑定,则配对会存在绑定过程即LTK等秘钥的分发。

具体分发哪些秘钥也是可以控制,这里只说LTK,所以上面的设置中只设置了相互分发长期秘钥LTK,其他不需要设置

PS:之所以相互分发LTK是因为,如果手机本次作为主机连接了设备,设备作为从机,配对绑定后断开连接,当再次连接时如果手机依然是作为主机去连设备,那么加密时就需要  从机分发给手机的LTK。但是有的应用可能主从角色并不是固定的,下次可能 是设备作为主机去连手机那么 加密时 就需要上次绑定时 手机发给设备的LTK。 上面的情况我们设置了相互分发LTK,其实一般都是手机一直作为主机去连设备,这种情况我们只需要g_pair_params.kdist_periph.enc = 1;就可以了

既然是配对会存在分发秘钥过程,那么协议栈交换的秘钥存储在哪里以在绑定完成后返回给上层呢。

返回的秘钥就是存在 sd_ble_gap_sec_params_repl 的第四个参数keyset

设置如下,即我们需要自己创建变量来存储分发的秘钥,因为这只用了LTK,所以其他两个指针设置为NULL就行了。

ble_gap_enc_key_t my_enc_key;

ble_gap_enc_key_t my_enc_key_center;

ble_gap_sec_keyset_t keyset;

void init_keyset(void){

keyset.keys_periph.p_enc_key = &my_enc_key;

keyset.keys_periph.p_id_key = NULL;

keyset.keys_periph.p_sign_key = NULL;

keyset.keys_central.p_enc_key = &my_enc_key_center;

keyset.keys_central.p_id_key = NULL;

keyset.keys_central.p_sign_key = NULL;

}

当 sd_ble_gap_sec_params_repl按如上设置回复后,设备这边就会显示配对码需要让手机输入,因为没有显示 屏这里通过串口打印出来。

上层会收到协议栈的BLE_GAP_EVT_PASSKEY_DISPLAY提交上来的显示事件。直接将配对码打印出来

case BLE_GAP_EVT_PASSKEY_DISPLAY:

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("passkey: ");

for ( int i = 0; i < 6; i++ ){

printf("%c",p_ble_evt->evt.gap_evt.params.passkey_display.passkey[i]);

}

printf("\r\n");

break;

这之后基本都是协议栈内部进行了,当绑定完成后上层会收到协议栈的BLE_GAP_EVT_AUTH_STATUS事件表示完成了秘钥的分发。

我们在收到这个事件后打印相关的秘钥信息

case BLE_GAP_EVT_AUTH_STATUS:

flag = 1;

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("keyset dispatch done\r\n");

printf("LTK :");

for(int i = 0; i < my_enc_key.enc_info.ltk_len; i++){

printf("%x",my_enc_key.enc_info.ltk[i]);

}

printf("   AUTH: %d ",my_enc_key.enc_info.auth);

printf("   LTK length: %d \r\n",my_enc_key.enc_info.ltk_len);

printf("EDIV: %x ",my_enc_key.master_id.ediv);

printf("rand:");

for(int i = 0; i < 8; i++){

printf("%x",my_enc_key.master_id.rand[i]);

}

printf("\r\n");

break;

ps: EDIV 和RAND是和LTK一起发送的,你可以将其看做是LTK的标示,当手机以后请求用LTK来进行加密时就会发送给从机EDIV和RAND让其确定要使用的LTK

到这里配对绑定过程就结束了,前面说过绑定的目的是为了下次链接需要安全链路时不再进行繁琐的配对过程,所以一般手机和一个设备绑定过后,当下次再连接时都会直接用以前绑定时的LTK来发起加密请求。

我们在收到这个信息后打印了加密请求的一些信息,打印了我们回复的LTK和请求的EDIV,RAND看是不是和上面绑定过程时分配的一样。

case BLE_GAP_EVT_SEC_INFO_REQUEST:

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("enc need: %d  id need:%d   sign need:%d\r\n",

p_ble_evt->evt.gap_evt.params.sec_info_request.enc_info,

p_ble_evt->evt.gap_evt.params.sec_info_request.id_info, 
                                            p_ble_evt->evt.gap_evt.params.sec_info_request.sign_info);

printf("RSP:  LTK :");

for(int i = 0; i < my_enc_key.enc_info.ltk_len; i++){

printf("%x",my_enc_key.enc_info.ltk[i]);

}

printf("\r\nEDIV :%x  RANDOM:",

p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.ediv);

for(int i = 0; i< 8; i++){

printf("%x",

p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.rand[i]);

}

err_code=sd_ble_gap_sec_info_reply(m_conn_handle,  &(my_enc_key.enc_info), NULL, NULL);

printf("\r\nencryption rsp err_code:%d\r\n",err_code);

break;

关于如何让手机发起配对,我们还是设置CCCD的访问安全要求 来实现在点击notify时,设备会返回安全不足,然后手机便会发起配对。具体可以看之前的

静态/动态配对码 的文章。

程序运行后如下图所示,连接上后,点击notify便会触发配对。

首先收到配对请求

之后协议栈会上传配对码,通过串口显示,手机端输入该配对码。

最后配对完成,打印了LTK和EDIV,RAND.

然后断开连接,再次连接设备,可以看到手机这次直接就发加密请求过来了。请求中的EDIV和RAND也和之前绑定时分配的一样。

最后贴一下相关代码,代码都是关于几个事件的处理,我全部都添加在了on_ble_evt这个事件处理函数中。

ble_gap_sec_params_t  g_pair_params;

void init_sec(void){

g_pair_params.bond = 1;

g_pair_params.io_caps = 0;

g_pair_params.oob = 0;

g_pair_params.mitm = 1;

g_pair_params.min_key_size = 7;

g_pair_params.max_key_size = 16;

g_pair_params.kdist_central.enc = 1;

g_pair_params.kdist_central.id = 0;

g_pair_params.kdist_central.sign = 0;

g_pair_params.kdist_periph.enc = 1;

g_pair_params.kdist_periph.id = 0;

g_pair_params.kdist_periph.sign = 0;

}

ble_gap_sec_keyset_t  sec_keyset;

ble_gap_conn_sec_mode_t sec_mode;

ble_gap_enc_key_t my_enc_key;

ble_gap_enc_key_t my_enc_key_center;

ble_gap_sec_keyset_t keyset;

void init_keyset(void){

keyset.keys_periph.p_enc_key = &my_enc_key;

keyset.keys_periph.p_id_key = NULL;

keyset.keys_periph.p_sign_key = NULL;

keyset.keys_central.p_enc_key = &my_enc_key_center;

keyset.keys_central.p_id_key = NULL;

keyset.keys_central.p_sign_key = NULL;

}

uint8_t step_count = 0;

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;

init_keyset();

printf("\r\nconnected\r\n");

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;

printf("\r\ndisconnected");

break;

case BLE_GAP_EVT_SEC_PARAMS_REQUEST:

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("receive pair req\r\n");

init_sec();

err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_SUCCESS, &g_pair_params, &keyset);

printf("err_code :%d\r\n",err_code);

// APP_ERROR_CHECK(err_code);

break;

case BLE_GAP_EVT_PASSKEY_DISPLAY:

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("passkey: ");

for ( int i = 0; i < 6; i++ ){

printf("%c",p_ble_evt->evt.gap_evt.params.passkey_display.passkey[i]);

}

printf("\r\n");

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

printf("\r\n\r\n step : %d\r\n",++step_count);

printf("keyset dispatch done\r\n");

printf("LTK :");

for(int i = 0; i < my_enc_key.enc_info.ltk_len; i++){

printf("%x",my_enc_key.enc_info.ltk[i]);

}

printf("   AUTH: %d ",my_enc_key.enc_info.auth);

printf("   LTK length: %d \r\n",my_enc_key.enc_info.ltk_len);

printf("EDIV: %x ",my_enc_key.master_id.ediv);

printf("rand:");

for(int i = 0; i < 8; i++){

printf("%x",my_enc_key.master_id.rand[i]);

}

printf("\r\n");

break;

case BLE_GAP_EVT_SEC_INFO_REQUEST:

printf("\r\nenc need: %d  id need:%d   sign need:%d\r\n",p_ble_evt->evt.gap_evt.params.sec_info_request.enc_info,

p_ble_evt->evt.gap_evt.params.sec_info_request.id_info,

p_ble_evt->evt.gap_evt.params.sec_info_request.sign_info);

printf("RSP:  LTK :");

for(int i = 0; i < my_enc_key.enc_info.ltk_len; i++){

printf("%x",my_enc_key.enc_info.ltk[i]);

}

printf("\r\nEDIV :%x  RANDOM:",p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.ediv);

for(int i = 0; i< 8; i++){

printf("%x",p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.rand[i]);

}

err_code = sd_ble_gap_sec_info_reply(m_conn_handle, &(my_enc_key.enc_info), NULL, NULL);

printf("\r\nencryption rsp err_code:%d\r\n",err_code);

break;

default:

// No implementation needed.

break;

}

}

nrf51822-配对绑定实现过程相关推荐

  1. Android——BLE配对绑定实现

    蓝牙配对绑定原理不再赘述了,终端的实现可以参照文章后的参考链接,本处主要记录总结下Android端的配对绑定实现过程. 1.动态注册系统广播,接收蓝牙配对请求 intentFilter = new I ...

  2. ble连接过程建立_BLE配对绑定过程梳理

    (一)BLE SM为以下三种procedure提供支持: 1. Pairing; 2. Bondig; 3. Encryption Re-establishment; 区别于传统蓝牙的配对过程,BLE ...

  3. BLE配对绑定过程梳理

    (一)BLE SM为以下三种procedure提供支持: 1. Pairing; 2. Bondig; 3. Encryption Re-establishment; 区别于传统蓝牙的配对过程,BLE ...

  4. nRF51822 配对之device_manager_init 调用,以及保证 用户数据存储 的Flash 操作不与device manager 模块冲突...

    昨天 遇到了一个烦心的问题,被老外客户怼了两句,恼火,很想发火,发现英文不够用,算了,就不跟直肠的鬼佬一般见识.说正事. 最近的一个nRF51822+MT2503 钱包防丢项目,准备接近量产了.昨天做 ...

  5. CC2640R2F之配对绑定与解除绑定篇

    蓝牙协议栈:simplelink_cc2640r2_sdk_1_40_00_45 IAR版本:IAR for ARM 8.11.3 开发板:CC2640R2F 蓝牙版本:BLE4.2 配对模式:Pas ...

  6. 一篇文章带你解读蓝牙配对绑定

    BLE配对绑定解读 什么是低功耗蓝牙配对?什么又是绑定?配对和绑定有什么区别?配对有什么好处?如何删除绑定信息?如何确定配对的安全等级?just work的配对一定就不安全吗?如何开发自己的配对应用? ...

  7. 0网卡开启_中标麒麟Linux v7系统下设置双网卡bond或team绑定详细过程

    中标麒麟Linux v7系统下设置双网卡bond或team绑定详细过程.所谓bond,就是把多个物理网卡绑定成一个逻辑网卡,使用同一个IP工作,在增加带宽的同时也可以提高冗余性,一般使用较多的就是来提 ...

  8. android ble配对绑定,Android蓝牙(一)搜索配对和绑定

    蓝牙技术在智能硬件方面有很多用武之地,今天我就为大家分享一下蓝牙在Android系统下的使用方法技巧,并实现一下两个终端间数据的传输. 蓝牙(Bluetooth)是一种短距离的无线通信技术标准,蓝牙协 ...

  9. 关于阿里云服务器ECS与域名的绑定详细过程介绍

    本文简单的介绍下阿里云的虚拟服务器ECS与域名绑定 条件:阿里云服务器+已实名认证域名 域名解析 1进入阿里云管理控制台 --云解析DNS,选择需要解析的域名--解析 2添加两条解析,打码的地方添自己 ...

最新文章

  1. phpnow 安装apache失败_装PHPnow 提示 apache 安装失败 的解决方法
  2. mysql必备技能_Mysql常用技能(1)
  3. iframe中的奇怪现象
  4. Slave: received end packet from server, apparent master shutdown
  5. 线性代数学习资料汇编
  6. 超细粒度分析XLNet中神奇的Attention Mask
  7. springboot + vue_Springboot+VUE---实现简单的websocket
  8. Oracle 12C 新特性之扩展数据类型(extended data type)
  9. Python urllib爬取百度首页
  10. Ubuntu 16.04 LTS Final Beta about JAVA
  11. 同工作组计算机连接用户名和密码错误,登录失败: 未知的用户名或错误密码
  12. matlab正弦波占空比怎么调,matlab实现可调节占空比的方波
  13. c语言将时速转换成配速,配速和时速换算(配速时速换算)
  14. 部署并安装Discuz
  15. 号称中国第一美女!!
  16. React基础语法总结
  17. Unity 鼠标拖动UI
  18. negroni-gzip源码分析
  19. GameFramework源码学习(一)
  20. CAN总线控制器SJA1000的使用

热门文章

  1. Java 8系列之重构和定制收集器
  2. 你应该如何正确健壮后端服务?
  3. SaaS颠覆传统软件到底是不是个伪命题?
  4. Visual Studio Code高效开发----自动保存设置方法
  5. 网络:HTTP1.1和HTTP2区别
  6. 印象笔记html预览,7 个方法,把印象笔记打造成轻量级笔记工具
  7. python3.8安装pygame_Python3.8安装Pygame教程步骤详解
  8. 后处理编辑修改_NX后处理打开报错处理方法
  9. ML之FE:利用FE特征工程(单个特征及其与标签关系的可视化)对RentListingInquries(Kaggle竞赛)数据集实现房屋感兴趣程度的多分类预测
  10. Python语言学习之图表可视化:python语言中可视化工具包的简介、安装、使用方法、经典案例之详细攻略