LoRaWAN 1.0.2 Session Key Security I am reading about LoRaWAN 1.0.2 specification. For the confidentiality and integrity of the comunication the protocol generate two session keys, the NwkSKey and the AppSKey (part 6.2.5 of the specification, page 35).

Both, application and network session keys are derived like following, the only difference is the first component (0x01 and 0x02):

AppSKey = aes128_ecb_encrypt(AppKey, 0x02 | AppNonce | NetID |DevNonce | pad_16 )



0x02 is a costant of 8 bit.
AppNonce is a nonce generated by network server of 24 bit.
NetID is network identifier of 24 bit and not change if the join procedure is related on the same network.
DevNonce is a nonce generated by end-device of 16 bit.
The pad_16 function appends zero octets so that the length of the data is a multiple of 16.


I'm not sure of the robustness of this key derivation. Is the variable part inside the block being encrypted not just 40 bits? Furthermore, if you use the same AppSKey for a long period, even 3/4 years, is the solution still robust?

Furthermore, the DevNonce is sent from the end-device in the join request message and the message is not encrypted.
aes128_ecb_encrypt (the AES block cipher in the forward direction) is a pseudorandom permutation family: if the adversary doesn't know the key, then knowing the output corresponding to some inputs doesn't help to find the output corresponding to some other input. In other words, the only way to find AppSKey for a given AppKey is to convince someone who knows AppKey to calculate and publish the value of AppSKey for that exact input (same AppNonce, same NetID and DevNonce).

Therefore the potential problems with the protocol are:


Can users who share an AppKey be convinced to repeat both AppNonce and DevNonce within the same NetID?
Can this use of AppKey result in calling the AES permutation with the same inputs as other uses of AppKey?


1. Nonce repetition

Nonce repetition needs to be done on both sides. AppNonce is a 24-bit value, so if it's chosen at random, it'll likely repeat at least once within a little over $2^{12} \approx 4000$ attempts (birthday paradox). DevNonce is a 16-bit value which is supposed to be random, so it'll likely repeat at least once within a little over $2^8 = 256$ attempts (§6.2.4). But since the two nonces are chosen by different devices, the probability that one nonce repeats is independent from the probability of the other nonce repeating. If AppNonce is genuinely random then to get a good chance of repeating you need about $2^{20} \approx 1,000,000$ attempts. At 11kbit/s, which is the nominal maximum bandwidth, you could go through this in a day, if the device's battery is up to it.

If the nonces are repeated, they'll end up using the same AppSKey. AppSKey is used for unauthenticated encryption with CCM*. Unauthenticated CCM* is CTR with a choice of initial counter value that ensures that counter values won't repeat if the CCM* IV doesn't repeat. So in order to get a block to repeat, you need to arrange not only for the key to repeat, but also the IV. Since the IV is calculated in a simple way from constant device characteristics and the frame count (§4.3.3), each session uses the same IV sequence. So if two sessions use the same AppSKey, then the corresponding messages in these sessions will be encrypted with the same mask. This reveals the xor of each pair of corresponding messages.

Uses of AppKey

In addition to the derivation of AppSKey, AppKey is also used to calculate integrity values (MIC) for join messages (§6.2.4) and join-accept messages (§6.2.5), to derive NwkSKey (§6.2.5), and to encrypt join-accept messages (§6.2.5).


NwkSKey is derived in the same way as AppSKey except with the prefix 0x01 instead of 0x02.
MIC are CMAC calculations. CMAC uses AES in the encryption direction, with inputs that are the result of xor-ing successive input blocks with an intermediate result that's an AES output. The intermediate result is not published.
The join-accept message is calculated by decrypting a block of data.


I don't see an obvious way to get the inputs to collide, but this would require extensive analysis.