3. LE Secure Connections:ECDH密钥交换、密钥生成、安全连接升级流程
LE Secure Connections,说白了就是蓝牙4.2以后引入的一套全新安全架构。我最早接触它是在做一款医疗手环项目时,客户要求数据必须经过P256椭圆曲线加密——嗯,那时候我才真正开始啃这套协议。
这一节我们聚焦三个核心问题:密钥怎么交换的?最终生成了哪些密钥?以及从普通连接升级到安全连接的完整流程。
3.1 ECDH密钥交换:双方如何协商出共享密钥?
传统蓝牙的配对依赖PIN码或OOB数据,本质上是一种预共享密钥模式。而LE Secure Connections用的是椭圆曲线Diffie-Hellman(ECDH),它让双方在不传递私钥的情况下,计算出同一个共享密钥。
具体过程是这样的:
- 生成密钥对:Master和Slave各自生成一个P-256椭圆曲线密钥对(私钥+公钥)。
- 交换公钥:双方通过Pairing Request/Response之后的
Pairing Public Key包,把自己的公钥发给对方。 - 计算共享密钥:各自用对方的公钥和自己的私钥,执行ECDH运算,得到DHKey(Diffie-Hellman共享密钥)。
核心公式(理解即可):
DHKey = P256(SKa, PKb) = P256(SKb, PKa)
其中SKa是A的私钥,PKb是B的公钥。两边算出来的DHKey是完全一样的。
我在项目中遇到过一个问题:公钥交换时如果被中间人篡改,双方算出的DHKey就不一致。所以LE Secure Connections在后续的Authentication Stage 1里,会用Numeric Comparison或Passkey Entry等方式验证公钥的真实性。这一点后面会细讲。
3.2 密钥生成:从DHKey到最终使用的加密密钥
DHKey只是一个256位的共享秘密,不能直接用来加密。蓝牙协议定义了一套密钥派生函数(f1~f5),把DHKey和配对过程中交换的随机数、地址等信息揉在一起,生成最终使用的密钥。
我习惯把这套流程称为“密钥烘焙”——原料是DHKey,辅料是各种随机数,烤出来的是LTK、IRK等成品。
| 函数 | 输入 | 输出 | 用途 |
|---|---|---|---|
| f1 | DHKey, SKa, SKb, Na, Nb, IOcapA, IOcapB | MConfirm / NConfirm | 配对确认值(Authentication Stage 1) |
| f2 | DHKey, Na, Nb, AAddr, BAddr | MacKey, LTK | 生成长期密钥LTK和MAC密钥 |
| f3 | DHKey, Na, Nb, AAddr, BAddr | IRK | 身份解析密钥(用于私密地址) |
| f4 | DHKey, Na, Nb, AAddr, BAddr | CSRK | 连接签名解析密钥 |
| f5 | DHKey, Na, Nb, AAddr, BAddr | IV, SK | 生成会话密钥SK和初始向量IV |
避坑指南:我曾经在移植协议栈时,发现f2和f5的输入参数顺序搞反了,导致LTK和Session Key对不上。建议你在实现时,对照Core Spec Vol.3 Part H Section 2.2.7的伪代码逐行核对。
3.3 安全连接升级流程:从无加密到加密通信
整个升级过程可以分成四个阶段。我画了一张流程图,方便你理解整体脉络。
3.4 认证阶段1的三种模式
Phase 3是整个流程中最容易出问题的环节。根据双方的IO能力,蓝牙协议定义了三种认证方式:
- Numeric Comparison(数值比较):双方显示一个6位数字,用户确认是否一致。这是最常见的方式,适合有显示屏和确认按钮的设备。
- Passkey Entry(密码输入):一方显示数字,另一方输入。适合键盘类设备。
- Out of Band(带外):通过NFC或其他带外通道交换确认值。适合无UI的设备。
注意:如果双方都没有显示屏和输入能力(比如两个传感器),则只能使用Just Works模式。这种模式下认证阶段1被跳过,无法抵抗中间人攻击。我在做工业传感器项目时,就因为这个被安全审计打回了一次——后来加了NFC OOB才通过。
3.5 密钥派生的实际顺序
Phase 4的密钥派生不是一次完成的。我整理了一个典型的执行顺序:
- f2函数:先生成MacKey和LTK。MacKey用于后续的密钥分发消息认证。
- f3函数:生成IRK,用于私密地址解析。
- f4函数:生成CSRK,用于连接签名。
- f5函数:生成Session Key SK和初始向量IV,用于当前连接的加密。
这里有个细节:LTK和SK是不同的。LTK是长期密钥,存储在非易失性存储器中,用于下次重连时的快速配对。SK是会话密钥,每次连接都会重新生成,用完即弃。
我的经验:在实现密钥存储时,建议把LTK、IRK、CSRK分开存储。我曾经见过一个方案把所有密钥拼成一个结构体存储,结果升级固件时结构体对齐方式变了,导致密钥读取失败——设备再也连不上了。
3.6 加密启动:最后一步
密钥派生完成后,Master发送LL_ENC_REQ,携带用SK加密的随机数。Slave回复LL_ENC_RSP。双方确认加密参数无误后,链路层开始用AES-CCM加密所有数据包。
嗯,到这里,一条安全的BLE连接才算真正建立起来。