配对与绑定机制:配对流程详解
配对,是BLE安全的第一道门。说白了,就是两台设备在建立连接后,如何协商出一套加密密钥的过程。我见过不少开发者把配对和绑定混为一谈,其实它们是两个阶段——配对是加密握手,绑定是把密钥存下来下次复用。
BLE 4.2之后,配对流程被标准化为三个阶段。咱们一个一个拆开讲。
配对三阶段总览
先看整体流程,我画了张图帮你建立全局印象:
阶段一:配对特征交换
连接建立后,发起方会发送一个配对请求,包含三样东西:IO能力、是否要求绑定、密钥大小。响应方回一个配对响应,内容格式一样。
这个阶段决定了后续用哪种配对方法。我举个例子:
- IO能力:设备有没有显示屏?有没有键盘?能不能输出/输入?
- 绑定标志:是否要把密钥存下来?
- 密钥大小:128位还是更短?现在基本都是128位。
关键点:配对方法的选择完全由IO能力组合决定。不是你想用哪种就用哪种,是协议栈根据双方IO能力自动匹配的。
阶段二:密钥生成——四种配对方法
这是整个配对的核心。四种方法,各有各的适用场景。我按安全等级从低到高给你捋一遍。
1. Just Works
说白了就是「无脑配对」。双方不展示任何数字,不要求用户确认,直接生成临时密钥(STK)。
适用场景:只有LED和按钮的设备,比如蓝牙灯泡、简单的传感器。
警告:Just Works 不提供MITM保护。也就是说,中间人攻击可以轻松破解。我在项目中见过有人用Just Works做门锁配对,嗯,那扇门基本等于没锁。
流程:
- 双方交换公钥(P-256椭圆曲线)
- 各自计算共享密钥DHKey
- 生成确认值(Confirm Value)并交换
- 验证确认值,生成STK
注意,Just Works虽然也走了公钥交换,但它不验证确认值中的随机数——这就是它不防MITM的原因。
2. Numeric Comparison
这是BLE 4.2引入的方法,也是我个人最推荐的一种。双方各自计算出一个6位数字,显示在屏幕上,用户确认两边数字是否一致。
适用场景:双方都有显示屏,比如手机连手表、手机连车机。
流程:
- 交换公钥,计算DHKey
- 各自生成随机数(na, nb)
- 计算确认值并交换
- 各自计算6位比较值,显示给用户
- 用户确认数字一致后,双方完成配对
避坑指南:我曾经遇到过一个坑——两边显示的数字明明一样,但配对就是失败。后来发现是随机数生成器的种子没初始化好。嗯,嵌入式开发里随机数真的是个老大难问题。
3. Passkey Entry
一方输入6位PIN码,另一方显示或确认。典型场景是蓝牙键盘、蓝牙门锁。
适用场景:一方有输入能力(键盘),另一方有显示能力(屏幕),或者只有LED闪烁提示。
流程:
- 输入方生成6位Passkey
- 双方基于Passkey逐位生成确认值
- 交换并验证20轮(每轮处理1位)
- 生成LTK
这里有个细节:Passkey Entry的20轮交换是为了防暴力破解。每轮只处理1位,攻击者无法一次性猜出全部6位。
4. OOB(Out of Band)
通过蓝牙以外的通道交换配对信息。比如NFC、二维码、声波。
适用场景:需要最高安全等级,或者设备没有显示屏也没有键盘。比如医疗设备、工业传感器。
流程:
- 通过OOB通道交换公钥或随机数
- 蓝牙通道只做确认和验证
- 生成LTK
安全等级对比:OOB > Numeric Comparison > Passkey Entry > Just Works
但OOB的安全性取决于带外通道本身。如果你用NFC,那NFC的安全等级就是OOB的安全等级。
配对方法选择表
下表总结了四种方法的IO能力组合和MITM保护情况:
| 配对方法 | 发起方IO | 响应方IO | MITM保护 | 用户交互 |
|---|---|---|---|---|
| Just Works | NoInputNoOutput | NoInputNoOutput | ❌ 无 | 无 |
| Numeric Comparison | DisplayYesNo | DisplayYesNo | ✅ 有 | 确认数字 |
| Passkey Entry | KeyboardOnly | DisplayOnly | ✅ 有 | 输入PIN码 |
| OOB | 任意 | 任意 | ✅ 有(取决于OOB通道) | 带外操作 |
阶段三:密钥分发
配对完成后,双方开始交换长期使用的密钥。主要包括:
- LTK(Long Term Key):加密连接用的长期密钥
- EDIV + Rand:用于重新生成LTK的标识
- IRK(Identity Resolving Key):用于私密地址解析
- CSRK(Connection Signature Resolving Key):用于数据签名
这些密钥通过加密通道传输——没错,阶段二生成的STK或LTK此时已经加密了连接,所以密钥分发是安全的。
绑定与存储
绑定,就是把阶段三分发的密钥存到非易失存储里。下次两台设备再连接时,直接读取存储的密钥,跳过整个配对流程。
绑定信息通常包括:
- 对端设备的地址(Public Address 或 Random Address)
- LTK、EDIV、Rand
- IRK(如果支持私密地址)
- CSRK(如果支持数据签名)
注意:绑定信息必须安全存储。我见过有人把LTK明文写在Flash里,没有任何加密保护。嗯,那跟把钥匙挂在门上有什么区别?
存储建议:
- 使用硬件唯一密钥(如SoC的OTP密钥)加密绑定数据
- 绑定信息关联对端设备地址,防止地址欺骗
- 定期清理无效绑定,避免存储耗尽
我个人习惯在绑定信息里额外存一个时间戳,记录配对时间。调试时很有用——你能知道设备是什么时候配对的,方便排查问题。
小结
配对与绑定,说白了就是「先握手认识,再存下联系方式」。四种配对方法的选择取决于设备硬件能力,安全等级从Just Works到OOB逐级提升。绑定则是把配对成果固化下来,避免每次连接都重新走一遍流程。