2. 密钥管理体系:AppKey、NwkKey、AppSKey、NwkSKey的生成与存储
密钥管理是LoRaWAN安全架构的基石。说白了一句话:密钥搞错了,后面所有加密都是白搭。我见过太多现场故障,最后追根溯源,都是密钥生成或存储环节埋下的雷。
这一章我们就把LoRaWAN里那几把钥匙——AppKey、NwkKey、AppSKey、NwkSKey——彻底讲清楚。它们怎么来的、存在哪、什么时候用、什么时候换,一个不落。
2.1 密钥家族:谁是谁?
LoRaWAN 1.0.x 和 1.1 的密钥体系略有不同。我们先以最主流的 LoRaWAN 1.0.x 为例,把角色理清。
| 密钥名称 | 长度 | 存储位置 | 主要用途 |
|---|---|---|---|
| AppKey | 128 bit (AES-128) | 终端设备 + 网络服务器 | 派生 AppSKey 和 NwkSKey(OTAA入网时) |
| NwkSKey | 128 bit (AES-128) | 终端设备 + 网络服务器 | 网络层加密(MIC校验、FCnt等) |
| AppSKey | 128 bit (AES-128) | 终端设备 + 应用服务器 | 应用层加密(FRMPayload) |
关键区别:NwkSKey 和 AppSKey 职责分离。NwkSKey 管网络完整性,AppSKey 管应用数据机密性。两者不能混用,否则安全模型就破了。
到了 LoRaWAN 1.1,密钥体系做了调整。引入了 NwkKey 和 AppKey 两个根密钥,并且把 NwkSKey 拆成了两个:FNwkSIntKey、SNwkSIntKey、NwkSEncKey。嗯,这里不展开细讲,但你要知道:1.1 的密钥派生流程和 1.0.x 不兼容。我遇到过有人把 1.0.x 的终端往 1.1 的服务器上怼,结果入网死活过不去——就是密钥派生算法对不上。
2.2 密钥生成:从根密钥到会话密钥
密钥生成分两步:根密钥预置 和 会话密钥派生。
2.2.1 根密钥预置(AppKey / NwkKey)
根密钥是在设备出厂前就烧录好的。我个人习惯的做法是:
- 在安全环境中生成随机 128 bit 密钥
- 一份写入终端设备的 安全存储区(比如 STM32 的 OTP 区域或专用安全芯片)
- 一份登记到网络服务器的 密钥数据库
这里有个坑:千万不要把根密钥硬编码在固件里。我曾经接手过一个项目,厂商把 AppKey 写死在代码里,结果固件被反编译,所有设备的密钥全部泄露。嗯,那场面……
警告:根密钥一旦泄露,整个网络的所有设备都需要重新入网。这不是开玩笑的事。
2.2.2 会话密钥派生(OTAA 入网流程)
终端通过 OTAA 入网时,会基于根密钥派生出会话密钥。流程如下:
- 终端发送 Join Request(包含 DevEUI、AppEUI、DevNonce)
- 网络服务器验证后,生成 Join Accept(包含 AppNonce、NetID、DevAddr)
- 双方使用相同的派生算法,基于 AppKey 计算出 NwkSKey 和 AppSKey
派生公式(LoRaWAN 1.0.x):
NwkSKey = aes128_encrypt(AppKey, 0x01 | AppNonce | NetID | DevNonce | pad16)
AppSKey = aes128_encrypt(AppKey, 0x02 | AppNonce | NetID | DevNonce | pad16)
注意那个 0x01 和 0x02,它们就是区分两个密钥的“盐”。如果写反了,网络层和应用层就乱套了。我排查过一起数据解密失败的问题,最后发现是服务器端把这两个值搞反了。
2.3 密钥存储:安全第一
密钥存哪?怎么存?这是整个安全体系里最容易出问题的地方。
| 存储位置 | 安全等级 | 推荐场景 |
|---|---|---|
| MCU 内部 Flash(明文) | 低 | 仅用于原型验证,严禁量产 |
| MCU 内部 Flash(加密存储) | 中 | 成本敏感型产品,需配合读保护 |
| 独立安全芯片(SE) | 高 | 金融级、工业级应用 |
| TPM / 硬件安全模块(HSM) | 极高 | 网络服务器端密钥管理 |
我的建议:终端设备至少使用 MCU 的读保护 + 加密存储。服务器端一定要上 HSM 或密钥管理服务(KMS)。别省这个钱,省了迟早要还。
2.4 密钥生命周期管理
密钥不是永久的。它有自己的生命周期:生成 → 分发 → 使用 → 轮换 → 销毁。
2.4.1 密钥轮换
会话密钥(NwkSKey、AppSKey)在每次重新入网时都会重新派生。但根密钥(AppKey)呢?它一般不换。这就带来一个问题:如果根密钥泄露,所有历史通信都可以被解密。
我建议的做法是:
- 对于高安全场景,支持 远程密钥更新(通过 LoRaWAN 的 FUOTA 或自定义指令)
- 定期更换根密钥,比如每两年一次
- 设备退役时,必须物理销毁密钥存储区
注意:密钥轮换不是简单的“覆盖写”。你需要确保新旧密钥的过渡期不出错。我曾经见过一个系统,轮换密钥时没处理好时序,导致一半设备用新密钥、一半用旧密钥,网络直接分裂了。
2.4.2 密钥销毁
设备报废时,密钥必须彻底清除。别以为格式化 Flash 就完事了——有些 MCU 的 Flash 可以用特殊手段恢复数据。
正确的做法:
- 对密钥存储区执行 多次覆写(比如先写 0x00,再写 0xFF,再写随机数)
- 触发 MCU 的 安全擦除 指令(如果有的话)
- 物理销毁存储介质(比如研磨芯片)——这是最彻底的办法
2.5 常见故障与排查
最后,我列几个我实际踩过的坑,你排查时可以直接对照:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 入网成功,但数据解密失败 | AppSKey 派生错误 | 检查 AppNonce/DevNonce 是否一致,派生公式中的 0x01/0x02 是否写反 |
| 入网请求被拒绝 | AppKey 不匹配 | 核对终端和服务器上的 AppKey 是否一致 |
| 设备频繁掉线 | NwkSKey 损坏或 FCnt 不同步 | 重新入网,检查 FCnt 重置逻辑 |
| 固件升级后无法入网 | 密钥存储区被误擦除 | 检查固件升级脚本是否保护了密钥区域 |
一个小技巧:排查密钥问题时,先在测试环境用固定的 AppKey 和 DevNonce 做对比测试。这样能快速定位是算法问题还是密钥本身的问题。
密钥管理这件事,说难不难,说简单也不简单。你只要记住一条:密钥是安全的第一道门,也是最后一道门。门没锁好,其他都是白费功夫。