BLE蓝牙的连接和配对过程

一 连接

同一款手机,为什么跟某些设备可以连接成功,而跟另外一些设备又连接不成功?同一个设备,为什么跟某些手机可以建立连接,而跟另外一些手机又无法建立连接?同一个手机,同一个设备,为什么他们两者有时候连起来很快,有时候连起来又很慢?Master是什么?slave又是什么?什么又是Connection event和slave latency?希望这篇文章能帮助你回答上述问题。

1 BLE连接示例

假设我们有一台手机A(以安卓手机为例),一个设备B(设备名称:Nordic_HRM),如下所示,我们可以通过安卓设置菜单里面的蓝牙界面,让两者连接起来。

  1. 打开安卓设置菜单
  2. 选择“蓝牙”条目
  3. 打开蓝牙
  4. 等待系统搜索结果,不出意外的话,设备“Nordic_HRM”会出现在结果列表中
  5. 点击“Nordic_HRM”,手机将与此设备建立连接
    在这里插入图片描述
    上述即为大家直观感受到的“连接”,那么手机要与设备Nordic_HRM建立连接,具体包含哪些流程?他们为什么可以连接成功?下面给大家一一道来。

2 广播(advertising)

在手机跟设备B建立连接之前,设备B需要先进行广播,即设备B(Advertiser)不断发送如下广播信号,t为广播间隔。每发送一次广播包,我们称其为一次广播事件(advertising event),因此t也称为广播事件间隔。虽然图中广播事件是用一根线来表示的,但实际上广播事件是有一个持续时间的,蓝牙芯片只有在广播事件期间才打开射频模块,这个时候功耗比较高,其余时间蓝牙芯片都处于idle状态,因此平均功耗非常低,以Nordic nRF52810为例,每1秒钟发一次广播,平均功耗不到11uA。
在这里插入图片描述
上面只是一个概略图,按照蓝牙spec,实际上每一个广播事件包含三个广播包,即分别在37/38/39三个通道上同时广播相同的信息,即真正的广播事件是下面这个样子的。
在这里插入图片描述
设备B不断发送广播信号给手机(Observer),如果手机不开启扫描窗口,手机是收不到设备B的广播的,如下图所示,不仅手机要开启射频接收窗口,而且只有手机的射频接收窗口跟广播发送的发射窗口匹配成功,手机才能收到设备B的广播信号。由于这种匹配成功是一个概率事件,因此手机扫到设备B也是一个概率事件,也就是说,手机有时会很快扫到设备B,比如只需要一个广播事件,手机有时又会很慢才能扫到设备B,比如需要10个广播事件甚至更多。
在这里插入图片描述

3 建立连接(connection)

根据蓝牙spec规定,advertiser发送完一个广播包之后150us(T_IFS,该值称为帧间隔,是指在同一个信道上连续两帧之间的间隔详见: 蓝牙核心卷,Vol 6, Part B,4.1.1),advertiser必须开启一段时间的射频Rx窗口,以接收来自observer的数据包。Observer就可以在这段时间里给advertiser发送连接请求。如下图所示,手机在第三个广播事件的时候扫到了设备B,并发出了连接请求conn_req。
在这里插入图片描述
上图的交互流程比较粗略,为此我们引入下图,以详细描述连接建立过程。
在这里插入图片描述
图5:连接建立过程

注:图中M代表手机,S代表设备B,M->S表示手机将数据包发给设备B,即手机开启Tx窗口,设备B开启Rx窗口;S->M正好相反,表示设备B将数据包发给手机,即设备B开启Tx窗口,手机开启Rx窗口。

