Author Topic: Example sketches - session key to prevent replay attacks  (Read 6618 times)

dewoodruff

  • Newbie
  • *
  • Posts: 17
Example sketches - session key to prevent replay attacks
« on: January 25, 2015, 05:48:23 PM »
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-ACKs

The 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!
« Last Edit: March 15, 2015, 11:41:57 AM by dewoodruff »

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 5481
  • Country: us
    • LowPowerLab
Re: Example sketches - session key to prevent replay attacks
« Reply #1 on: January 25, 2015, 06:25:54 PM »
Nice work, I wrote an article a while ago about wireless security issues, see the rolling code vulnerabilities section of the article here.

dewoodruff

  • Newbie
  • *
  • Posts: 17
Re: Example sketches - session key to prevent replay attacks
« Reply #2 on: January 28, 2015, 08:30:23 PM »
Thanks! I did read your article some time ago. For my attempt I chose to implement a connection handshake kind of like the three way handshake in TCP. It doesn't need to keep some piece of information in sync in perpetuity but rather it negotiates the key for each burst of information that is sent. The downside is the overhead of two non-data packets per piece of information the be transmitted but the positive is that there is no counter or time to keep in sync between the gateway and node.

I'll update the examples soon to pull the connection logic out into functions so that they could be easily copy/pasted into someone else's code without much effort. Hopefully someone else finds this useful!

TrendSetter

  • Newbie
  • *
  • Posts: 7
Re: Example sketches - session key to prevent replay attacks
« Reply #3 on: January 29, 2015, 08:05:30 AM »
The way i handled this is just including the lower two bytes of the current millis() into the packet before encryption/sending.  the receiving end doesnt look at those bytes, but it does ensure the payload is different every time, and adds relatively little overhead.
edit: i just realized that this does not prevent replay attacks.  its funny what causes you to think differently about things.
« Last Edit: January 29, 2015, 08:14:54 AM by TrendSetter »

TomWS

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1800
Re: Example sketches - session key to prevent replay attacks
« Reply #4 on: January 29, 2015, 08:06:02 AM »
<...snip>

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.

<snip...>
I personally don't have a need for this feature, but I do like that the connection is initiated by the node, which, in my view, spend the bulk of their time sleeping and have the data or need the data from the gateway.  The exceptions to this are control type nodes, (like Garage Door openers, to take a random example).

ISTM that the session key could be returned by the gateway in the Ack response to the connection request.  From what I've seen this is a little used but, IMO, a very valuable feature of the RFM69 library - that Ack can send data.  Also, if you dig into the library code, you will see that the library itself is capable of prepending the session key to the node's data packet within the sendFrame function so that, if the node has a new CTL bit set, enabling session key support, the whole transaction can be totally transparent to the node (other than losing one byte of payload).  The node would only have to call a new method to enable session key support.

There are spare CTL bits, but, as a head's up, I am currently using bit 5 in my own version of the library to control auto transmit level.  My updates will be submitted in the next month or so...

If you're interested, I can include a snippet of code that would handle the session key on the node end...  The gateway side would be somewhat different, of course...

Tom

dewoodruff

  • Newbie
  • *
  • Posts: 17
Re: Example sketches - session key to prevent replay attacks
« Reply #5 on: January 29, 2015, 03:38:16 PM »
The way i handled this is just including the lower two bytes of the current millis() into the packet before encryption/sending.  the receiving end doesnt look at those bytes, but it does ensure the payload is different every time, and adds relatively little overhead.
edit: i just realized that this does not prevent replay attacks.  its funny what causes you to think differently about things.

The only issue with this approach is that the receiving end doesn't have anything to verify to say that the incoming data is actually from a legitimate node, rather than being replayed by an attacker. It makes the data look different as it flies over the air, but if it were captured and replayed, the receiver will still process the data.

dewoodruff

  • Newbie
  • *
  • Posts: 17
Re: Example sketches - session key to prevent replay attacks
« Reply #6 on: January 29, 2015, 03:50:05 PM »
I personally don't have a need for this feature, but I do like that the connection is initiated by the node, which, in my view, spend the bulk of their time sleeping and have the data or need the data from the gateway.  The exceptions to this are control type nodes, (like Garage Door openers, to take a random example).

I was thinking about this situation as well and hope to implement a polling method to handle it. My backend is nodered based and I'm going to add MQTT soon, so I was thinking that when a command is initiated it would be published to a MQTT topic, then when the node checks in and polls for a command, nodered would poll the MQTT topic to see if it needs to send a command. Still working out the details... And that wouldn't be a good solution for when you want an immediate response to that command.

ISTM that the session key could be returned by the gateway in the Ack response to the connection request. From what I've seen this is a little used but, IMO, a very valuable feature of the RFM69 library - that Ack can send data.  Also, if you dig into the library code, you will see that the library itself is capable of prepending the session key to the node's data packet within the sendFrame function so that, if the node has a new CTL bit set, enabling session key support, the whole transaction can be totally transparent to the node (other than losing one byte of payload).  The node would only have to call a new method to enable session key support.

There are spare CTL bits, but, as a head's up, I am currently using bit 5 in my own version of the library to control auto transmit level.  My updates will be submitted in the next month or so...

If you're interested, I can include a snippet of code that would handle the session key on the node end...  The gateway side would be somewhat different, of course...

I would definitely be interested in an example. What you described is ultimately where I hoped to go - integrating it into the library, piggybacking on the ACK, so that all this is handled seamlessly. However I also see a value for "fire and forget" from a node to a gateway such as in reading temperature, so the gateway would have to handle both.

Dan

TomWS

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1800
Re: Example sketches - session key to prevent replay attacks
« Reply #7 on: January 29, 2015, 05:46:04 PM »
I personally don't have a need for this feature, but I do like that the connection is initiated by the node, which, in my view, spend the bulk of their time sleeping and have the data or need the data from the gateway.  The exceptions to this are control type nodes, (like Garage Door openers, to take a random example).

I was thinking about this situation as well and hope to implement a polling method to handle it. My backend is nodered based and I'm going to add MQTT soon, so I was thinking that when a command is initiated it would be published to a MQTT topic, then when the node checks in and polls for a command, nodered would poll the MQTT topic to see if it needs to send a command. Still working out the details... And that wouldn't be a good solution for when you want an immediate response to that command.
That's pretty much how I'm setting up my nodes, practically always sleeping and if the home server has something to deliver to the node, the server sends it to the gateway and the gateway queues it up and keeps track that it's 'gotSomething' for the node.  Then, on the next post from the node, the GW sees that it's got 'something' for the node and signals this (along with the type of 'something') in its Ack to the node's send.  The node can then decide if it wants to wait around for the something or defer it to another time.  If it's willing to accept the 'something', then it sends a request along with the 'something's id, stays awake longer than normal, and the GW passes the 'something' back to it.  This is how I'll do wireless program updates, for example, the 'something' in this case will be individual program update records.  The node can fetch as many as it's willing to grab without draining its battery and then come back for more at a later time.  It will take a long time for an update but I don't much care if it takes even 24 hours to ship out a code update.  Once deployed, nodes shouldn't need updates very often...

A good example of a 'control' type node that I have is my sprinkler valve.  It takes a lot of energy to flip on or off the DC Latching solenoid but it doesn't happen very often so battery operation is entirely plausible.  There are two exceptions to this case, however, first, when you're testing the sprinkler system you want to turn the valves on and off relatively quickly.  In the other case, once a valve is ON then you sure don't want to wait hours to turn it off again  :D   So the polling interval will be variable based on whether the valve is on or off. Or, in the testing case, the server can temporarily override the polling interval.  The neat thing about sprinklers in general is that their operation is generally predictable even up to 24 hours in advance so, with a programmable interval, you can get responsiveness without consuming battery life.

ISTM that the session key could be returned by the gateway in the Ack response to the connection request. From what I've seen this is a little used but, IMO, a very valuable feature of the RFM69 library - that Ack can send data.  Also, if you dig into the library code, you will see that the library itself is capable of prepending the session key to the node's data packet within the sendFrame function so that, if the node has a new CTL bit set, enabling session key support, the whole transaction can be totally transparent to the node (other than losing one byte of payload).  The node would only have to call a new method to enable session key support.

