3、LoRaWAN安全机制:Join过程、AppKey与NwkKey、会话密钥派生
聊LoRaWAN安全,很多人第一反应就是“AES加密”。但说实话,加密只是最后一步。真正决定安全性的,是设备怎么入网、密钥怎么来的。我早年调试一个水表项目时,就因为Join过程没走对,结果设备死活发不出数据——后来发现是会话密钥根本没派生成功。嗯,今天我们就来把这套机制彻底捋清楚。
3.1 为什么需要Join过程?
LoRaWAN设备不是插电就能用的。它必须先跟网络服务器“握手”,拿到一组临时密钥,才能开始通信。这个握手过程,就叫Join。
你想想看,如果每个设备都用同一个固定密钥加密,那一旦密钥泄露,整个网络就完了。所以LoRaWAN设计了一套动态密钥派生机制:每次入网都会生成新的会话密钥,即使这次被破解,下次入网又会换一套。
核心思想: 长期密钥(AppKey/NwkKey)只用于入网认证,不用于数据加密。数据加密用的是每次入网临时派生的会话密钥(AppSKey/NwkSKey)。
3.2 两个长期密钥:AppKey与NwkKey
在LoRaWAN 1.0.x版本中,只有一个根密钥叫AppKey。但从1.1版本开始,为了安全分离,拆成了两个:NwkKey和AppKey。
| 密钥名称 | 长度 | 用途 | 存储位置 |
|---|---|---|---|
| NwkKey | 128位(AES-128) | 网络层密钥,用于Join过程完整性校验、派生NwkSKey | 设备 + 网络服务器 |
| AppKey | 128位(AES-128) | 应用层密钥,用于派生AppSKey | 设备 + 应用服务器 |
我个人习惯把NwkKey理解为“网络身份证”,AppKey理解为“应用保险箱钥匙”。两者分开后,即使网络服务器被攻破,攻击者也拿不到AppKey,应用数据依然是安全的。
注意: 在LoRaWAN 1.0.x中,只有一个AppKey,同时承担网络和应用的双重职责。升级到1.1后,务必确认你的网络服务器和应用服务器是否支持双密钥模式。我曾经见过一个项目,服务器端还是1.0的固件,设备端烧了1.1的密钥,结果Join永远失败。
3.3 Join过程的完整流程
Join过程说白了就是一次“密钥交换握手”。设备发送Join Request,服务器回复Join Accept,然后双方各自派生出会话密钥。
3.3.1 第一步:设备发送Join Request
设备上电后,会组装一个Join Request消息,包含以下字段:
- DevEUI:设备唯一标识,类似MAC地址,全球唯一。
- AppEUI(或JoinEUI):应用标识,告诉服务器“我想加入哪个应用”。
- DevNonce:一个随机数,用于防止重放攻击。
整个消息会使用NwkKey计算一个MIC(消息完整性校验码),附在末尾。服务器收到后,会用同样的NwkKey重新计算MIC,如果对不上,直接丢弃。
避坑指南: DevNonce必须保证每次入网都不一样。我曾经遇到一个客户,设备代码里DevNonce生成逻辑写错了,每次上电都生成同一个值。结果服务器认为这是重放攻击,直接拒绝入网。折腾了两天才找到原因。
3.3.2 第二步:服务器验证并回复Join Accept
网络服务器收到Join Request后,会做三件事:
- 验证MIC是否正确(用NwkKey)。
- 检查DevNonce是否重复(防止重放)。
- 生成一个AppNonce(服务器随机数),用于后续密钥派生。
然后服务器组装Join Accept消息,包含AppNonce、网络参数(如频段、速率等),同样用NwkKey计算MIC。这个消息会加密后发给设备。
3.3.3 第三步:双方派生会话密钥
设备收到Join Accept后,用同样的NwkKey解密并验证MIC。验证通过后,双方就可以用相同的算法派生出会话密钥了。
3.4 会话密钥派生:AppSKey与NwkSKey
派生算法用的是AES-128的CMAC模式。说白了,就是把AppNonce、DevNonce等参数拼在一起,用NwkKey或AppKey做AES加密,输出就是会话密钥。
具体公式如下(LoRaWAN 1.1版本):
// NwkSKey 派生(使用 NwkKey)
NwkSKey = aes128_cmac(NwkKey, 0x01 || AppNonce || DevNonce || ...)
// AppSKey 派生(使用 AppKey)
AppSKey = aes128_cmac(AppKey, 0x02 || AppNonce || DevNonce || ...)
这里有个细节:0x01和0x02是区分符,确保NwkSKey和AppSKey不会算出相同的值。我当年第一次看协议时,还纳闷为什么加个固定字节——后来自己写代码时才发现,不加这个区分符,两个密钥可能一模一样,那就出大问题了。
| 会话密钥 | 长度 | 用途 | 派生源 |
|---|---|---|---|
| NwkSKey | 128位 | 网络层:校验数据包完整性(MIC)、加密MAC命令 | NwkKey |
| AppSKey | 128位 | 应用层:加密/解密应用数据(传感器数据、控制指令等) | AppKey |
重要原则: NwkSKey只存在于设备和网络服务器之间,AppSKey只存在于设备和应用服务器之间。网络服务器不应该知道AppSKey,应用服务器也不应该知道NwkSKey。这样即使一方被攻破,另一方数据依然安全。
3.5 密钥的生命周期管理
会话密钥不是永久的。每次设备重新入网(重新Join),都会生成新的会话密钥。旧的会话密钥立即失效。
但长期密钥(NwkKey和AppKey)是设备出厂时烧录的,理论上终身不变。所以:
- 出厂阶段:在安全环境中将NwkKey和AppKey写入设备。
- 运行阶段:设备每次入网,动态派生会话密钥。
- 密钥更新:如果需要更换长期密钥,只能通过物理接触设备(比如用串口重新烧录)。
安全提醒: 千万不要把NwkKey或AppKey通过无线方式传输!我见过一个方案,为了“方便管理”,在设备入网后通过下行命令把AppKey读回来——这等于把保险箱密码写在门上。正确的做法是:长期密钥只在出厂时写入,之后永远不出设备。
3.6 小结:一张图看懂密钥体系
最后,我用一张图总结整个LoRaWAN密钥体系的关系:
嗯,到这里,LoRaWAN的Join过程和密钥体系就讲完了。记住一句话:长期密钥保安全,会话密钥保通信。下次你调试设备入网失败时,先检查DevNonce是否重复,再检查MIC计算是否正确——这两个坑,我踩过不止一次。