3. LoRaWAN 密钥体系:七把钥匙,一把都不能少

说实话,我刚接触 LoRaWAN 的时候,被这一堆 Key 搞得有点晕。
AppKey、NwkKey、AppSKey、NwkSKey…… 还有 FNwkSIntKey、SNwkSIntKey、NwkSEncKey。
七个名字,七个不同的用途。弄混一个,设备就入不了网,或者数据被截了你也发现不了。

这一节,我就带你把这七把钥匙彻底理清楚。
你想想看,一个 LoRaWAN 设备从出厂到正常工作,密钥体系其实就分两大阶段:
激活前 和 激活后。

核心原则:LoRaWAN 1.0.x 和 1.1 的密钥体系有差异。1.1 版本把网络层和应用层彻底分离,密钥数量从 3 个变成了 7 个。我们以 LoRaWAN 1.1 为准来讲,这是目前的主流。

3.1 根密钥:AppKey 与 NwkKey

这两个是「根密钥」,写在设备出厂固件里。
我个人习惯把它们比作「身份证的底档」—— 一旦泄露,整个设备就废了。

  • AppKey(Application Key):应用层根密钥。用于派生应用会话密钥 AppSKey。
  • NwkKey(Network Key):网络层根密钥。用于派生所有网络层会话密钥。

在 LoRaWAN 1.0.x 时代,只有一个根密钥叫 AppKey,既派网络密钥又派应用密钥。
到了 1.1,LoRaWAN 联盟觉得这样不安全 —— 万一网络层被攻破,应用数据也一起完蛋。
所以拆成了两个。嗯,这里要注意:AppKey 和 NwkKey 永远不能在空中传输。

我曾经见过一个项目,厂商为了方便,把 AppKey 通过串口明文打印出来。结果测试阶段就被同事拍照传到了群里…… 那批模块最后全部报废重烧。根密钥的保管,再怎么小心都不为过。

3.2 会话密钥:OTAA 激活后动态生成

设备通过 OTAA(Over-The-Air Activation)入网时,服务器和终端会基于根密钥,结合随机数协商出一组临时密钥。
这组密钥只在当前会话有效,设备重启或重新入网就会变。

会话密钥一共 5 个,分两类:

3.2.1 网络层会话密钥(3 个)

密钥名称 全称 用途
FNwkSIntKey Forwarding Network Session Integrity Key 上行数据完整性校验(网络服务器转发用)
SNwkSIntKey Serving Network Session Integrity Key 下行数据完整性校验(服务网络服务器用)
NwkSEncKey Network Session Encryption Key 网络层 MAC 命令加密

为什么网络层要拆成三个?
说白了,是为了「职责分离」。
FNwkSIntKey 负责上行完整性,SNwkSIntKey 负责下行完整性,NwkSEncKey 负责加密 MAC 命令。
这样即使某个网络服务器被攻破,它也只能伪造上行数据,伪造不了下行指令。

我自己的经验:调试时如果发现设备能入网但收不到下行,先检查 SNwkSIntKey 是否匹配。我曾经花了两天排查射频问题,最后发现是服务器和终端算出来的 SNwkSIntKey 不一样 —— 因为 Join-Response 的 MIC 计算用错了密钥。

3.2.2 应用层会话密钥(1 个)

  • AppSKey(Application Session Key):用于加密应用层负载数据。也就是你传感器上传的温度、湿度这些业务数据。

AppSKey 只由 AppKey 派生,网络服务器拿不到。
这意味着:网络层只能看到加密后的密文,解不开你的业务数据。
嗯,这才是真正的端到端加密。

3.2.3 遗留密钥:NwkSKey(仅 1.0.x)

如果你还在维护 LoRaWAN 1.0.x 的老设备,会看到一个叫 NwkSKey 的密钥。
它同时承担了网络层加密、完整性校验和应用层加密 —— 一个密钥干三份活。
我个人建议:新项目一律用 1.1,别再用 NwkSKey 了。

3.3 密钥派生流程(OTAA)

我画了一张图,把整个派生关系串起来。你看完应该就全通了。

LoRaWAN 1.1 密钥派生关系图 LoRaWAN 1.1 密钥派生关系图 NwkKey(网络根密钥) AppKey(应用根密钥) Join-Request / Join-Accept 随机数 Join-Accept 随机数 FNwkSIntKey 上行完整性 SNwkSIntKey 下行完整性 NwkSEncKey MAC 命令加密 AppSKey 应用数据加密 说明:所有会话密钥均由根密钥 + 随机数通过 AES-CMAC 派生 FNwkSIntKey / SNwkSIntKey / NwkSEncKey 来自 NwkKey;AppSKey 来自 AppKey

3.4 密钥使用场景速查

我把每个密钥在数据帧里的使用场景整理了一下。调试的时候对照着看,能省不少时间。

数据帧类型 加密密钥 完整性校验密钥
上行应用数据(FRMPayload) AppSKey SNwkSIntKey
下行应用数据(FRMPayload) AppSKey SNwkSIntKey
上行 MAC 命令(FRMPayload) NwkSEncKey FNwkSIntKey
下行 MAC 命令(FRMPayload) NwkSEncKey SNwkSIntKey
FOptLen 中的 MAC 命令 不加密 FNwkSIntKey / SNwkSIntKey

一个小技巧:如果你用 Wireshark 抓 LoRaWAN 包,发现 MIC 校验失败,先确认你填的密钥对不对。
上行 MIC 用的是 FNwkSIntKey,下行用的是 SNwkSIntKey —— 我见过有人把这两个搞反,排查了一下午。

3.5 避坑指南:密钥管理常见问题

  1. 根密钥硬编码风险:AppKey 和 NwkKey 写在固件里,如果固件被逆向,所有设备都暴露。建议结合芯片唯一 ID 做密钥分散。
  2. 会话密钥未及时更新:设备长时间在线,会话密钥不变。如果怀疑被窃,应该触发重新入网(发送 LinkCheckReq 或强制重启)。
  3. 1.0.x 与 1.1 混用:服务器配置成 1.1,终端用 1.0.x 的固件,密钥派生会完全错位。我遇到过最离谱的一次,设备能入网但发不了数据,最后发现是 NwkSKey 和 NwkSEncKey 长度不同。
  4. 密钥存储位置:生产环境下,根密钥建议放在安全元件(SE)或 TEE 里。别图省事放 Flash 明文区。

我曾经帮一个客户排查产线问题,发现 30% 的设备入网失败。最后定位到:烧录工位把 AppKey 和 NwkKey 写反了。两个密钥长度一样,但内容不同,导致 Join-Accept 解密失败。从那以后,我要求所有产线烧录脚本必须加 CRC 校验和回读验证。

3.6 小结

七把钥匙,其实就两类:
根密钥(AppKey、NwkKey)—— 出厂烧录,永不泄露。
会话密钥(FNwkSIntKey、SNwkSIntKey、NwkSEncKey、AppSKey)—— 入网协商,动态更新。
还有一个 NwkSKey,是 1.0.x 的历史遗留,新项目别碰。

记住一句话:根密钥管身份,会话密钥管通信。
搞清楚了这七把钥匙的关系,LoRaWAN 安全体系你就掌握了 80%。