There are spare CTL bits, but, as a head's up, I am currently using bit 5 in my own version of the library to control auto transmit level.  My updates will be submitted in the next month or so...

If you're interested, I can include a snippet of code that would handle the session key on the node end...  The gateway side would be somewhat different, of course...

I would definitely be interested in an example. What you described is ultimately where I hoped to go - integrating it into the library, piggybacking on the ACK, so that all this is handled seamlessly. However I also see a value for "fire and forget" from a node to a gateway such as in reading temperature, so the gateway would have to handle both.

Dan
I'll see if I can cobble together a strawman in a day or two.  To my mind it would be a decision on the node's part to have packets controlled by session keys or not.  This would be completely backward compatible.

TomWS

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1800
Re: Example sketches - session key to prevent replay attacks
« Reply #8 on: January 30, 2015, 08:15:03 AM »
<...snip>
I would definitely be interested in an example. What you described is ultimately where I hoped to go - integrating it into the library, piggybacking on the ACK, so that all this is handled seamlessly. However I also see a value for "fire and forget" from a node to a gateway such as in reading temperature, so the gateway would have to handle both.

Dan
I'll see if I can cobble together a strawman in a day or two.  To my mind it would be a decision on the node's part to have packets controlled by session keys or not.  This would be completely backward compatible.
Dan, I'm going to back off my statement that this is 'easy'.  I do think on the Node side it can be easy and essentially invisible to the Node (other than enabling session key support).  However, as I thought about the gateway end, I had the 'oopsie' revelation that Gateways need to support multiple simultaneous sessions and all of a sudden the gateway side became much more involved than a simple 1:1 implementation would be.  Consequently, as I said, I'm going to awkwardly back out of this for the time being...
 :-[

Tom

dewoodruff

  • Newbie
  • *
  • Posts: 17
Re: Example sketches - session key to prevent replay attacks
« Reply #9 on: February 05, 2015, 08:43:56 PM »
Dan, I'm going to back off my statement that this is 'easy'.  I do think on the Node side it can be easy and essentially invisible to the Node (other than enabling session key support).  However, as I thought about the gateway end, I had the 'oopsie' revelation that Gateways need to support multiple simultaneous sessions and all of a sudden the gateway side became much more involved than a simple 1:1 implementation would be.  Consequently, as I said, I'm going to awkwardly back out of this for the time being...
 :-[

Tom

No worries! I still plan to give it an attempt myself. For my purposes I don't have the requirement of multiple simultaneous sessions. I'm good with letting one transaction block another. I'm sure I'll run into other complications along the way but I just need to find the time to sit down and put some serious work into it. Might be a few months until I have something to share... but I will be back!
Dan

dewoodruff

  • Newbie
  • *
  • Posts: 17
Re: Example sketches - session key to prevent replay attacks
« Reply #10 on: March 01, 2015, 06:14:49 PM »
Here's what I've come up with to directly integrate session key support into the library. Session keys can be seamlessly enabled by putting useSessionKey(1) in the sketch. I've tested these configurations, both with 'send' and 'sendWithRetry' using the Node and Gateway example sketches:
  • both gateway and node with session key disabled
  • both gateway and node with session key enabled
  • gateway enabled, node disabled - works as expected, allowing "fire and forget" messages from nodes that don't require session keys. However, the gateway cannot initiate a new connection to send data to the node because the gateway will try to initiate a new session, but the node will not be enabled, so it will never handshake a key.
  • gateway disabled, node enabled - does not work, as expected, because the nodes can't handshake a key.
I have NOT tested anything with remote firmware uploads or anything more advanced than the example sketches.

The git diff is here: https://github.com/dewoodruff/RFM69/commit/26246e436a2b5b1acc529e04281a128ab282d30a
I'd love some feedback - please tear it apart! After I post this I'm going to start uploading to my production gateway and nodes.

Dan

Felix

  • Administrator
  • Hero Member
  • *****
  • Posts: 5481
  • Country: us
    • LowPowerLab
Re: Example sketches - session key to prevent replay attacks
« Reply #11 on: March 01, 2015, 07:24:51 PM »
Dan, thanks for the contributions.
I would consider these extra features and so I would propose including these in a separate library that inherits from RFM69.h.

TomWS

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1800
Re: Example sketches - session key to prevent replay attacks
« Reply #12 on: March 01, 2015, 07:57:20 PM »
Dan, thanks for the contributions.
I would consider these extra features and so I would propose including these in a separate library that inherits from RFM69.h.
So the separate library would extend RFM69 and override the sendFrame method and Interrupt handler? 

Makes sense on the sendFrame method, but it might be better to provide 'hook' that the Interrupt handler escapes to, if enabled.  I need to think about this, but given that I also have 'extensions' that aren't necessarily compatible with this proposal, your suggestion might be the best way to deal with both...

I need to think on this... another scotch, please.

Tom

kobuki

  • Sr. Member
  • ****
  • Posts: 282
Re: Example sketches - session key to prevent replay attacks
« Reply #13 on: March 01, 2015, 08:39:44 PM »
Dan, an interesting approach at preventing replay attacks. There are many ways to solve this, and I think it's essentially an algoritmical problem, rather than something specific to microcontrollers. I also think if your communication scheme is similar to what Tom uses, it's probably just fine. You're probably aware that your key is not a "session key"  but rather a "message unique key", since to repel this kind of attack, you need a new key for every message.

I've pondered the same idea several times, though haven't implemented it yet. My approach is simpler, and relies on serial numbers. Sorry if this post becomes long, please feel free to throw it out into a new thread. I don't want to hijack yours, but I thought an exchange of ideas on the subject is the right place here.

So, my approach would be: similar to your session key, each and every packet contains a serial number, which is stored and consequently transmitted encoded before or after the payload, together with an additional encoded, fixed node ID. The serial number is strictly monotonic increasing, this must be ensured by the sender, however the difference between subsequent serial numbers is not important. It can be practically incremented by one every time a new packet is sent. There is one problem to solve: what about reboots? We assume for now that the serial is 32 bits. We have EEPROM of course, so we can store a 16-bit prefix (high 16 bits) in nonvolatile storage. At every reboot of the node, the prefix must be incremented by one. The lower 16 bits are simply incremented on the fly and stored in a static variable. Should it overflow, we increment the stored prefix. This simple algoritm ensures we always have a node-local independent serial number.

There are 3 main attack vectors: first is the AES encryption key which is a shared secret between the nodes and the gateway. In practice its impossible to guess, let alone compute the correct one in a timely manner. The second is the serial. It can easily be guessed but without the key it's irrelevant. The 3rd is jamming/modifying the radio comms, but its usefullness is only equal to DOS (denial of service) or to delaying certain packets.

The gateway only needs to verify the node ID, the monotonicity criterion and of course the CRC, but this latter is done by the module itself, and from security and data integrity perspective it's far from ideal but let's just skip it for now. The node ID + serial number together forms a globally unique ID (GID) for every packet sent in a given system, so it's not possible to simply replay any of them. Naturally the GW needs to keep track of the serial for every node. Other benefits are that it can be used in one-way communication scenarios because the GID is independent of the gateway. This enables less frequent wake-ups, less radio comms and more sleep for a mote.
« Last Edit: March 01, 2015, 08:42:11 PM by kobuki »

TomWS

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1800
Re: Example sketches - session key to prevent replay attacks
« Reply #14 on: March 01, 2015, 11:31:01 PM »
Kobuki, I'm not sure how your proposal is immune from the inevitable missed connection.  Further, I don't see how Dan's proposal is weak WRT to the stated goal, which is to eliminate the possibility of replay attacks, which, I believe, is the main exposure with the current encryption scheme. 

The advantage of Dan's scheme is that it requires an interchange, which, by its very nature, is unique and, under the covers of encryption, totally immune from replay.  Any single exchange method requires an implied synchronization that would be very hard, if not impossible, to maintain in a Moteino environment.  The one aspect of Dan's implementation that might be considered weak is the fact that it uses Arduino's non-random random function.  But that could be easily addressed and probably isn't too serious as each session is still sufficiently unique in the context of someone monitoring 'garage door' openings - it probably wouldn't be acceptable for Fort Knox, however  ;)

What am I missing from your suggestion?

Tom