This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
[Bug]: nonces are only randomized with 31 bits, this make it rare but possible to see duplicated nonces in the wild threatening confidentiality of messages #4031
Labels
bug
Something isn't working
Category
Other
Hardware
Not Applicable
Firmware Version
current
Description
The IV initialization looks incorrect, it use 96 bits IV, but ~65* of them are fixed, so only ~31* bits are randomized.
It used to be stored in flash but apparently this did not worked (see 5a4fab2).
It now picks a random 31 bits number together with the lower 32bits of the mac address:
firmware/src/mesh/Router.cpp
Line 105 in b43c7c0
firmware/src/mesh/CryptoEngine.cpp
Lines 30 to 37 in b43c7c0
The crypto code use 64 bits packet ids, but the packet id type is defined as 32 bits:
firmware/src/mesh/MeshTypes.h
Line 10 in b43c7c0
There is then a zero-extension when calling encrypt:
firmware/src/mesh/Router.cpp
Line 424 in b43c7c0
If you use a 64bits number but 33 of them are fixed, you only gain 31 bits of security.
Due to the birth paradox assuming the randomness source is good you would need ~58k reboots to reach a 50% duplicate nonce chance on one node. This does not cause an issue across nodes because they each have a different nodeid.
The number of reboots is lower because each messages then incrementally update the packet id, so a reboot might only consume a handful of nonces or many thousands depending on how many messages were sent.
Given there are many thousand nodes each rolling for theses odds independently it is likely a some of duplicate nonces will be used some day if they weren't already.
The consequences of duplicated nonces with AES-CTR is that it becomes possible to perform known plaintext attack to decrypt one message knowing the other.
This is way worst than it sounds because it is possible to bruteforce each bit independently. That means if we know a tiny bit about the structure of the message (which for meshtastic we do, they are often nodeinfo, or chat messages) we can extend our guess with new information gained.
Independent information like exact GPS positions or Battery % are unlikely to be recoverable.
But we know chat messages are likely UTF8 and likely to form meaningful sentences, so you could bruteforce character by character until it makes meaningful words and sentences, this should be easy to do on a modern CPU and trivial on a modern GPU.
Combined with #4030 attack, you could replay a malicious with a custom content. Upside because there is no MAC or AEAD it's impossible to know if you are actually correct in your complete guess, so completely random pieces of information like arbitrary numbers or GPS position would be hard to impossible to confidently break if they align.
If one message is shorter than the other, only the shared length can be decrypted.
Because nonces are incremented sequentially, you wouldn't get a random duplicates from time to time.
You would see all overlapped messages back-to-back duplicates.
Checking for duplicated nonces is trivial, the nodeid and packetid are sent in plaintext (which is normal, there is hardly a way around that within meshtastic's tradeoffs context).
This could be improved by using a duplicate nonce resistant cipher like
AES-GCM-SIVor deriving the nonce from the message hash or many other things. This looks like it would be a breaking change either way.*I say ~65bits because it is possible to roll something in the high 31 bits then the message increment would roll into 32 bits.
So 64 out of 96 bits are fixed, 31 bits are randomized and 1 is very likely to be 0.
Relevant log output
The text was updated successfully, but these errors were encountered: