当前位置: 首页 > news >正文

. 使用TFloatKeyAnimation关键帧创建弹跳球动画 . 使用TColorKeyAnimation关键帧动画眩目背景变换 ...

沾缚耐鬃1 加密流程 (Encryption Procedure)

加密的核心在于主从设备双方协商出一致的会话密钥 (Session Key) 和 初始化向量 (IV)。这两个参数由双方各自生成的片段组合而成: IV (Initialization Vector) = IVm (主) + IVs (从), SKD (Session Key Diversifier) = SKDm (主) + SKDs (从)。

它们通过 LL_ENC_REQ(加密请求)和 LL_ENC_RSP(加密响应)这两个 PDU(协议数据单元)进行交换。

1.1 加密流程分析

阶段一:主设备发送加密请求

主设备主机发送请求:主设备主机(Master Host)通过 HCI 接口向链路层发送 HCI_LE_Start_Encryption 命令,携带 Connection_Handle、Random_Number (Rand)、Encrypted_Diversifier (EDIV) 和 Long_Term_Key (LTK)。

主设备暂停发送数据 PDU:主设备链路层在收到指令后,会先发送完当前队列中的数据 PDU,随后暂停发送所有数据 PDU,仅允许发送控制 PDU(如 LL_ENC_REQ)或空包。

主设备链路层发送请求: 发送 LL_ENC_REQ 。其中 Rand, EDIV (来自 Host),SKDm, IVm (控制器内部生成的随机数)。

第二步:从设备接收加密请求

4. 暂停接收数据 PDU:从设备接收到主设备的 LL_ENC_REQ 之后,会暂停 TX 和 RX 数据流。从设备的链路层应完成当前数据通道 PDU 的发送,并可以完成控制器中排队的其他数据通道 PDU 的发送。在这些数据通道 PDU 被确认后,从设备的链路层只允许发送空 PDU 或 LL_ENC_RSP、LL_START_ENC_REQ、LL_START_ENC_RSP、LL_TERMINATE_IND、LL_REJECT_IND 或 LL_REJECT_IND_EXT PDU。

5. 从设备发送响应: 发送 LL_ENC_RSP (携带 SKDs 和 IVs)。主设备收到后也将暂停数据 PDU接收。

6. 获取 LTK: 向主机发送 LL_LTK_REQ_IND,包含 Master 发来的 Rand 和 EDIV。等待从设备主机回复 HCI_LE_LTK_Request_Reply,提供对应的 Long_Term_Key (LTK)。

第三步:密钥的组合与生成

此时,主从双方都拥有了对方的 IV 和 SKD 片段。它们将按照以下规则将各部分拼接成完整的 SKD 和 IV:

SKD = SKDm || SKDs (SKDm 的低位字节在前,SKDs 的高位字节在后)

IV = IVm || IVs (IVm 的低位字节在前,IVs 的高位字节在后)

从设备的链路层会使用加密引擎,以 LTK 作为加密密钥,以拼接好的 SKD 作为输入明文,计算出本次通信的会话密钥(sessionKey)。这个 sessionKey 将用于后续所有数据包的加解密。

第四步:完成加密握手

在成功生成 sessionKey 后:

11. 从设备发送 LL_START_ENC_REQ PDU(此包未加密),通知 Master 已准备好接收一个加密的响应。

12. 主设备收到后,发送 LL_START_ENC_RSP PDU(此包已加密),并准备好收发加密数据,此时主设备进入加密状态。

13. 从设备收到加密的 LL_START_ENC_RSP 后,也回复一个已加密的 LL_START_ENC_RSP PDU,此时从设备进入加密状态。

第五步:通知主机:

双方链路层都会通知各自的上层主机,发送 LL_START_ENC_RSP 事件,表示连接已成功加密。

成功加密时序图

从设备主机

从设备链路层

主设备链路层

主设备主机

从设备主机

从设备链路层

主设备链路层

主设备主机

1. HCI_LE_Start_Encryption 开始加密

2. 暂停数据发送,等待发送队列清空

3. 发送 LL_ENC_REQ (携带 IVm, SKDm, Rand, EDIV)

4. 暂停数据收发,生成 IVs, SKDs

5. 回复 LL_ENC_RSP (携带 IVs, SKDs)

6. 发送LL_LTK_REQ_IND 事件

发送 HCI_LE_LTK_Request_Reply

通过 LTK 和 SKD 计算会话密钥 Session Key

通过 LTK 和 SKD 计算会话密钥 Session Key

11. 发送 LL_START_ENC_REQ (此包未加密)

使能发送和接收加密

12. 回复 LL_START_ENC_RSP (此包已加密)

恢复数据收发

使能发送加密

发送LL_ENC_CHANGE_IND 事件,通知Host已加密

13. 发送 LL_START_ENC_RSP (此包已加密)

恢复数据收发

发送LL_ENC_CHANGE_IND 事件,通知Host已加密

1.2 异常情况

在加密流程中,可能会遇到各种异常,链路层需根据情况进行处理。

1.2.1 从设备不支持加密

若从设备不支持加密,会直接拒绝 LL_ENC_REQ。然后发送 LL_REJECT_IND 或 LL_REJECT_IND_EXT。 错误码:0x1A (Unsupported Remote Feature)。Master 通知 Host 加密失败,连接保持未加密状态继续通信。

1.2.2 密钥丢失 (LTK Missing)

场景 A:初始加密时缺失

若 Slave Host 无法提供 LTK(例如未配对或密钥丢失),应拒绝加密。错误码:0x06 (PIN or Key Missing)。连接保持未加密状态。

场景 B:加密暂停后缺失

若在“加密暂停”流程(即更换密钥)后无法提供 LTK,属于严重安全错误。必须断开连接。

1.2.3 MIC 校验失败 (MIC Failure)

在加密开启后的任何阶段,如果收到解密校验失败的数据包(MIC 不匹配),或者在握手阶段收到非预期的明文/密文。立即断开连接。0x3D (Connection Terminated Due to MIC Failure)。

从设备不支持加密时序图

从设备链路层

主设备链路层

主设备主机

从设备链路层

主设备链路层

主设备主机

LE Start Encryption 请求启用加密

LL_ENC_REQ

LL_REJECT_IND / LL_REJECT_IND_EXT (Unsupported Remote feature 错误码: 0x1A)

通知:加密失败 (对方不支持)

主机未提供 LTK 时序图

从设备主机

从设备链路层

主设备链路层

主设备主机

从设备主机

从设备链路层

主设备链路层

主设备主机

LL_ENC_REQ

LL_ENC_RSP

请求 LTK

未提供 LTK

请求 LTK

未提供 LTK

LL_REJECT_IND / LL_REJECT_IND_EXT (错误码: PIN or key Missing)

通知:加密失败 (密钥丢失)

1.3 加密暂停流程

如果需要在不中断连接的情况下更换加密密钥,就需要先暂停当前的加密,然后再重新开始加密流程。在暂停期间,为保护数据安全,不允许发送未加密的数据 PDU。

流程如下:

主设备发送 LL_PAUSE_ENC_REQ PDU(加密的)来发起暂停请求。在发送前,它会确保当前的数据包已发送完毕,并暂停发送新的数据包。

从设备收到请求后,同样完成当前数据包的发送,然后回复一个 LL_PAUSE_ENC_RSP PDU(加密的)。同时,从设备将自己设置为准备接收未加密的数据。

主设备收到从设备的响应后,也将自己设置为收发都不加密的状态,并向从设备再发送一个 LL_PAUSE_ENC_RSP PDU(这次是未加密的)。

从设备收到这个未加密的响应后,也切换到发送不加密的状态。

至此,双方都暂停了加密。接下来,系统将自动启动前述的“加密开始流程”,以协商并启用新的会话密钥。

加密暂停时序图

从设备链路层

主设备链路层

从设备链路层

主设备链路层

双方现在都处于未加密状态,暂停完成。

接下来将自动执行“加密开始流程”以启用新密钥。

1. LL_PAUSE_ENC_REQ (已加密)

2. LL_PAUSE_ENC_RSP (已加密)

