【BLE】CC2541之配对与绑定

本篇博文最后修改时间:2017年01月06日,11:06。


一、简介

本文以SimpleBLEPeripheral工程为例,介绍配对与绑定。


二、实验平台

协议栈版本:BLE-CC254x-1.4.0

编译软件: IAR 8.20.2

硬件平台: Smart RF开发板(主芯片CC2541)、USB Dongle

手机平台: 红米1S

安卓系统: Android 4.3

APP: BLE Device Monitor


版权声明

博主:甜甜的大香瓜

声明:喝水不忘挖井人,转载请注明出处。

原文地址:http://blog.csdn.NET/feilusia

联系方式:[email protected]

香瓜BLE之CC2541群:127442605

香瓜BLE之CC2640群:557278427

香瓜BLE之Android群:541462902

香瓜单片机之STM8/STM32群:164311667
甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i

四、 实验前提
1、在进行本文步骤前,请先 阅读 以下博文:
暂无

2、在进行本文步骤前,请先 实现以下博文:
暂无


五、基础知识

1、什么是配对与绑定?

答:

配对——主从机连接的密码配对过程。

绑定——连接一次后就一直绑定着不需要再输入密码。


2、配对与绑定过程是主从机中的哪一端发起的?

答:配对模式配置为“GAPBOND_PAIRING_MODE_INITIATE”的一端发起的,可以是主机,也可以是从机。


3、配对与绑定发生在什么阶段?

答:早期的蓝牙配对与绑定发生在连接之前,BLE的配对与绑定则发生在连接之后。


4、配对与绑定的过程在连接之后,是否会在连接之后、配对之前的阶段造成数据泄露?

答:是的,可能导致数据泄露。

原因是连接之后,有的APP会弹窗配对并要求配对正确方可操作数据,而有的APP虽会弹窗但允许置之不理直接操作数据(一段时间没有配对成功,从机会认为配对超时而断开,主机APP可在这段超时时间内窃取从机数据)。

解决办法:将特征值在属性表中的属性设置为“加密读”或“加密写”,也就是改成“GATT_PERMIT_AUTHEN_READ”或“GATT_PERMIT_AUTHEN_WRITE”。


六、实验步骤

1、添加一个绑定与否的状态变量(simpleBLEPeripheral.c)

typedef enum  
{  
  GUA_PAIRSTATUS_PAIRED = 0,  
  GUA_PAIRSTATUS_NO_PAIRED,  
}GUA_PAIRSTATUS;  
static GUA_PAIRSTATUS gGUA_PairStatus = GUA_PAIRSTATUS_NO_PAIRED;       //配对状态,默认是没配对

2、修改绑定初始化 (simpleBLEPeripheral.c的SimpleBLEPeripheral_Init函数中)

  // Setup the GAP Bond Manager
  {
    uint32 passkey = 0; // passkey "000000"
    //uint8 pairMode = GAPBOND_PAIRING_MODE_WAIT_FOR_REQ;
    uint8 pairMode = GAPBOND_PAIRING_MODE_INITIATE;
    uint8 mitm = TRUE;
    uint8 ioCap = GAPBOND_IO_CAP_DISPLAY_ONLY;
    uint8 bonding = TRUE;
    GAPBondMgr_SetParameter( GAPBOND_DEFAULT_PASSCODE, sizeof ( uint32 ), &passkey );
    GAPBondMgr_SetParameter( GAPBOND_PAIRING_MODE, sizeof ( uint8 ), &pairMode );
    GAPBondMgr_SetParameter( GAPBOND_MITM_PROTECTION, sizeof ( uint8 ), &mitm );
    GAPBondMgr_SetParameter( GAPBOND_IO_CAPABILITIES, sizeof ( uint8 ), &ioCap );
    GAPBondMgr_SetParameter( GAPBOND_BONDING_ENABLED, sizeof ( uint8 ), &bonding );
  }
注:

1)GAPBOND_PAIRING_MODE_WAIT_FOR_REQ

这个宏是表示等待对方发起配对请求的模式,如果主从机都是这种模式,则双方都不会发起配对请求。

因此主从机的其中一方必须要配置成GAPBOND_PAIRING_MODE_INITIATE方可进行配对。

