TL;DR: Looking for advice on node-to-node authentication / access control / data integrity, preferably agnostic to microcontroller platform and communication transport.
Like many, I have a long list of potential projects that I want to work on, and several of them are for home-automation. One example is the common garage door opener. Hardware-wise, this is simple. And really, it could be simple on the software side, too. But I want to keep security in mind, and that’s where it gets more complicated.
Another project I have in mind is to distribute temperature sensor nodes in my house, and control our thermostat based on data from rooms other than where the main control panel is located, and perhaps even on last-known motion detection in different locations.
My first thought was, everything will run through our WiFi, which is protected with WPA2, and we use pretty strong passwords on our wifi, so it should be safe enough from the casual wardriver. But for one thing, even WPA2 isn’t beyond cracking, and for another, what if one of my kids loses their iPod, which automatically connects to our wifi? I don’t want to rely on a false equivalence of “connected to my wifi” == “authenticated user”.
So I’m trying to think of ways to do further authentication and access control. I did do a little bit of Googling, but I didn’t turn up any ready-made libraries, or even much in the way of generic articles.
For a garage door opener, the communication is likely to happen between a phone and a webserver (probably running on a RasPi). Securing that is easy, because I can use SSL without any limitations, and I can even set up per-user authentication with logins, if desired.
What I’m more curious about is securing node-to-node controls. In my example of a multi-node thermostat control, I don’t want a guest on my wifi network (or worse, a hacker) to be able to spoof sensor readings and send my A/C or heater to extremes, and run up my power bill. Also, for node-to-node communications, I’m thinking it might be good to keep things independent of the transport protocol – I might have nodes using 433MHz modules or serial, instead of WiFi, for example.
I might be over-thinking things, but in quickly jotting down some ideas off the top of my head, I came up with a 5-way handshake. Imagine we have a Controller, responsible for receiving and storing data from a collection of Nodes. The Controller and Nodes will have a shared secret (password) used to help verify messages. They will also share a hashing algorithm of some sort, probably something like HMAC-SHA1. The Node and Controller will exchange randomly(?) generated keys in each conversation, to help avoid replay attacks.
Node: "START: I am Node X, rndkey Y"
Controller: “ACK: Hello X, I am C, rndkey Z”
Node and Controller both compute a session key (sesskey) based on their shared secret, X, C, Y, and Z:
sesskey = hmacsha1( secret, (X + C + Y + Z)), or something like that
Node: "DATA: sesskey, data"
Controller: "ACK: termid_c = hmacsha1(secret, (sesskey + data))
Node: "BYE: termid_n = hmacsha1(secret, (termid_c + data))
At this point, the Controller has fully verified that the communication session was authentic, and both Controller and Node agree on the value of the data that the Node sent, and it can save or otherwise process that data. If any of the keys fail to match (
FAIL message would be sent, and the Node would need to restart with a new
START packet, giving up after some set number of retries.
+ operator above could be just simple addition,
xor, concatenation, or whatever, as long as both C and N compute it in the same way.
Note that this is not encrypting the communications, it’s just providing message authentication via the shared secret key. Also, we often see a 3-way handshake (like when opening a TCP/IP socket). But I wanted to also verify integrity of the data sent from the Node to the Controller.
Also, I’m just using HMAC-SHA1 as an example. It could use some other algorithm, and to cut down the number of bytes sent, maybe it could even just send a CRC32 of that value for verification. Obviously, that reduces the security, but for this purpose I think it would still suffice.
Any thoughts? Any gotchas? Does anyone know of an already-existing library for end-to-end session authentication and data integrity verification? Or should I just start coding this up?