低功耗蓝牙终端的安全认证,是这两年做物联网硬件绕不开的一个坎。我最早接触这块是在一个智能门锁项目上,当时产品已经小批量出货,结果被安全团队用一台笔记本加一个几十块钱的抓包模块,在十分钟内复现了"伪造开锁指令"——问题就出在BLE链路的身份认证形同虚设,配对阶段用的还是最基础的Just Works模式,密钥协商过程完全裸奔。那次之后我花了将近三个月时间,把BLE从链路层到应用层的认证机制重新啃了一遍,也踩了不少TRNG(真随机数发生器)相关的坑。这篇内容就是把这套经验整理出来,讲清楚低功耗蓝牙物联网终端的身份认证到底该怎么做、TRNG在其中扮演什么角色、以及实际落地时哪些细节最容易翻车。适合正在做BLE终端固件、物联网安全方案、或者被安全审计卡住的硬件工程师和嵌入式开发者参考,不需要你对蓝牙协议栈有很深的前置知识,但至少要写过BLE的GATT服务。
1. 为什么BLE终端的身份认证比想象中更棘手
1.1 从一次伪造开锁说起:认证缺失的真实代价
先把这个案例讲透,因为它几乎涵盖了BLE认证的所有典型问题。那款智能门锁用的是某国产BLE SoC,配对模式配置为Just Works,也就是无确认、无密钥交换的"裸配对"。攻击者只需要在门锁广播时发起连接,利用配对过程中的明文特征,就能推导出后续通信的加密密钥。更致命的是,应用层的开锁指令没有做二次签名校验,只要链路层加密被解开,指令就是明文可读、可重放的。
这里要澄清一个很多人混淆的概念:BLE的链路层加密不等于应用层身份认证。链路层加密解决的是"这条链路别人偷听不到",但它不解决"连上来的这个设备到底是不是合法设备"。Just Works模式下,任何设备都能完成配对并建立加密链路,加密密钥是双方临时协商的,攻击者作为中间人完全可以各连一边。所以身份认证必须做在应用层,链路层加密只是第一道防线。
我后来复盘,正确的做法应该是三层防护叠加:链路层用带MITM保护的配对模式(Passkey或Numeric Comparison),应用层做基于挑战-响应的双向认证,关键指令再加一层数字签名。这三层里,随机数的质量直接决定了每一层的安全性,这就引出了TRNG的问题。
1.2 链路层加密和应用层认证的分工边界
很多团队在方案评审时会争论"到底要不要自己做应用层认证",理由是"芯片厂商说链路层已经加密了"。这个说法对,但不完整。我把两者的职责边界列清楚:
| 防护层 | 解决的问题 | 典型机制 | 失效场景 |
|---|---|---|---|
| 链路层加密 | 防窃听、防链路层篡改 | AES-CCM、配对密钥协商 | Just Works被中间人、密钥泄露 |
| 应用层认证 | 确认对端设备身份合法 | 挑战-响应、证书、预共享密钥 | 随机数可预测、密钥硬编码 |
| 指令级签名 | 防重放、防伪造指令 | HMAC、数字签名、计数器 | 计数器回绕、签名算法弱 |
从表里能看出来,链路层加密失效的场景恰恰是应用层认证要补的位。而应用层认证的核心是"挑战值"——服务器发一个随机数给终端,终端用密钥对它做运算返回,服务器验证。如果这个随机数可预测,攻击者就能提前算好响应值,认证直接绕过。所以随机数质量是应用层认证的命门,这也是为什么标题里把TRNG和身份认证放在一起讲。
1.3 物联网终端对认证方案的特殊约束
和手机、电脑不一样,物联网终端做认证有一堆现实约束,这些约束直接决定了方案选型。我总结了几条最要命的:
- 算力有限:很多终端跑的是Cortex-M0/M4,主频几十兆,跑不动RSA-2048这种重运算,ECC P-256已经是上限。
- 内存紧张:RAM可能只有几十KB,证书链、密钥材料都得精打细算。
- 功耗敏感:纽扣电池供电的设备,认证握手多几轮就可能少活几个月。
- 无稳定时钟:很多终端没有RTC,或者RTC精度很差,基于时间戳的防重放机制容易失效。
- 量产密钥注入:每台设备的密钥怎么安全地写进去,产线环节本身就是个大坑。
这些约束叠加起来,意味着你不能照搬互联网那套TLS双向认证,得做裁剪和取舍。后面几节我会具体讲怎么在这些约束下把认证做扎实。
2. TRNG在BLE认证链路里到底管什么用
2.1 伪随机和真随机的差距:一个可预测的nonce如何毁掉整套认证
先讲清楚TRNG和PRNG(伪随机数发生器)的本质区别。PRNG是确定性的算法,给定相同的种子,输出序列完全一致。TRNG是从物理熵源(热噪声、环形振荡器抖动、亚稳态等)提取随机性,理论上不可预测。
在BLE认证里,随机数用在三个地方:配对阶段的密钥生成、应用层认证的挑战值(nonce)、以及会话密钥的派生。这三处任何一处用了弱随机数,整套认证就可能崩盘。我见过最离谱的案例是某终端直接用rand()函数生成挑战值,而srand()的种子是固定的编译时间戳——这意味着每次上电后生成的挑战值序列完全一样,攻击者抓一次包就能预测后续所有认证。
注意:很多芯片的硬件随机数外设在低功耗模式下会关闭,唤醒后第一次读取可能返回全0或固定值。这个坑我在nRF52系列上遇到过,必须在读取前确认外设已稳定,或者丢弃前若干个采样值。
2.2 熵源从哪来:芯片内置TRNG与外部熵源的取舍
大部分主流BLE SoC都内置了TRNG外设,比如Nordic nRF52/nRF53系列、TI CC26xx系列、Silicon Labs EFR32系列。这些内置TRNG的熵源通常是环形振荡器抖动或热噪声,质量参差不齐。选型时我一般看两个指标:熵率(每秒能产出多少比特的真随机)和是否通过相关随机性检测(如NIST SP 800-22、AIS-31)。
如果芯片内置TRNG质量不够,或者你用的是没有TRNG的低端MCU,就得考虑外部熵源。常见方案有:
- 专用安全芯片:如ATECC608A、SE050,内置高质量TRNG,还带密钥存储和加密加速,是物联网终端的首选。
- 外部TRNG模块:成本高,一般只在特殊场景用。
- 混合方案:用内置TRNG做种子,喂给CSPRNG(密码学安全PRNG)扩展,兼顾质量和速度。
我的经验是,只要预算允许,优先上专用安全芯片。它一次性解决了TRNG、密钥存储、加密加速三个问题,而且密钥永远不出芯片,比在MCU里软实现安全得多。下面这张表是我实际项目里对比过的几款方案:
| 方案 | TRNG质量 | 密钥存储 | 加密加速 | 成本 | 适用场景 |
|---|---|---|---|---|---|
| MCU内置TRNG | 中等 | 无(需软实现) | 部分有 | 低 | 低安全要求、成本敏感 |
| ATECC608A | 高 | 安全存储 | ECC/AES | 中 | 主流物联网终端 |
| SE050 | 高 | 安全存储 | 全算法 | 中高 | 高安全要求 |
| 纯软件CSPRNG | 依赖种子 | 无 | 无 | 极低 | 不推荐用于认证 |
2.3 把TRNG接进认证流程:挑战值生成与密钥派生的实操
具体怎么用?我拿一个典型的挑战-响应认证流程举例。终端和服务器共享一个预置密钥K,认证过程如下:
- 终端发起认证请求,携带设备ID。
- 服务器用TRNG生成一个16字节随机挑战值
nonce,下发给终端。 - 终端用K对
nonce做HMAC-SHA256运算,得到响应值resp,回传。 - 服务器本地用同样的K和
nonce算一遍,比对resp。 - 认证通过后,双方用
nonce和K派生出会话密钥,用于后续通信加密。
这个流程里,nonce必须由TRNG生成,且每次认证都不同。终端侧如果也要生成随机数(比如主动上报时的会话ID),同样得用TRNG。代码层面,以nRF52为例,读取TRNG的典型写法是:
#include "nrf_crypto.h" #include "nrf_crypto_rng.h" ret_code_t generate_random(uint8_t *p_buff, size_t len) { ret_code_t err = nrf_crypto_rng_vector_generate(p_buff, len); if (err != NRF_SUCCESS) { // 处理错误,绝不能降级到弱随机 return err; } return NRF_SUCCESS; }关键点是错误处理不能降级。我见过有代码在TRNG读取失败时直接memset成0或者调用rand()兜底,这等于把安全门直接拆了。正确做法是认证流程直接失败,宁可设备不可用,也不能用弱随机凑合。
3. 身份认证方案的选型与落地细节
3.1 对称密钥还是非对称:基于终端能力的决策树
这是方案选型第一个要拍板的问题。对称方案(预共享密钥+HMAC)算力开销小、代码量少,但密钥管理麻烦——每台设备的密钥都得安全注入,服务器侧要存全量密钥,一旦服务器被拖库,所有设备沦陷。非对称方案(ECC签名/密钥交换)终端只需存私钥,服务器存公钥,泄露风险小,但算力开销大。
我一般用这个决策逻辑:
- 终端是Cortex-M0且无硬件加速:优先对称方案,配合安全芯片存密钥。
- 终端是Cortex-M4及以上或有ECC加速:优先非对称,用ECC P-256。
- 安全等级要求极高(如金融、门锁):非对称+安全芯片,双保险。
这里有个折中方案值得提:用安全芯片做非对称运算,MCU只负责搬运数据。ATECC608A这类芯片内部就能完成ECDSA签名和ECDH密钥交换,MCU不需要有ECC算力,等于用几块钱的芯片给低端MCU加了个安全引擎。我在一个Cortex-M0+的项目上就是这么干的,效果很好。
3.2 配对模式的选择:Just Works为什么不能用
回到开头那个案例。BLE的配对模式有四种:Just Works、Passkey Entry、Numeric Comparison、OOB。安全等级从低到高。Just Works没有任何MITM保护,只适合"完全无敏感数据"的场景,但凡涉及控制指令、用户数据,都不能用。
Passkey Entry需要一端显示6位数字、另一端输入,适合有显示屏或按键的设备。Numeric Comparison是双方都显示6位数字、用户确认一致,适合双方都有显示屏的场景。OOB是通过带外通道(如NFC)交换配对信息,安全性最高但需要额外硬件。
物联网终端很多是"无屏无按键"的,这就尴尬了——Passkey和Numeric Comparison都用不了。这时候的常见做法是:配对阶段用Just Works建立链路,但应用层强制做双向认证。也就是说,链路层加密只当防窃听用,真正的身份确认交给应用层。这个组合在实践中是可接受的,前提是应用层认证做得足够扎实。
3.3 密钥注入与生命周期管理:产线环节的坑
密钥怎么进到设备里,是量产阶段最容易出事的地方。我见过几种做法,按安全性从低到高排:
- 固件里硬编码:所有设备同一个密钥,最差,一旦泄露全军覆没。
- 产线明文写入:每台设备不同密钥,但写入过程明文,产线人员能拿到。
- 产线加密写入:密钥加密后传输,设备内解密存储,较好。
- 安全芯片内生成:密钥在芯片内生成,永不导出,公钥导出给服务器,最佳。
最后一种是最理想的。以ATECC608A为例,可以在产线让芯片自己生成ECC密钥对,然后只把公钥读出来上传到服务器,私钥永远锁在芯片里。这样即使产线被渗透,也拿不到私钥。缺点是产线需要联网上传公钥,流程复杂一些。
提示:密钥注入环节一定要做产线审计,记录每台设备的密钥注入时间和操作员。一旦出现批量安全事件,审计日志是追溯源头的唯一手段。
4. 从抓包到复现:认证流程的验证与攻击面排查
4.1 用抓包工具看清认证握手的每一步
方案做完不能就算完,必须验证。BLE抓包我用得最多的是nRF Sniffer配合Wireshark,成本低、上手快。抓包时重点看几个地方:
- 配对请求里的
AuthReq字段,确认MITM标志位是否置位。 - 配对过程中的密钥交换是否暴露了可推导密钥的信息。
- 应用层认证的挑战值是否每次不同、是否有规律。
- 认证失败后设备的行为,是否会泄露额外信息。
我一般会抓三次完整的认证流程,把三次的挑战值拉出来对比。如果发现有重复、递增规律、或者和某些固定值相关,基本可以判定随机数有问题。这一步能筛掉大部分低级错误。
4.2 重放攻击、中间人攻击的复现与防御验证
验证认证方案是否抗重放,最直接的办法就是自己重放一遍。用抓包工具录下一次合法的认证响应,然后在新的认证会话里把响应值原样发回去,看服务器是否接受。如果接受了,说明没有防重放机制,或者nonce复用。
抗重放的标准做法是:每次认证的挑战值必须唯一且不可预测,服务器侧维护一个已用挑战值的黑名单或时间窗口。对于没有稳定时钟的终端,可以用单调递增的计数器配合挑战值,服务器记录每台设备的最大计数器值,拒绝回退的请求。
中间人攻击的验证稍微复杂,需要两台BLE设备做转发。核心是看应用层认证能否识别出"链路两端不是同一个对端"。如果应用层认证是基于预共享密钥的挑战-响应,中间人无法伪造响应(因为它没有密钥),认证会失败。但如果认证只是"连上就信",中间人就能得逞。
4.3 认证失败时的降级陷阱与日志泄露
这是最容易被忽视的攻击面。很多设备在认证失败后会"友好地"降级——比如连续失败几次后允许无认证访问,或者返回详细的错误信息("密钥错误"vs"设备不存在")。这些行为都是攻击者的信息源。
正确的做法是:认证失败一律返回统一的模糊错误,且不提供任何降级路径。失败次数达到阈值后,设备进入锁定状态,需要物理复位或管理员解锁。日志方面,认证相关的日志不能包含密钥、挑战值等敏感信息,只记录成功/失败和时间戳。
我在一个项目里就吃过这个亏:设备认证失败后返回的错误码区分了"密钥错误"和"设备未注册",攻击者据此可以枚举出哪些设备ID是有效的。后来改成统一错误码才堵上。
5. 低功耗约束下的认证优化与实测数据
5.1 认证握手的功耗拆解与优化空间
物联网终端最怕认证流程把电耗光。我实测过一套基于ECC P-256的认证流程,在nRF52832上的功耗数据大致如下:
| 阶段 | 耗时 | 平均电流 | 单次能耗 |
|---|---|---|---|
| 广播与连接建立 | 约50ms | 5mA | 0.25mAs |
| 链路层加密协商 | 约30ms | 6mA | 0.18mAs |
| ECDH密钥交换 | 约120ms | 8mA | 0.96mAs |
| ECDSA签名验证 | 约80ms | 8mA | 0.64mAs |
| 应用层挑战-响应 | 约20ms | 5mA | 0.10mAs |
一次完整认证大约消耗2.1mAs。如果设备用CR2032纽扣电池(约220mAh),理论上能支撑约37万次认证。但如果认证频繁(比如每次上报数据都认证),续航就会急剧下降。
优化方向有几个:会话复用(认证一次后派生会话密钥,后续通信复用,定期重新认证)、认证结果缓存(短时间内重复连接直接复用上次结果)、降低认证频率(非敏感操作不认证)。我在项目里一般设置会话有效期15分钟,期间重连不重新认证,实测续航提升明显。
5.2 会话复用与认证频率的平衡
会话复用不是无脑复用,得设边界。我的做法是:
- 会话密钥有效期15分钟,到期强制重新认证。
- 会话内如果检测到异常(如指令序列异常、信号强度突变),立即作废会话。
- 设备重启后会话作废,必须重新认证。
- 服务器侧可以主动吊销会话,终端下次通信时重新认证。
这套机制在安全性和功耗之间取得了不错的平衡。实测下来,正常使用场景下认证频率从"每次通信"降到"每15分钟一次",功耗降低约70%。
5.3 实测:不同TRNG方案对认证耗时的影响
最后分享一组TRNG方案对认证耗时影响的实测数据。测试平台是nRF52840,认证流程用ECC P-256,对比三种随机数来源:
| TRNG方案 | 挑战值生成耗时 | 认证总耗时 | 随机数质量 |
|---|---|---|---|
| 内置TRNG | 约0.5ms | 约300ms | 中等 |
| ATECC608A | 约2ms | 约310ms | 高 |
| 软件CSPRNG(TRNG做种子) | 约0.1ms | 约295ms | 依赖种子质量 |
从数据看,TRNG方案对认证总耗时的影响很小(因为ECC运算才是大头),所以不要为了省那1-2ms去用弱随机数,得不偿失。ATECC608A虽然生成随机数慢一点,但质量最高,还顺带解决了密钥存储问题,综合性价比最高。
我个人在实际操作中的体会是,BLE终端的身份认证没有"一招鲜"的方案,核心是把链路层加密、应用层认证、随机数质量这三件事都做扎实,任何一环偷懒都会成为短板。TRNG看起来是个小细节,但它决定了整套认证的地基稳不稳。选型时优先考虑带安全芯片的方案,验证时一定要自己动手抓包重放,功耗优化要建立在安全不打折的前提下。这套思路我在几个量产项目上验证过,虽然前期投入大一些,但省去了后期被安全事件追着跑的麻烦。