如图所示,手机在收到A1广播包ADV_IND后,以此为初始锚点(这个锚点不是连接的锚点),T_IFS后给Advertiser发送一个connection request命令,即A2数据包,告诉advertiser我将要过来连你,请做好准备。手机在发完连接请求之后会被强制延时1.25ms,紧接着是发送窗口偏移,和发送窗口。发送窗口偏移可以是0到连接间隔之间的任意值,但必须是1.25ms的整数倍。从发送窗口开始从设备必须打开RX窗口用来接收手机发过来的P1数据包。如果发送窗口结束还没有收到P1数据包,那么从设备终止监听,并会在下一个连接间隔后再次尝试。从P1开始使用数据通道。Advertiser根据connect_req命令信息做好接收准备,connect_req包含如下关键信息:

  • Transmit window offset,定义如图5所示
  • Transmit window size,定义如图5所示
  • connect_req数据包完整定义如下所示
    在这里插入图片描述
  • Initiator: 发起连接者的mac地址,BLE的MAC地址,随机地址的最高两位应该为11b
  • Advertiser: 广播者的地址mac地址
  • Access Address: 接入地址。LL层使用接入地址来区分当前发送的数据是广播包还是数据包,广播包接入地址固定为0x8E89BED6,数据包使用就是该值。
  • CRC initialization value: CRC初始值
  • transmitWindowSize: 发送窗口大小, 单位是1.25ms
  • transmitWindowOffset: 发送窗口偏移, 单位是1.25ms
  • connInterval: 连接间隔 单位是1.25ms
  • connSlaveLatency: 从设备延时,表示从设备可以跳过多少个连接事件。
  • connSupervisionTimeout: 监控超时。单位是10ms
  • Channel Map: 信道图,表示当前环境中哪一个信道可用,每一个bit表示一个信道1表示可用,0表示不可用。比如ff ff ff ff 1f(0x1fffffffff), 二进制为0001111111111111111111111111111111111111b
  • masterSCA: 00100b, 休眠时钟精度, 151 ppm to 250 ppm
  • hopIncrement: 110b, 跳频算法的hop值,6
    在这里插入图片描述

connect_req其实是在告诉advertiser,手机将在Transmit Window期间发送第一个同步包(P1)给你,请在这段时间里把你的射频接收窗口打开。设备B收到P1后,T_IFS时间后将给手机回复数据包P2。一旦手机收到数据包P2,连接即可认为建立成功。后续手机将以P1为锚点(原点),Connection Interval为周期,周期性地给设备B发送Packet,Packet除了充当数据传送功能,它还有如下两个非常重要的功能:

  1. 同步手机和设备的时钟,也就是说,设备每收到手机发来的一个包,都会把自己的时序原点重新设置,以跟手机同步。
  2. 告诉设备你现在可以传数据给我了。连接成功后,BLE通信将变成主从模式,因此把连接发起者(手机)称为Master或者Central,把被连接者(之前的Advertiser)称为Slave或者Peripheral。BLE通信之所以为主从模式,是因为Slave不能“随性”给Master发信息,它只有等到Master给它发了一个packet后,然后才能把自己的数据回传给Master。

对于主设备而言,连接请求一旦发出就认为连接已经建立。当从设备收到连接请求时,它也认为自己已经处在连接之中,连接已经创建,但不能证明完全确立。

4 连接失败

有如下几种典型的连接失败情况:

  1. 如图5所示,如果slave在transmit window期间没有收到master发过来的P1,那么连接将会失败。此时应该排查master那边的问题,看看master为什么没有在约定的时间把P1发出来。
  2. 如果master在transmit window期间把P1发出来了,也就是说master按照connect_req约定的时序把P1发出来了,但slave没有把P2回过去,那么连接也会失败。此时应该排查slave这边的问题,看一看slave为什么没有把P2回过去
  3. 如果master把P1发出来了,slave也把P2回过去了,此时主机还是报连接失败,这种情况有可能是master软件有问题,需要仔细排查master的软件。
  4. 还有一种比较常见的连接失败情况:空中射频干扰太大。此时应该找一个干净的环境,比如屏蔽室,排除干扰后再去测试连接是否正常。

5 连接事件

连接事件(Connection events)

连接成功后,master和slave在每一个connection interval开始的时候,都必须交互一次,即master给slave发一个包,slave再给master发一个包,整个交互过程称为一个connection event。蓝牙芯片只有在connection event期间才把射频模块打开,此时功耗比较高,其余时间蓝牙芯片都是处于idle状态的,因此蓝牙芯片平均功耗就非常低,以Nordic nRF52810为例,每1秒钟Master和Slave通信1次,平均功耗约为6微安左右。Master不可能时时刻刻都有数据发给slave,所以master大部分时候都是发的空包(empty packet)给slave。同样slave也不是时时刻刻都有数据给master,因此slave回复给master的包大部分时候也是空包。另外在一个connection event期间,master也可以发多个包给slave,以提高吞吐率。综上所述,连接成功后的通信时序图应该如下所示:

在这里插入图片描述
图7: 连接成功后的通信时序图(每个connection event只发一个包)

在这里插入图片描述
图9: 连接成功后的通信时序图( connection event可能发多个包)

在这里插入图片描述
图10:connection event细节图

6 从设备延时

从设备延时(Slave latency)

图10中出现了slave latency(slave latency = 2),那么什么叫slave latency?

如前所述,在每一个connection interval开始的时候,Master和Slave必须交互一次,哪怕两者之间交互的是empty packet(空包),但如果slave定义了slave latency,比如slave latency = 9,此时slave可以每9个connection interval才回复一次master,也就是说slave可以在前面8个connection interval期间一直睡眠,直到第9个connection interval到来之后,才回复一个packet给master,这样将大大节省slave的功耗,提高电池续航时间。当然如果slave有数据需要上报给master,它也可以不等到第9个connection interval才上报,直接像正常情况进行传输即可,这样既节省了功耗,又提高了数据传输的实时性。

7 GAP层角色总结

对上面提到的手机和设备B,在BLE通信过程中,随着时间的推移,他们的状态在发生变化,两者的关系也在发生变化,为此蓝牙spec根据不同的时间段或者状态给手机和设备B取不同的名字,即GAP层定义了如下角色:

  • advertiser。 发出广播的设备
  • observer或者scanner。可以扫描广播的设备
  • initiator。能发起连接的设备
  • master或者central。连接成功后的主设备,即主动发起packet的设备
  • slave或者peripheral。连接成功后的从设备,即被动回传packet的设备

图11通过时间把observer,initiator和central串起来了,其实这三个角色是相互独立的,也就是说一个设备可以只支持observer角色,而不支持initiator和central角色。同样,图11也把advertiser和peripheral串起来了,其实advertiser和peripheral也是相互独立的,即一个设备可以只作为advertiser角色,而不支持peripheral角色。
在这里插入图片描述
图11:GAP层角色

二 配对

区别于传统蓝牙的配对过程,BLE的配对过程发生在连接过程之后。

配对是一个三阶段的过程。前两个阶段是必须的,第三阶段是可选的。

  • 第一阶段:配对特征交换
  • 第二阶段:短期秘钥(STK)生成
  • 第三阶段: 传输特定秘钥分配

image

image

STK生成规则

  1. Just work: 没有加密 TK=0x00
  2. passkey entry: 密码输入如果 passkey 是 ‘019655’ TK的值就是0x00000000000000000000000000004CC7。
    将输入的值作为一个6位数的十进制,转换成16字节的十六进制。
  3. OOB: 带外的TK值是一个16字节的随机数,通过非BLE的方式传递给对端。

2.1 第一阶段

设备首先在配对特征交换阶段交换IO能力来决定在第二阶段使用下面哪种方法:

  • JustWorks:只工作
  • PasskeyEntry:输入密码
  • OutOfBand(OOB):带外

LE Legacy Pairing - Just Works
Just Works方式不能抵抗窃听者和中间人攻击,只有在配对过程时没有遭受攻击,后面加密的链路的数据传输才是可信的。安全级别很低。

LE Legacy Pairing - Passkey Entry
这种方式通过输入6位数字的方式来进行配对,生成STK。6位数是随机产生的在000000到999999之间的数值,这个数值相当于一个TK,比如远端显示这个数字,需要在本地端输入这个数字给本地设备与远端配对。如输入019655,那此时的临时Key–TK是:0x00000000000000000000000000004CC7。

Out of Band 带外
这种方式是通过BLE之外的,设备上的其他方式来获取这个OOB data,比如通过IR红外,或其余的方式,因此对于蓝牙窃听者/攻击者而言这个data的传输是不可见的了,因此会显得要安全些。

2.1.1 配对请求的数据格式

image

1. IO capabilities表明输入,输出的能力

输入是按键、键盘,输出是显示数字用的界面。

  • 0x00 DisplayOnly 只能是显示000000 ~ 999999的数字
  • 0x01 DisplayYesNo 显示Yes/No 的按钮
  • 0x02 KeyboardOnly 只能是输入000000 ~ 999999的数字
  • 0x03 NoinputNoOutput 没有输入也没有显示,只能用Just work工作方式
  • 0x04 KeyboardDisplay 能输入000000 ~ 999999的数字和输出

2. OOB data flag

  • 0x00 OOB 数据没有发送
  • 0x01 OOB 数据通过远端设备发送(如IR)
  • 0x02-0xFF 保留

3. 身份验证请求

image

  • Bonding_Flags b1b0 Bonding Type

    • 00 No Bonding
    • 01 Bonding
    • 10 Reserved
    • 11 Reserved
  • MITM

MITM域设置为1为请求MITM(中间人介入)保护,否则设置为0. 设备将标志设置为1为STK请求认证的安全属性。
选择Key生成的方法
如果auth Req中MITM没有,则说明不需要人参与中间,所以IO capabilities会被忽略,只用Just Works就OK了。
如果有OOB data,auth Req将可直接忽略,会直接选择OOB的方式了。

  • SC

SC字段是一个1位标志,设置为1以请求LE安全连接配对,否则应根据发起方和响应方支持的功能将其设置为0,可能的结果配对机制为:如果两个设备均支持 LE安全连接,使用LE安全连接; 否则,请使用LE旧式配对。

  • Keypress

keypress字段是一个1位标志,仅在Passkey Entry协议中使用,而在其他协议中将被忽略。 当双方将该字段设置为1时,应使用SMP配对按键通知PDU生成并发送按键通知。

4. MaximumEncryptionKeySize

最大秘钥长度,7到16字节之间

5. InitiatorKeyDistribution

发起者的秘钥分配,该域表明秘钥初始化设备请求分配使用。

配对请求命令中的“生成”字段由主机使用,以请求发起者向响应者分发或生成哪些密钥。

6. ResponderKeyDistribution

响应者的秘钥分配,该字段表明秘钥初始化设备请求响应设备来分配秘钥分配使用。

2.1.2 配对请求实例

image

1. Code (1 octet)

0x01 Pairing Request

2. IO Capability (1 octet)

0x03 NoInputNoOutput: 用just work 认证方式

3. OOB data

0x00 OOB(out of band)
没有带外认证, 带外这种方式是通过BLE之外的,设备上的其他方式来获取这个OOB data,比如通过IR红外,或其余的方式,因此对于蓝牙窃听者/攻击者而言这个data的传输是不可见的了,因此会显得要安全些。

4. AuthReq (1 octet)

AuthReq字段是一个位字段,指示STK和LTK以及GAP绑定信息的请求安全属性
0x01 :表示绑定

5. MaxEncKeySize

0x10 表示最大认证key大小是0x10个字节

6. InitiatorKeyDistribution

该域表明秘钥初始化设备请求分配秘钥分配使用。

7. ResponderKeyDistribution

001 该字段表明秘钥初始化设备请求响应设备来分配秘钥分配使用。

2.1.3 从设备向主设备向发送配对回复报文

image

具体字段含义参考 配对请求报文。

2.2 第二阶段

2.2.1 配对确认

第一阶段的配对特征交换成功之后,用来启动STK生成。该命令被两个对等设备使用,来向对等设备发送确认值。初始化设备通过向响应设备发送配对确认命令启动STK生成。

报文格式
image

启动STK的生成,这一部分可简述为以下步骤的实现

  1. Initiator生成128-bit随机数Mrand,并使用这个Mrand结合一些其他的输入,使用密码工具箱中c1计算出一个128-bit的Mconfirm值:
Mconfirm = c1(TK, Mrand,
Pairing Request command, Pairing Response command,
initiating device address type, initiating device address,
responding device address type, responding device address)

Responder也生成一个128-bit随机数Srand,并使用这个Srand结合一些其他的输入,使用密码工具箱中c1计算出一个128-bit的Sconfirm值:

Sconfirm = c1(TK, Srand,
Pairing Request command, Pairing Response command,
initiating device address type, initiating device address,
responding device address type, responding device address)
  1. Initiator将其计算的Mconfirm值通过Pairing Confirm包发送给Responder,而Responder也将其计算的Sconfirm值通过Pairing Confirm包发送给Initiator;
  2. Initiator收到Sconfirm后,再将Mrand值通过Pairing Random包发送给Responder;
  3. Responder收到Mrand值后计算它的Mconfirm值,再跟前面那个Initiator送过来的Mconfirm值进行比较,若不同说明配对失败了。若相同,则Responder也会将它的Srand值通过Pairing Random包发送给Initiator;
  4. 而Initiator也会计算收到的Srand值的Sconfirm值,并跟前面那个Responder送过来的Sconfirm值进行比较,若不同说明配对失败了,若相同,继续。

报文实例

主设备向从设备发送配对确认报文,从设备也向主设备发送配对确认报文。

image

image

2.2.2 随机配对

该命令用来由初始化和响应设备发送,用来计算在配对确认命令中的确认值的随机数。

报文数据格式
image

报文实例

主设备向从设备发送配对随机值报文,从设备也向主设备发送配对随机值报文。
image

image

