lora/lora-lorawan: Add LoRaWAN 1.0.x MAC layer#1111
Conversation
Add LoRaWAN Class A device operation with OTAA and ABP activation. Includes AES-128-CMAC/CTR crypto primitives built on ucryptolib for MIC calculation, payload encryption, and session key derivation per the LoRaWAN 1.0.x specification. Used by Pycom LoPy/LoPy4 boards as defined in micropython/micropython#19026. Signed-off-by: Danilo D <danilodt@gmail.com>
|
Hi @projectgus — gentle ping on the LoRaWAN side of the split. #1111 holds the |
projectgus
left a comment
There was a problem hiding this comment.
This is neat! A lot less code than I expected for a functional LoRaWAN Class A node as well, nice work.
I gave this a quick skim and put a few notes below. My main concern at this point is the same one raised in #1102 - we already have a LoRa modem driver API and we can't merge a second incompatible API.
If we can resolve that in #1102, and then this PR is made to work with that, then I think we'd be on a good path to getting this merged as well.
| return True | ||
|
|
||
| # RX2 window: JoinAcceptDelay2 at RX2 frequency/DR | ||
| sf, bw = _DR_TABLE_EU868[_RX2_DR] |
There was a problem hiding this comment.
Need a way to make data rates configurable rather than hardcoded to one region (for example, I'm in Australia so I legally cannot even test EU868 settings!)
| from lora import LoRa | ||
| from lorawan import LoRaWAN | ||
|
|
||
| radio = LoRa(frequency=868100000, sf=7, bw=125000) |
There was a problem hiding this comment.
This will need to work with the existing LoRa modem drivers as well. (See related discussion at #1102 (comment))
Specifically here: The existing drivers pass the hardware-specific config as constructor kwargs, but the LoRa radio settings are passed in a lora_cfg dictionary which is non-hardware-specific so it's easy to factor code to work with different modem drivers.
| if L[0] & 0x80: | ||
| K1 = _xor(K1, b"\x00" * 15 + b"\x87") | ||
| K2 = _shift_left_1(K1) | ||
| if K1[0] & 0x80: |
There was a problem hiding this comment.
I have some mild concern about whether any of these kind of branches create timing side channels.
Naive way to make this "constant time" would be perhaps
K2 = _xor(K2, b"\x00" * 15 + (b"\x87" if (K1[0] & 0x80) else b"\x00"))Whether this is actually better for timing would need to be measured.
Alternatively, mbedTLS has AES-CMAC support so we could expose the primitives from there via cryptolib. Pros: faster, not rolling own crypto. Cons: binary size would probably be higher, and on all boards... :/
| now = time.ticks_ms() | ||
| wait = time.ticks_diff(tx_end + delay_ms, now) | ||
| if wait > 0: | ||
| time.sleep_ms(wait) |
There was a problem hiding this comment.
Not asking for it in this PR, it would be interesting to see if this driver could be made async so an async task is blocking for the correct window to open, while the code is doing something else. (As async is non-preemptive this might turn out to not be tight enough on timing, though.)
| if (mhdr & 0xE0) != _MTYPE_JOIN_ACCEPT: | ||
| return False | ||
|
|
||
| from ucryptolib import aes |
There was a problem hiding this comment.
| from ucryptolib import aes | |
| from cryptolib import aes |
(We deprecated the u-prefix a couple of versions ago.)
Also please move all imports to the top, unless there's a runtime reason why this code path should be optional.
| """ | ||
| LoRaWAN cryptographic primitives (AES-128-CMAC, CTR, key derivation). | ||
|
|
||
| Uses ucryptolib.aes (AES-128-ECB) as the only hardware dependency. |
There was a problem hiding this comment.
| Uses ucryptolib.aes (AES-128-ECB) as the only hardware dependency. | |
| Uses cryptolib.aes (AES-128-ECB) as the only hardware dependency. |
(and same below)
Summary
Add
lora-lorawan: a LoRaWAN 1.0.x MAC layer for MicroPython.ucryptolibThe MAC layer is radio-agnostic: it consumes a
radioobject that exposesthe
lorasend/recv API. Tested with lora-sx127x-pycom on Pycom LoPy/LoPy4 boards.Split out of #1102 per @projectgus's request to
make the driver and the MAC layer reviewable independently.
Testing
ruff checkandruff formatRelated
lora-sx127x-pycom)