3. 切换到未加密模式

4. LL_PAUSE_ENC_RSP (未加密)

5. 切换到未加密模式

异常处理:与加密开始流程类似,如果在暂停过程中收到非预期的 PDU,也应立即断开连接,并报告 "Connection Terminated Due to MIC Failure" (0 x 3 D) 错误。

加密重新启动 (Encryption Restart) 在需要动态增加或减少安全级别时非常有用。例如,初始建立连接时安全级别较低,但在传输敏感数据时,可以使用此过程更换链路密钥并提升安全级别。

回到顶部

2 数据加密和解密

BLE 使用 AES-128 作为基础加密引擎,结合 CCM (Counter with CBC-MAC) 模式。CCM 模式同时提供加密(机密性) 和认证(完整性)。

2.1 数据加密流程

数据加密流程分为以下几个部分 :

准备Nonce, AAD, Session Key

Nonce(Number Used Once)总长度 13 字节,由以下各部分拼接:PacketCounter,39 bits,每个连接独立的计数器。每发送一个新包就 +1,重传时不增加;DirectionBit,1 bit,主设备 (Master) 发送时为 1,从设备 (Slave) 为 0;IV (初始化向量) ,8 octets,连接开始时生成的随机数,双方共享。

AAD (Additional Authenticated Data)。提取 Data PDU 的首字节。将其中的 NESN、SN、MD 比特位强制置为 0。这是为了确保重传(导致这些位变化)不会破坏解密校验。

Session Key: 用 LTK 作为密钥对 SKD进行 AES-128 运算。这在上文中开始加密的阶段已经准备好了。

生成 MIC

将 AAD、Nonce 和 明文 Payload 填入 CCM 规范定义的

B

0

,

B

1

.

.

.

数据块中。使用 Session Key 对这些块进行 AES-CBC-MAC 运算,生成 MIC。

加密 Payload 和 MIC

使用 Session Key 和 Nonce 生成密钥流 (Keystream)。将明文 Payload 与密钥流进行 XOR(异或) 运算,得到加密后的 Payload。将步骤 2 算出的 MIC 也与密钥流的第一段进行 XOR 运算,得到加密后的 MIC。

加密流程图

最终组包 (Final Assembly)

生成密钥

生成MIC

输入准备

Yes

原始 Payload

长度 > 0?

准备 Header Octet 0

掩码处理: NESN/SN/MD 设为 0

Packet Counter + Direction + IV

构造 13-byte Nonce

构造 B0, B1 块

AES-CBC-MAC 计算

Session Key

生成 4-byte MIC

构造 A0, A1... 块

AES 引擎

生成 Keystream 密钥流

XOR 异或运算

加密后的 Payload + 加密后的 MIC

添加原始 Header 发送

2.2 Cordio 代码分析

PalCryptoAesCcmEncrypt 函数用于对发送的数据包进行软件 AES-CCM 加密。

/*

* 位于: platform/targets/nordic/sources/pal_crypto.c

* 功能: 执行 AES-CCM 加密

*/

bool_t PalCryptoAesCcmEncrypt(PalCryptoEnc_t *pEnc, uint8_t *pHdr, uint8_t *pBuf, uint8_t *pMic)

{

// 1. 基础检查

// 如果未启用加密,直接返回

if (!pEnc->enaEncrypt) { return FALSE; }

// 2. 准备 Nonce

// 将当前的 Packet Counter 填入 Nonce 结构中

// PAL_BB_NONCE_MODE_PKT_CNTR 模式下,计数器由软件维护

if (pEnc->nonceMode == PAL_BB_NONCE_MODE_PKT_CNTR) {

palCryptoIncPktCnt(pCb);

}

// 3. 加载密钥

// 将 Session Key 加载到硬件 ECB 引擎

palCryptoLoadEcbData(pEnc);

// 4. 计算 MIC (认证 - Authentication)

// 使用 AES-CBC-MAC 算法计算 MIC

if (pEnc->enaAuth) {

palCryptoAuthPdu(pEnc->type, pCb, pMic, pHdr, pBuf, pldLen);

}

// 5. 加密 Payload (加密 - Encryption)

// 使用 AES-CTR 模式加密数据 (异或密钥流)

palCryptoPdu(pCb, pMic, pBuf, pldLen);

// 6. 更新计数器

// 为下一个包准备 Packet Counter

if (pEnc->nonceMode == PAL_BB_NONCE_MODE_PKT_CNTR) {

palCryptoIncPktCnt(pCb);

}

return pEnc->enaAuth;

}

