LoRaWAN 密钥体系:AppKey、NwkKey、AppSKey、NwkSKey 的生成与作用
聊 LoRaWAN 安全,绕不开的就是密钥。很多刚入行的朋友,看到 AppKey、NwkKey、AppSKey、NwkSKey 这四个名字就头大。说实话,我当年也迷糊过一阵子。
但你要想明白一件事:LoRaWAN 的密钥设计,本质上就是一套「谁该知道什么」的权限划分。搞懂了这一点,后面看安全更新机制就顺了。
1.1 从一把钥匙到两把钥匙:LoRaWAN 1.0.x 与 1.1 的区别
先说说历史。LoRaWAN 1.0.x 时代,只有一套密钥体系:
- AppKey:根密钥,用来派生其他密钥
- AppSKey:应用会话密钥,加密应用数据
- NwkSKey:网络会话密钥,加密网络层数据
看起来挺简洁对吧?但问题来了——AppSKey 和 NwkSKey 都是从同一个 AppKey 派生出来的。这意味着,网络服务器和应用服务器共享了同一个根密钥。你想想看,这合理吗?
所以 LoRaWAN 1.1 做了关键改进:把一把钥匙拆成了两把。
- NwkKey:网络根密钥,只归网络服务器管
- AppKey:应用根密钥,只归应用服务器管
这样一来,网络侧和应用侧彻底解耦。我个人觉得,这是 1.1 版本最值得升级的理由之一。
1.2 密钥的生成:从哪里来?
所有密钥的源头,其实都在设备出厂那一刻就定好了。LoRaWAN 终端设备在烧录时,会写入两个关键值:
- DevEUI:全球唯一设备标识,类似设备的身份证
- AppKey(或 NwkKey + AppKey,取决于版本)
这些根密钥是怎么生成的?标准做法是:
// 伪代码示意:根密钥生成
AppKey = AES_128_ECB_encrypt(RootKey, DevEUI || JoinNonce)
// 实际生产环境中,RootKey 由密钥管理系统(KMS)安全生成
嗯,这里要注意:根密钥必须由安全的随机数生成器产生。我在项目中见过有人直接用固定字符串当 AppKey,结果可想而知——整个网络的安全形同虚设。
1.3 会话密钥的派生:OTAA 流程中的关键步骤
设备入网(Join)时,会通过 OTAA 流程派生出会话密钥。这个过程我建议你仔细看,因为它是整个安全体系的基石。
当设备发送 Join Request 后,网络服务器会回复 Join Accept。这个 Join Accept 里面包含一个关键参数——AppNonce(或 JoinNonce)。
然后,双方用这个 Nonce 加上其他参数,通过 AES 算法派生出会话密钥:
// LoRaWAN 1.0.x 的派生方式
NwkSKey = aes128_encrypt(AppKey, 0x01 || AppNonce || NetID || DevNonce || pad16)
AppSKey = aes128_encrypt(AppKey, 0x02 || AppNonce || NetID || DevNonce || pad16)
// LoRaWAN 1.1 的派生方式
FNwkSIntKey = aes128_encrypt(NwkKey, 0x01 || JoinNonce || JoinEUI || DevNonce || pad16)
SNwkSIntKey = aes128_encrypt(NwkKey, 0x03 || JoinNonce || JoinEUI || DevNonce || pad16)
NwkSEncKey = aes128_encrypt(NwkKey, 0x04 || JoinNonce || JoinEUI || DevNonce || pad16)
AppSKey = aes128_encrypt(AppKey, 0x05 || JoinNonce || JoinEUI || DevNonce || pad16)
关键点:注意看 1.1 版本中,NwkKey 派生了三个网络密钥,而 AppKey 只派生了 AppSKey。这就是「职责分离」的具体实现。
1.4 各密钥的作用:谁用谁?
我把四个核心密钥的作用整理成了一张表,方便你对照:
| 密钥名称 | 所属版本 | 存储位置 | 主要用途 |
|---|---|---|---|
| AppKey | 1.0.x / 1.1 | 终端 + 应用服务器 | 派生 AppSKey;1.0.x 中还派生 NwkSKey |
| NwkKey | 1.1 新增 | 终端 + 网络服务器 | 派生所有网络层会话密钥 |
| AppSKey | 1.0.x / 1.1 | 终端 + 应用服务器 | 加密/解密应用层负载(FRMPayload) |
| NwkSKey | 1.0.x | 终端 + 网络服务器 | 计算 MIC、加密网络头(FHDR) |
我的建议:如果你还在用 1.0.x,尽快评估升级到 1.1。虽然迁移有成本,但安全收益是实打实的。尤其是做智慧抄表、工业传感器这类对数据保密性要求高的场景,1.1 的密钥分离设计能省掉很多合规上的麻烦。
1.5 密钥的生命周期管理
密钥不是永久的。每次设备重新入网(Rejoin),会话密钥都会重新派生。但根密钥(AppKey / NwkKey)是写死在设备里的,除非物理更换设备,否则不会变。
这就引出一个问题:如果根密钥泄露了怎么办?
说实话,这是 LoRaWAN 目前的一个短板。根密钥泄露后,攻击者可以伪造设备身份、解密历史数据。唯一的补救措施就是——换设备。
所以我在项目里一直强调:根密钥的存储和分发,必须用硬件安全模块(HSM)或安全元件(SE)。别图省事把密钥明文写在配置文件里,那是给自己挖坑。
1.6 密钥体系全景图
下面这张图,是我根据 1.1 版本的密钥体系画的。你可以看到,从根密钥到会话密钥,再到具体的加密用途,整个链路非常清晰:
1.7 避坑指南:我见过的密钥管理翻车现场
做了这么多年物联网安全,我见过太多密钥管理上的问题了。挑几个典型的说说:
- 密钥硬编码在固件里——有人把 AppKey 直接写在代码里,结果固件被反编译后全网密钥都暴露了。我建议用安全芯片存储根密钥。
- 所有设备用同一个 AppKey——这相当于一把钥匙开所有锁。一旦泄露,整个网络都得重建。
- 忽略 JoinNonce 的随机性——JoinNonce 如果不够随机,会话密钥就可能被预测。我在一个项目中排查过这个问题,最后发现是随机数生成器初始化种子没做好。
- 1.0.x 升级到 1.1 时密钥没迁移——有些厂商直接在 1.0.x 的设备上刷 1.1 的固件,但根密钥还是旧的 AppKey,导致 NwkKey 缺失。嗯,这会导致入网失败。
总结一下:LoRaWAN 的密钥体系,说白了就是一套「最小权限原则」的落地。1.0.x 版本把网络和应用绑在一起,1.1 版本把它们拆开了。理解了这个演进逻辑,你就能明白为什么安全更新机制要这么设计——因为密钥的更新,本质上就是权限的重新分配。