2、安全基础:对称加密与非对称加密、AES算法原理、CMAC消息认证码、密钥派生函数

聊LoRaWAN安全,绕不开这几个基础概念。我刚开始接触物联网安全时,觉得这些术语又抽象又枯燥。但后来在项目中踩过几次坑,才明白——这些基础不扎实,后面密钥管理根本玩不转。

说白了,LoRaWAN的整个安全体系,就是靠这几块积木搭起来的。咱们一块一块拆开看。

2.1 对称加密 vs 非对称加密

先搞清楚这两个东西的区别。你想想看,两个人要传递秘密消息,怎么办?

对称加密:加密和解密用同一个密钥。就像你和朋友共用一把钥匙开同一把锁。速度快,适合大量数据。但问题来了——这把钥匙怎么安全地交给对方?

非对称加密:有一对密钥——公钥和私钥。公钥公开,私钥自己藏好。别人用你的公钥加密,只有你能用私钥解密。安全是安全了,但速度慢,不适合大块数据。

对比项 对称加密 非对称加密
密钥数量 1个(共享密钥) 2个(公钥+私钥)
速度 快(硬件加速友好) 慢(数学运算复杂)
典型算法 AES、SM4 RSA、ECC
适用场景 数据加密、消息认证 密钥交换、数字签名
LoRaWAN中使用 核心加密(AES-128) 不直接使用

关键点:LoRaWAN终端资源极其有限(MCU主频几十MHz,RAM几十KB),所以全程采用对称加密——AES-128。非对称加密太重,跑不动。

我在一个项目中见过有人想在LoRa节点上跑RSA做密钥交换,结果单次加密耗时3秒多,电池直接崩了。嗯,后来老老实实改回预共享密钥方案。

2.2 AES算法原理

AES(Advanced Encryption Standard)是目前最主流的对称加密算法。LoRaWAN用的就是AES-128,密钥长度128位,分组大小也是128位。

我习惯把AES理解成一个「混乱+扩散」的加工流水线。输入128位明文,经过10轮(AES-128是10轮)操作,输出128位密文。

每一轮干四件事:

  1. SubBytes(字节代换)——用一个S盒把每个字节替换成另一个字节。非线性操作,抵抗数学攻击。
  2. ShiftRows(行移位)——把状态矩阵的行循环移位。扩散数据。
  3. MixColumns(列混合)——对每一列做矩阵乘法。进一步扩散。
  4. AddRoundKey(轮密钥加)——把这一轮的轮密钥和状态异或。密钥介入。

最后一轮没有MixColumns。记住这个细节,我在调试时因为搞错轮数吃过亏。

实战建议:不要自己实现AES。直接用硬件AES引擎(STM32、ESP32等都有)或经过验证的库(如mbedTLS、OpenSSL)。自己写的AES大概率有侧信道漏洞。

2.3 CMAC消息认证码

加密只能保证机密性,不能保证完整性。别人篡改了密文,你解密后得到的是垃圾数据,甚至可能被利用。

CMAC(Cipher-based Message Authentication Code)就是干这个的——用AES算法生成一个固定长度的认证标签,确保消息没有被篡改。

LoRaWAN里,CMAC无处不在:

  • Join-Request消息的MIC(消息完整性码)
  • 数据帧的MIC校验
  • 密钥派生过程中的中间值计算

CMAC的计算流程大致是:

1. 用AES-128加密全零块,得到子密钥K1和K2
2. 将消息分块(128位一块)
3. 最后一块不足128位时,补位后与K2异或
4. 最后一块满128位时,与K1异或
5. 逐块AES加密,最终输出128位CMAC值

我曾经踩过的坑:CMAC的补位规则和普通AES-CBC不一样。CMAC补的是"100...0"(先补1,再补0),而不是全零补位。搞错了MIC校验永远过不了,排查了我整整两天。

2.4 密钥派生函数

LoRaWAN里,终端和网络服务器不会直接使用预置的根密钥(AppKey/NwkKey)来加密数据。而是通过密钥派生函数(KDF),派生出会话密钥。

为什么这么做?

  • 密钥隔离:即使某个会话密钥泄露,也不会影响根密钥和其他会话密钥。
  • 密钥多样化:每次入网都生成不同的会话密钥。
  • 符合最小权限原则:应用数据密钥和网络数据密钥分开。

LoRaWAN 1.0.x和1.1.x的派生方式略有不同,但核心都是基于AES-CMAC的KDF。说白了就是:

会话密钥 = AES_CMAC(根密钥, 固定字符串 || 随机数 || 其他参数)

举个例子,LoRaWAN 1.0.x中派发AppSKey(应用会话密钥):

AppSKey = AES_CMAC(AppKey, 0x02 || JoinNonce || NetID || DevNonce || pad16)

其中0x02是固定标识符,JoinNonce/NetID/DevNonce是入网过程中交换的随机数。

核心原则:KDF的输入必须包含足够的熵(随机性)。如果JoinNonce或DevNonce可预测,派生的会话密钥就不安全。我在测试时见过有人把DevNonce写死成0x0000,结果所有终端都用同一个会话密钥——这跟没加密一样。

2.5 本章知识体系总览

下面这张图把本章的核心逻辑串起来了。我建议你多看几遍,搞清楚每个模块之间的依赖关系。

LoRaWAN安全基础:核心知识体系 对称加密 同一密钥加密/解密 非对称加密 公钥/私钥对 LoRaWAN选用 资源受限不适用 AES-128算法 10轮 SubBytes/ShiftRows/MixColumns/AddRoundKey CMAC消息认证码 基于AES的完整性校验 密钥派生函数 (KDF) AES_CMAC(根密钥, 固定字符串 || 随机数 || 参数) 输出:会话密钥 AppSKey / NwkSKey FNwkSIntKey / SNwkSIntKey

从图上可以看得很清楚:LoRaWAN选择对称加密(AES-128)作为核心,基于AES构建CMAC用于完整性校验,再以CMAC为基础实现密钥派生函数,最终派生出各类会话密钥。每一层都依赖下一层,环环相扣。

我的学习建议:先动手跑一遍AES-128的加解密示例(用Python的pycryptodome或C的mbedTLS),再手动算一次CMAC,最后模拟一次Join流程的密钥派生。纸上得来终觉浅,代码跑通才是真理解。