2.3 第三阶段

2.3.1 传输特定的密钥分发

所有的键和值都由主从设备分发。

要分发的密钥由配对请求和配对响应的密钥分发参数决定,
配对请求和配对响应来自第一阶段配对特征交换
image

BLE的SMP的一些Key相关定义

  1. Long Term Key (LTK):加密链路用,128-bit;

  2. Encrypted Diversifier (EDIV):在LE legacy pairing过程中,用于识别LTK分发,16-bit;

  3. Random Number (Rand):在LE legacy pairing过程中,用于识别LTK分发,64-bit。

  4. Identity Resolving Key (IRK):用于生成和解析random address用的,128-bit;

  5. AddrType (1 octet)
    如果BD_ADDR是公共设备地址,则AddrType应设置为0x00。
    如果BD_ADDR是静态随机设备地址,则AddrType应设置为0x01。
    BD_ADDR(6个八位字节)此字段设置为分发设备的公共设备地址或静态随机地址。

  6. Connection Signature Resolving Key (CSRK):用于对数据进行签名已经验证签名数据,128-bit;

2.3.2 特定key分发原因

密钥分发阶段的从设备将密钥发送给主设备,这样就可以对重新连接进行加密,并解析其随机地址。或者,主设备可以验证来自从设备的签名数据,主设备也可以向从设备提供密钥,这样,如果角色互换,可以对重连接进行加密,可以解析主设备的随机地址,或者从设备可以验证来自主设备的签名数据。

三 绑定

就是将配对阶段产生的一系列key 保持到flash中,以便后续使用。

以上这个过程的报文交互如下图,
image

  • 64
    点赞
  • 443
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
BLE蓝牙绑定和密码配对流程及代码详解: 一、蓝牙绑定流程 在 BLE 蓝牙设备连接时,需要进行绑定操作,以确保设备间通信的安全性。蓝牙绑定流程如下: 1. 从主设备中发出绑定请求。 2. 从设备接收到绑定请求并回复同意绑定。 3. 主设备生成随机数并加密发送到从设备。 4. 从设备使用预设的加密算法对接收到的随机数进行解密,并将加密后的结果发送给主设备。 5. 主设备对接收到的加密结果进行校验,若校验通过,表示绑定成功。 二、密码配对流程 在 BLE 蓝牙设备连接时,需要进行密码配对操作,以确保设备间通信的安全性。密码配对流程如下: 1. 从主设备中发出密码配对请求。 2. 从设备接收到密码配对请求并回复同意配对。 3. 主设备生成随机数并加密发送到从设备。 4. 从设备使用预设的加密算法对接收到的随机数进行解密,并将加密后的结果发送给主设备。 5. 主设备对接收到的加密结果进行校验,若校验通过,表示配对成功。 三、代码实现 下面是使用 Android BLE API 实现蓝牙绑定和密码配对的示例代码: ```java // 绑定流程 private void startBonding(BluetoothDevice device) { device.createBond(); } // 密码配对流程 private void startPairing(BluetoothDevice device) { device.setPairingConfirmation(true); } @Override public void onBondStateChanged(BluetoothDevice device, int state) { switch (state) { case BluetoothDevice.BOND_BONDING: Log.d(TAG, "正在绑定设备:" + device.getName()); break; case BluetoothDevice.BOND_BONDED: Log.d(TAG, "已绑定设备:" + device.getName()); break; case BluetoothDevice.BOND_NONE: Log.d(TAG, "未绑定设备:" + device.getName()); break; } } @Override public void onPairingRequest(BluetoothDevice device, int mode) { switch (mode) { case BluetoothDevice.PAIRING_VARIANT_PIN: Log.d(TAG, "需要输入 PIN 码"); // 输入 PIN 码 device.setPin(mPin.getBytes()); break; case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION: Log.d(TAG, "需要确认 Passkey"); // 确认 Passkey device.setPairingConfirmation(true); break; case BluetoothDevice.PAIRING_VARIANT_CONSENT: Log.d(TAG, "需要确认配对"); // 确认配对 startPairing(device); break; case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY: case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN: Log.d(TAG, "显示 Passkey 或 PIN 码"); break; default: Log.e(TAG, "未知的配对模式:" + mode); break; } } ``` 以上代码仅供参考,实际实现可能会因为硬件设备和蓝牙协议版本的不同而有所差异。在实际开发中,还需要注意蓝牙设备的连接状态和信号强度等信息,并根据需要进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值