从机中往往有机密数据,因此从机端需要配置成GAPBOND_PAIRING_MODE_INITIATE,否则如果配对请求的主动权交予主机,主机一旦不发起请求,那也就无配对过程,导致从机的数据公之于众了。


2)GAPBOND_IO_CAP_DISPLAY_ONLY

这个宏是只显示密码,将密码显示在LCD上给主机看,主机也就知道密码了。

如果设备有按键可以输入密码,也可以选择GAPBOND_IO_CAP_KEYBOARD_ONLY。


3、注册回调函数

1)注册回调函数(替换simpleBLEPeripheral.c中的simpleBLEPeripheral_BondMgrCBs )

//配对与绑定的回调函数管理  
static gapBondCBs_t simpleBLEPeripheral_BondMgrCBs =  
{  
  GUA_ProcessPasscodeCB,                        //密码回调  
  GUA_ProcessPairStateCB                        //绑定状态回调  
};  

2)定义密码回调函数和配对状态回调函数

定义密码回调函数和配对状态回调函数(simpleBLEPeripheral.c中

//******************************************************************************                  
//name:             GUA_ProcessPasscodeCB                 
//introduce:        密码回调函数               
//parameter:        deviceAddr:设备地址       
//                  connectionHandle:连接句柄 
//                  uiInputs:
//                  uiOutputs:
//return:           none              
//author:           甜甜的大香瓜                       
//email:            [email protected]           
//QQ group          香瓜BLE之CC2541(127442605)                        
//changetime:       2016.12.13                        
//******************************************************************************                  
static void GUA_ProcessPasscodeCB(uint8 *deviceAddr, uint16 connectionHandle, uint8 uiInputs, uint8 uiOutputs)  
{  
  uint32 passcode;  
  uint8 str[7];  
  
  //设置密码  
  #if 0  
    LL_Rand(((uint8 *) &passcode), sizeof( uint32 ));  
    passcode %= 1000000;  
  #else  
    passcode = 456890;          
  #endif  
  
  //在LCD上显示  
  if(uiOutputs != 0)  
  {  
    HalLcdWriteString("Passcode:",  HAL_LCD_LINE_1);  
    HalLcdWriteString((char *)_ltoa(passcode, str, 10), HAL_LCD_LINE_2);  
  }  
    
  //发送密码响应给主机  
  GAPBondMgr_PasscodeRsp(connectionHandle, SUCCESS, passcode);  
}  

//******************************************************************************                  
//name:             GUA_ProcessPairStateCB                 
//introduce:        配对状态回调函数               
//parameter:        connectionHandle:连接句柄       
//                  state:当前配对与绑定的执行状态
//                  status:当前配对的状态
//return:           none              
//author:           甜甜的大香瓜                       
//email:            [email protected]           
//QQ group          香瓜BLE之CC2541(127442605)                        
//changetime:       2016.12.13                        
//****************************************************************************** 
static void GUA_ProcessPairStateCB(uint16 connHandle, uint8 state, uint8 status)  
{  
  //主机发起连接,会进入开始配对状态  
  if(state == GAPBOND_PAIRING_STATE_STARTED)  
  {  
    HalLcdWriteString("Pairing started", HAL_LCD_LINE_1);  
    gGUA_PairStatus = GUA_PAIRSTATUS_NO_PAIRED;  
  }  
    
  //当主机提交密码后,会进入配对完成状态    
  else if(state == GAPBOND_PAIRING_STATE_COMPLETE)  
  {  
    //配对成功  
    if(status == SUCCESS)      
    {  
      HalLcdWriteString("Pairing success", HAL_LCD_LINE_1);  
      gGUA_PairStatus = GUA_PAIRSTATUS_PAIRED;  
    }  
      
    //已配对过  
    else if(status == SMP_PAIRING_FAILED_UNSPECIFIED)  
    {       
      HalLcdWriteString("Paired device", HAL_LCD_LINE_1);  
      gGUA_PairStatus = GUA_PAIRSTATUS_PAIRED;  
    }  
      
    //配对失败  
    else  
    {  
      HalLcdWriteStringValue("Pairing fail", status, 10, HAL_LCD_LINE_1);  
      gGUA_PairStatus = GUA_PAIRSTATUS_NO_PAIRED;  
    }  
      
    //配对失败则断开连接  
    if(gGUA_PairStatus == GUA_PAIRSTATUS_NO_PAIRED)  
    {  
      GAPRole_TerminateConnection();  
    }  
  }  
  else if (state == GAPBOND_PAIRING_STATE_BONDED)  
  {  
    if (status == SUCCESS)  
    {  
      HalLcdWriteString("Bonding success", HAL_LCD_LINE_1);  
    }  
  }  
}  
注:

密码可以选择固定的456890方式,也可以选择随机函数产生的随机数。

以上两个函数,第一次连接时的进入先后顺序为:

ProcessPairStateCB——GAPBOND_PAIRING_STATE_STARTED(0x00)

ProcessPasscodeCB

ProcessPairStateCB——GAPBOND_PAIRING_STATE_COMPLETE(0x01)


绑定后再连接时的进入先后顺序为:

ProcessPairStateCB——GAPBOND_PAIRING_STATE_BONDED(0x02)

(其他步骤被忽略了)


声明密码回调函数和配对状态回调函数(simpleBLEPeripheral.c中

static void GUA_ProcessPasscodeCB(uint8 *deviceAddr, uint16 connectionHandle, uint8 uiInputs, uint8 uiOutputs);  
static void GUA_ProcessPairStateCB(uint16 connHandle, uint8 state, uint8 status);  

4、修改特征值char2在属性表中的属性(simpleGATTprofile.c的simpleProfileAttrTbl中)

      // Characteristic Value 2
      { 
        { ATT_BT_UUID_SIZE, simpleProfilechar2UUID },
        GATT_PERMIT_AUTHEN_READ,//GATT_PERMIT_READ, 
        0, 
        &simpleProfileChar2 
      },


5、在按键处理函数里增加清除绑定的功能

static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys )
{    
  VOID shift;  // Intentionally unreferenced parameter

  if ( keys & HAL_KEY_UP )
  {
	GAPBondMgr_SetParameter( GAPBOND_ERASE_ALLBONDS,0, NULL );  
  } 
}
无论是连接、还是非连接状态按下按键,都是作用在下一次连接上。
也就是在连接时按下按键并不会断开,下次想连接还会弹出输密码的框。


七、注意事项

手机可能缓存了之前的代码(在更新过CC2541的代码之后,都需要清除手机端的缓存!!!),因此要清除缓存,清除缓存的方法如下:

方法一:关闭app、关闭蓝牙总开关、打开蓝牙总开关、打开app。
方法二:手机重启。


八、实验结果

使用抓包软件Packet Sniffer,来观察手机app与CC2541之间的配对过程。

1、从机发起配对请求

【BLE】CC2541之配对与绑定_第1张图片


2、APP弹窗配对框时

(看截图左上角的蓝牙图标,实际上是配对请求的弹窗,香瓜在此先置之不理,试试读写特征值数据看看安全性)

1)读无加密的特征值char1

【BLE】CC2541之配对与绑定_第2张图片

【BLE】CC2541之配对与绑定_第3张图片

读未加密的特征值char1,成功返回01,说明连接之后、配对之前,该类属性的特征值也是不安全的。


2)读加密过的特征值char2

【BLE】CC2541之配对与绑定_第4张图片

【BLE】CC2541之配对与绑定_第5张图片

读加密了的特征值char2,返回错误状态字0x05,说明连接之后、配对之前,该类属性的特征值是安全的。


3)输错密码时

APP端会退回APP扫描设备的页面。

从机端发现APP发送过来的密码不对时,会断开连接。

【BLE】CC2541之配对与绑定_第6张图片


4)绑定成功之后,第二次连接

【BLE】CC2541之配对与绑定_第7张图片

绑定状态下,在安全请求之后,直接跳过了密码验证过程进行数据加密。


5)在开始加密请求之后,正式开始加密

【BLE】CC2541之配对与绑定_第8张图片


九、本文实验后仍存在的疑问

1、我的抓包出现大量错误通信,因此实验结果中有一些通信过程并没有真正抓到。此类错误暂不明原因,初步怀疑是我工程问题。期待知道大家的测试结果,是否跟我一样?

【BLE】CC2541之配对与绑定_第9张图片









你可能感兴趣的:(BLE-CC2541)