PalCryptoAesCcmDecrypt 函数用于对接收的数据包进行软件 AES-CCM 解密和校验。

/*

* 位于: platform/targets/nordic/sources/pal_crypto.c

* 功能: 执行 AES-CCM 解密与校验

*/

bool_t PalCryptoAesCcmDecrypt(PalCryptoEnc_t *pEnc, uint8_t *pBuf)

{

// 1. 基础检查

if (!pEnc->enaDecrypt) { return TRUE; }

// 2. 解密 Payload

// CTR 模式下,解密操作与加密操作数学上是对称的 (都是 XOR 密钥流)

// 这里会还原出明文 Payload 和明文 MIC

palCryptoPdu(pCb, pMic, pBuf, pldLen);

// 3. 计算预期 MIC

// 基于解密后的明文,重新计算一遍 MIC

if (pEnc->enaAuth) {

palCryptoAuthPdu(pEnc->type, pCb, actMic, pHdr, pBuf, pldLen);

}

// 4. 验证 MIC

// 将计算得到的 actMic 与包中携带的 pMic 进行比较

if (memcmp(actMic, pMic, 4) != 0) {

return FALSE; // MIC 校验失败,Controller 将断开连接

}

return TRUE;

}

http://www.cnnetsun.cn/news/1248553.html

相关文章:

  • Docker Desktop里搭建RabbitMq ..集群的保姆级教程
  • 2026年AI写作与创作利器:7款高效工具助你事半功倍
  • 写一段提取PDF单线图材料表的代码,能支持各种格式的PDF
  • 彼岸花会盛开在理想的他乡
  • Spring AI + RAG 从 0 到 1 落地:本地知识库 + 联网搜索,一套代码直接跑通
  • 推理框架极简入门与实战指南(非常详细),Nano-vLLM从入门到精通,收藏这一篇就够了!
  • 14K Star开源RAG项目实战全解(非常详细),检索优化从入门到精通,收藏这一篇就够了!
  • windows 安装openclaw的优势
  • 第 21 篇、为什么 Docker Compose 的 depends_on 根本管不住服务启动顺序?90% 的新手都搞错了
  • OpenClaw 腾讯云 + 火山方舟(Volcengine Ark)完整安装与扩展教程
  • HLS.js 原生开发!m3u8live.cn打造最贴合项目的 M3U8 在线播放器
  • 给Redis增加密码
  • 项目实训记录
  • CMake构建学习笔记-iconv库的构建
  • Flutter 三方库 graph_kit 的鸿蒙化适配指南 - 让逻辑治理回归“拓扑之美”,打造鸿蒙应用专家级的图算法与依赖治理中台
  • STM32F系列兼容西门子S7 200PLC源码 CPU:STM32F103RCT6(或其他S...
  • 【拼多多内推】2027届实习生
  • mac电脑查看安装的mysql版本以及启动
  • 使用 C++、YOLO 和 ONNX Runtime 实现实时目标检测的完整教程整理与代码实现指南。
  • 线性代数直觉(六):向量通过矩阵
  • 华沙理工大学突破性发现:让音乐生成变得可控
  • STM32F0实战:基于HAL库开发【2.8】
  • 673. 最长递增子序列的个数(序列dp)
  • JavaScript性能优化实战哪撤
  • 3.12团队准备开题答辩
  • 把微信做成 AI 入口,到底值不值得?wechatapi操作实践
  • 048海产品销售系统-springboot+vue
  • Claude Code 番外篇:内置 `/loop` 全解,cron 调度 + 自然语言,自动监控只需一行
  • 港科校友| 罗咏丰:以校友导师身份回馈科大
  • 第二章 Spring中的Bean