EDIT: The below was my first attempt at session keys, but has since been replaced with an 'extension' library built off of the RFM69 core. See this thread:
https://lowpowerlab.com/forum/index.php/topic,966.0.html and my blog:
http://www.makethenmakeinstall.com/2015/03/session-key-support-for-arduino-with-rfm69-wireless-module/ for more information.
tl;dr - I've created some proof of concept sketches that implement a session key to prevent replay attacks. They can be found here:
https://github.com/dewoodruff/RFM69-session-token-ACKsThe RFM69 library from Felix is wonderful and I've been using it to get my feet wet into Arduino, but it was lacking one critical piece - being able to prevent wireless replay attacks. It is theoretically possible that an attacker could capture packets being sent to or from nodes (like those to open a garage), then replay them at a time of their choosing. Just encrypting the packet is not enough because an encrypted packet would have the same content every time, so the replayed packet would be accepted by the other end as if it were a new, legitimate request.
I've cobbled together a few sketches based on the the Node and Gateway examples that Felix provided in the RFM69 library to implement a session key. It works as follows:
1. The Node makes a connection request.
2. The Gateway generates a random 1 byte session key, stores it and the node's ID, then sends the key back to the node. Then it waits until a defined timeout for a response.
3. The Node receives the session key and adds it as the first byte in DATA. It appends whatever other data needs to be sent after the key, then sends it all back to the Gateway.
4. The Gateway receives the response. It checks to make sure the first byte of DATA matches the expected key and is from the correct sender, then processes the rest of the payload.
And of course, this is all useless if encryption isn't enabled
Pros:
- Provides reasonable protection against replay attacks. Helpful for sensitive transactions such as opening a lock or garage door.
Cons:
- While the gateway waits for a response to the original connection request it is deadlocked. There is the potential to miss connections from other nodes during this time which could be a problem on busy networks. Can possibly be worked around by tweaking ACK timeout thresholds and counts and keeping the connection timeout low, or some other logic.
- Not perfect protection. An attacker could theoretically still continuously try to guess the session key by sending a new connection request, then replaying the stored packet, hoping that the session key in the stored packet ends up matching what was just generated by the gateway. However, the gateway only generates a new session key once per timeout period, so the longer the timeout, the less frequently an attacker can guess. This could be made more difficult by using a longer session key, at the expense of payload size. Also, the attacker would have to know what the code was doing to know that this scenario even had a possibility of working.
I'd love some feedback on the sketches. Ultimately I'd like to port them into functions in the RFM69 library directly to simplify the code that has to be written directly in the sketch, however, this proof of concept was the easiest method for me to get it working. I am new to C++/Arduino so there are probably better ways to get this working. Please let me know what you think, and how difficult it might be to build directly into the RFM69 library. Thanks!