MySensors Library & Examples  2.3.2
Modules
+ Collaboration diagram for Message signing:

Detailed Description

The message signing infrastructure provides message authenticity to users by signing MySensors messages.

Signing support created by Patrick "Anticimex" Fallberg.

Table of contents

How to use this
Whitelisting and node revocation
Known limitations
Typical use cases
The technical stuff
Background and concepts
How this is done
Why encryption is not part of this

How to use this

Before we begin with the details, I just want to emphasize that signing is completely optional and not enabled by default.

If you do want the additional security layer signing provides, you pick the backend of your choice in your sketch. Currently, two compatible backends are supported; MY_SIGNING_ATSHA204 (hardware backed) and MY_SIGNING_SOFT (software backed). There also exist a simplified variant (MY_SIGNING_SIMPLE_PASSWD) of the software backend which only require one setting to activate.

If you use hardware backed signing, then connect the device as follows:

Note
The pull-up resistor is optional but recommended.
If you change the default pin (A3) make sure you use a pin that supports input/output (ex. A6 & A7 on a Pro Mini are input only pins).

To use signing, you need to perform three major steps which are described below.

Firstly, you need to make sure to pick a backend to use.

//#define MY_SIGNING_SOFT
//#define MY_SIGNING_SIMPLE_PASSWD
#define MY_SIGNING_ATSHA204
#include <MySensors.h>
...

Make sure to set the define before the inclusion of MySensors.h. It is ok to mix MY_SIGNING_SOFT and MY_SIGNING_ATSHA204 in a network. They are fully compatible. It is however not recommended to use MY_SIGNING_SOFT on nodes that are publicly accessible (more on that later).

If you use MY_SIGNING_SOFT or MY_SIGNING_ATSHA204 you also need to decide if the node (or gateway) in question require messages to be signed in addition to the ability to generate signatures for other nodes. This has to be set by at least one of the nodes in a "pair" or nobody will actually start calculating a signature for a message. Just set the flag MY_SIGNING_REQUEST_SIGNATURES and the node will inform the gateway that it expects the gateway to sign all messages sent to the node. Note that when set in a gateway, the gateway will require ALL nodes in the network to sign messages. If this behaviour is undesired, enable the flag MY_SIGNING_WEAK_SECURITY which will allow the gateway to only require signatures from nodes that in turn require signatures. It will also allow the gateway (and all nodes) to "downgrade" security by clearing the signing/whitelisting requirements (whitelisting is described later on in the Whitelisting and node revocation section) in the EEPROM if a node presents itself as not having any security requirements. If MY_SIGNING_WEAK_SECURITY is not set, any node that has presented itself with signing/whitelisting requirements will be permanently marked as such by the receiver (typically the gateway). The only way then to reset/revert this requirement is to clear the EEPROM at the receiver (or disable MY_SIGNING_REQUEST_SIGNATURES, but the preference will be remembered if the request flag is re-enabled before EEPROM is cleared).
If you want to have two nodes communicate securely directly with each other, the nodes that require signatures must send a presentation message to all nodes it expect signed messages from (only the gateway is informed automatically). See signerPresentation().
A node can have three "states" with respect to signing:

  1. Node does not support signing in any way (neither MY_SIGNING_ATSHA204, MY_SIGNING_SOFT nor MY_SIGNING_SIMPLE_PASSWD is set)
  2. Node does support signing but don't require messages sent to it to be signed (neither MY_SIGNING_REQUEST_SIGNATURES nor MY_SIGNING_SIMPLE_PASSWD is set)
  3. Node does support signing and require messages sent to it to be signed (MY_SIGNING_SOFT or MY_SIGNING_ATSHA204 together with MY_SIGNING_REQUEST_SIGNATURES or MY_SIGNING_SIMPLE_PASSWD are set)

Secondly, you need to verify the configuration for the backend.
For hardware backed signing it is the pin the device is connected to. In MyConfig.h there are defaults which you might need to adjust to match your personal build. The setting is defined using MY_SIGNING_ATSHA204_PIN.
If you use an official MySensors board (like the SenseBender GW) you do not need to set the pin, this is configured automatically by the Arduino board definition files.

Similar to picking your backend, this can also be set in your sketch:

#define MY_SIGNING_ATSHA204
#define MY_SIGNING_ATSHA204_PIN 4
#define MY_SIGNING_REQUEST_SIGNATURES
#include <MySensors.h>
...

For the software backed signing backend, an unconnected analog pin is required on boards that does not provide a hardware based random generator unit to set a random seed for the pseudo-random generator. It is important that the pin is floating, or the output of the pseudo-random generator will be predictable, and thus compromise the signatures. The setting is defined using MY_SIGNING_SOFT_RANDOMSEED_PIN. The same configuration possibilities exist as with the other configuration options.

#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
#define MY_SIGNING_REQUEST_SIGNATURES
#include <MySensors.h>
...

An example of a node that require signatures is available in SecureActuator.ino.

Thirdly, if you use a signing backend and you don't use MY_SIGNING_SIMPLE_PASSWD, you need to personalize the node.

If you use the ATSHA204A (MY_SIGNING_ATSHA204), before any signing operations can be done, the device needs to be personalized. This can be a daunting process as it involves irreversibly writing configurations to the device, which cannot be undone. I have however tried to simplify the process as much as possibly by creating a helper-sketch specifically for this purpose in SecurityPersonalizer.ino Note that you also need to do personalization for MY_SIGNING_SOFT, but then the values are stored in EEPROM.

To personalize a ATSHA204A do the following procedure:

  1. Enable GENERATE_KEYS_ATSHA204A
    This will lock the ATSHA204A and generate random keys for HMAC (signing) and AES (encryption). Copy the keys generated and replace the corresponding definitions under "User defined key data", specifically MY_HMAC_KEY and MY_AES_KEY.
  2. Disable GENERATE_KEYS_ATSHA204A and enable PERSONALIZE_ATSHA204A
    This will store the HMAC key to the ATSHA204A and the AES key to EEPROM. It will also write a checksum of the personalization data in EEPROM to be able to detect if the data is altered.
    Personalization is now complete.

To personalize for software signing do the following procedure:

  1. Enable GENERATE_KEYS_SOFT
    This will generate random keys for HMAC (signing) and AES (encryption). Copy the keys generated and replace the corresponding definitions under "User defined key data", specifically MY_HMAC_KEY and MY_AES_KEY.
  2. Disable GENERATE_KEYS_SOFT and enable PERSONALIZE_SOFT
    This will store the HMAC key and the AES key to EEPROM. It will also write a checksum of the personalization data in EEPROM to be able to detect if the data is altered.
    Personalization is now complete.

If you want to use soft signing and you want to use whitelisting (the ability to revoke/ban compromised nodes in the network) and your target does not provide a unique device ID, you have to generate a unique serial and store it in EEPROM. This can be done by replacing PERSONALIZE_SOFT in step 2 above with PERSONALIZE_SOFT_RANDOM_SERIAL. See the output under "Hardware security peripherals" to determine if this is necessary.

When you have personalized your first device after step 2 above, you can run the same sketch on all devices in your network that needs to be personalized in a compatible manner. Pick PERSONALIZE_ATSHA204A or PERSONALIZE_SOFT as needed by the hardware. When the personalization has finished, you just program the sketch you plan to use (with the appropriate signing flags set).

If you are using a Raspberry PI-based gateway, personalizaion is done slightly differently:

  1. Generate keys, execute mysgw with arguments
    • To generate HMAC key
      --gen-soft-hmac-key 
    • To generate AES key
      --gen-aes-key 
    • To generate a soft serial number
      --gen-soft-serial 
  2. Update the gateway config file with the generated keys/valeus
    • For HMAC key
      soft_hmac_key=<DATA> 
    • For AES key
      aes_key=<DATA> 
    • For soft serial number
      soft_serial_key=<DATA> 

You are now set and ready to use message signing in your network. As of now, the following restrictions will be applied to your nodes:

Whitelisting and node revocation

Consider the situation when you have set up your secure topology. We use the remotely operated garage door as an example:

In this setup, your keyfob can securely transmit messages to your door node since the keyfob will sign the messages it sends and the door node will verify that these were sent from a trusted node (since it used the correct PSK). If the keyfob does not sign the messages, the door node will not accept them. Optionally, your keyfob sends a signed message to your gateway (which require signatures) and the gateway in turn sends a signed message to your garage door.

One day your keyfob gets stolen or you lost it or it simply broke down.

You now end up with a problem; you need some way of telling your door node that the keyfob in question cannot be trusted any more. You could now repersonalize all your node to switch to a different PSK but this obviously is a hassle. How do you make sure that the "rogue" keyfob can be removed from the "trusted chain"?

The answer to this is whitelisting. You let your door node keep a whitelist of all nodes it trusts. If you stop trusting a particular node, you remove it from the nodes whitelist (by uploading a new sketch), and it will no longer be able to communicate signed messages to the door node.

In case you want to be able to "whitelist" trusted nodes (in order to be able to revoke them in case they are lost) you also need to take note of the serial number of the ATSHA device or the software value stored in EEPROM. This is unique for each device. The serial number is printed in a copy+paste friendly format by the personalizer for this purpose.
The whitelist is stored on the node that require signatures. When a received message is verified, the serial of the sender is looked up in a list stored on the receiving node, and the corresponding serial stored in the list for that sender is then included in the signature verification process. The list is stored as the value of the flag that enables whitelisting, MY_SIGNING_NODE_WHITELISTING.

Whitelisting is achieved by 'salting' the signature with some node-unique information known to the receiver. In the case of MY_SIGNING_ATSHA204 this is the unique serial number programmed into the circuit. This unique number is never transmitted over the air in clear text, so Eve will not be able to figure out a "trusted" serial by snooping on the traffic.
Instead the value is hashed together with the senders NodeId into the HMAC signature to produce the final signature. The receiver will then take the originating NodeId of the signed message and do the corresponding calculation with the serial it has stored in it's whitelist if it finds a matching entry in it's whitelist.

Whitelisting is an optional alternative because it adds some code and configuration options which might not be desirable for every user. So if you want the ability to use whitelists, you need to enable MY_SIGNING_NODE_WHITELISTING. You need to remember that the gateway will remember if a node has presented it with a whitelisting requirement as described above, if you at some point decide to remove the whitelist requirement.
The whitelist is provided as value of the flag that enable it as follows (example is a node that require signing as well):

#define MY_SIGNING_ATSHA204
#define MY_SIGNING_REQUEST_SIGNATURES
#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}},{.nodeId = 2,.serial = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}}}
#include <MySensors.h>
...

In this example, there are two nodes in the whitelist; the gateway, and a separate node that communicates directly with this node (with signed messages). You do not need to do anything special for the sending nodes, apart from making sure they support signing.

The "soft" backend of course also support whitelisting. Example:

#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
#define MY_SIGNING_REQUEST_SIGNATURES
#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}},{.nodeId = 2,.serial = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}}}
#include <MySensors.h>
...

For a node that should transmit whitelisted messages but not receive whitelisted messages, you do not need any special configurations:

#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7

Remember that you always need to select a signing backend for all nodes that communicate to a node that require whitelisting. Also, note that a node that use whitelisting will not accept messages from nodes that are not present in it's whitelist. And you have to personalize all nodes that use signing with a common HMAC key but different serial numbers (MY_SIGNING_ATSHA204 always has unique serials).

Known limitations

Due to the limiting factor of our cheapest Arduino nodes, the use of diversified keys is not implemented. That mean that all nodes in your network share the same PSK (at least the ones that are supposed to exchange signed data). It is important to understand the implications of this, and that is covered in the "Typical use cases" chapter below.
Most importantly, if you use MY_SIGNING_SOFT your PSK will be stored in EEPROM and will therefore be accessible by anyone with physical access to your node. Therefore it is NOT recommended to use MY_SIGNING_SOFT on nodes that are placed in a public place or worn on on your person (like a keyfob).
Also be reminded that the strength of the signature is inversely proportional to the size of the message. The larger the message, the weaker the signature.

Typical use cases

"Securely located" in this context mean a node which is not physically publicly accessible. Typically at least your gateway.
"Public" in this context mean a node that is located outside your "trusted environment". This includes sensors located outdoors, keyfobs etc.

Securely located lock

You have a securely located gateway and a lock somewhere inside your "trusted environment" (e.g. inside your house door, the door to your dungeon or similar).
You need to make your node require signed messages but you do not necessarily need to make your gateway require signed messages (unless you are concerned that someone might spoof the lock status of your lock).
Configuration example for the secure lock node:

#define MY_SIGNING_ATSHA204
#define MY_SIGNING_REQUEST_SIGNATURES
#include <MySensors.h>
...

If you do also want your gateway to require signatures from your lock you just enable the same (or similar if using software signing) settings in the gateway.

Patio motion sensor

Your gateway is securely located inside your house, but your motion sensor is located outside your house. You have for some reason elected that this node should sign the messages it send to your gateway. You should lock the data (PSK) in this node then, because if someone were to steal your patio motion sensor, they could rewrite the firmware and spoof your gateway to use it to transmit a correctly signed message to your secure lock inside your house. But if you revoke your gateway (and lock) PSK the outside sensor cannot be used for this anymore. Nor can it be changed in order to do it in the future. You can also use whitelisting to revoke your lost node.
This is an unlikely use case because there really is no reason to sign sensor values. If you for some reason want to obfuscate sensor data, encryption is a better alternative.
Configuration example for a motion sensor:

#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
#define MY_SIGNING_REQUEST_SIGNATURES
#include <MySensors.h>
...

The gateway needs to be configured with a whitelist (and it has to have an entry for all nodes that send and/or require signed messages):

#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
#define MY_SIGNING_REQUEST_SIGNATURES
#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = MOTION_SENSOR_ID,.serial = {0x12,0x34,0x56,0x78,0x90,0x12,0x34,0x56,0x78}}}
#include <MySensors.h>
...

Keyfob for garage door opener

Perhaps the most typical usecase for signed messages. Your keyfob should be totally locked down. If the garage door opener is secured (and it should be) it can be unlocked. That way, if you loose your keyfob, you can revoke the PSK in both the opener and your gateway, thus rendering the keyfob useless without having to replace your nodes. You can also use whitelisting to revoke your lost keyfob.
Configuration example for the keyfob (keyfob will only transmit to another node and not receive anything):

#define MY_SIGNING_ATSHA204
#include <MySensors.h>
...

Configuration example for the door controller node (should require signing from anyone who wants to control it):

#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
#define MY_SIGNING_REQUEST_SIGNATURES
#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88}},{.nodeId = KEYFOB_ID,.serial = {<FROM ATSHA ON KEYFOB>}}}
#include <MySensors.h>
...

Relevant sketches

The technical stuff

The following sequence diagram illustrate how messages are passed in a MySensors network with respect to signing:

None of this activity is “visible” to you (as the sensor sketch implementor). All you need to do is to set your preferences in your sketch and personalize accordingly. That is enough to enable protection from both Eve and Mallory in your network although if you do not also enable encryption, Eve can eavesdrop, but not do anything about, your messages (except possibly preventing them from arriving).

How are the messages actually affected by the signing?
The following illustration shows what part of the message is signed, and where the signature is stored:

The first byte of the header is not covered by the signature, because in the network, this byte is used to track hops in the network and therefore might change if the message is passing a relay node. So it cannot be part of the signature, or the signature would be invalid when it arrives to its destination. The signature also carries a byte with a signing identifier to prevent false results from accidental mixing of incompatible signing backends in the network. Thus, the maximum size for a payload is 29-7 bytes. Larger payloads are not possible to sign at the moment. Another thing to consider is that the strength of the signature is inversely proportional to the payload size.

As for the software backend, it turns out that the ATSHA does not do “vanilla” HMAC processing. Fortunately, Atmel has documented exactly how the circuit processes the data and hashes thus making it possible to generate signatures that are identical to signatures generated by the circuit.

The signatures are calculates in the following way:

Exactly how this is done can be reviewed in the source for the software backend (MySigningAtsha204Soft.cpp) and the ATSHA204A datasheet . In the MySensors protocol, the following internal messagetypes handles signature requirements and nonce requests:
I_SIGNING_PRESENTATION
I_NONCE_REQUEST
I_NONCE_RESPONSE

Also, the version field in the header has been reduced from 3 to 2 bits in order to fit a single bit to indicate that a message is signed.

Background and concepts

Suppose two participants, Alice and Bob, wants to exchange a message. Alice sends a message to Bob. In MySensors “language” Alice could be a gateway and Bob an actuator (light switch, electronic lock, etc). But to be generic, we will substitute the term “gateway” with Alice and a “node” with Bob (although the reverse relationship is also supported).

Alice sends a message to Bob. This message can be heard by anyone who wants to listen (and also by anyone that is within “hearing” distance). Normally, this is perhaps not a big issue. Nothing Alice says to Bob may be secret or sensitive in any way. However, sometimes (or perhaps always) Bob want to be sure that the message Bob receives actually came from Alice. In cryptography, this is known as authenticity. Bob needs some way of determining that the message is authentic from Alice, when Bob receives it. This prevents an eavesdropper, Eve, to trick Bob into thinking it was Alice that sent a message Eve in fact transmitted. Bob also needs to know how to determine if the message has been repeated. Eve could record a message sent by Alice that Bob accepted and then send the same message again. Eve could also in some way prevent Bob from receiving the message and delay it in order to permit the message to arrive to Bob at a time Eve chooses, instead of Alice. Such an attack is known as a replay attack.
Authenticity permits Bob to determine if Alice is the true sender of a message.

It can also be interesting for Bob to know that the message Alice sent has not been tampered with in any way. This is the integrity of the message. We now introduce Mallory, who could be intercepting the communication between Alice and Bob and replace some parts of the message but keeping the parts that authenticate the message. That way, Bob still trusts Alice to be the source, but the contents of the message was not the content Alice sent. Bob needs to be able to determine that the contents of the message was not altered after Alice sent it.
Mallory would in this case be a man-in-the-middle attacker.
Integrity permits Bob to verify that the messages received from Alice has not been tampered with.
This is achieved by adding a signature to the message, which Bob can inspect to validate that Alice is the author.

The signing scheme used, needs to address both these attack scenarios. Neither Eve nor Mallory must be permitted to interfere with the message exchange between Alice and Bob.

The key challenge to implementing a secure signing scheme is to ensure that every signature is different, even if the message is not. If not, replay attacks would be very hard to prevent.
One way of doing this is to increment some counter on the sender side and include it in the signature. This is however predictable.
A better option would be to introduce a random number to the signature. That way, it is impossible to predict what the signature will be. The problem is, that also makes it impossible for the receiver (Bob) to verify that the signature is valid.
A solution to this is to let Bob generate the random number, keep it in memory and send it to Alice. Alice can then use the random number in the signature calculation and send the signed message back to Bob who can validate the signature with the random number used. This random number is in cryptography known as a nonce or salt.

However, Mallory might be eavesdropping on the communication and snoop up the nonce in order to generate a new valid signature for a different message. To counter this, both Alice and Bob keep a secret that only they know. This secret is never transmitted over the air, nor is it revealed to anybody. This secret is known as a pre-shared key (PSK).

If Eve or Mallory are really sophisticated, he/she might use a delayed replay attack. This can be done by allowing Bob to transmit a nonce to Alice. But when Alice transmits the uniquely signed message, Mallory prevents Bob from receiving it, to a point when Mallory decides Bob should receive it. An example of such an attack is described here.
This needs to be addressed as well, and one way of doing this is to have Bob keep track of time between a transmitted nonce and a signed message to verify. If Bob is asked for a nonce, Bob knows that a signed message is going to arrive “soon”. Bob can then decide that if the signed message does not arrive within a predefined timeframe, Bob throws away the generated nonce and thus makes it impossible to verify the message if it arrives late.

The flow can be described like this:

The benefits for MySensors to support this are obvious. Nobody wants others to be able to control or manipulate any actuators in their home.

How this is done

There exist many forms of message signature solutions to combat Eve and Mallory.
Most of these solutions are quite complex in term of computations, so I elected to use an algorithm that an external circuit is able to process. This has the added benefit of protecting any keys and intermediate data used for calculating the signature so that even if someone were to actually steal a sensor and disassembled it, they would not be able to extract the keys and other information from the device.
A common scheme for message signing (authenticity and integrity) is implemented using HMAC which in combination with a strong hash function provides a very strong level of protection.
The Atmel ATSHA204A is a low-cost, low-voltage/current circuit that provides HMAC calculation capabilities with SHA256 hashing which is a (currently) virtually unbreakable combination. If SHA256 were to be hacked, a certain cryptocurrency would immediately be rendered worthless.
The ATSHA device also contain a random number generator (RNG) which enables the generation of a good nonce, as in, non-predictable.
As I acknowledge that some might not want to use an additional external circuit, I have also implemented a software version of the ATSHA device, capable of generating the same signatures as the ATSHA device does. Because it is pure-software however, it does not provide as good nonces (it uses the Arduino pseudo-random generator) and the HMAC key is stored in SW and is therefore readable if the memory is dumped. It also naturally claims more flash space due to the more complex software. But for indoor sensors/actuators this might be good enough for most people.

Why encryption is not part of this

Well, some could be uncomfortable with somebody being able to snoop temperatures, motion or the state changes of locks in the environment. Signing does not address these issues. Encryption is needed to prevent this.
It is my personal standpoint that encryption should not be part of the MySensors “protocol”. The reason is that a gateway and a node does not really care about messages being readable or not by “others”. It makes more sense that such guarantees are provided by the underlying transmission layer (RF solution in this case). It is the information transmitted over the air that needs to be secret (if user so desires). The “trust” level on the other hand needs to go all the way into the sketches (who might have different requirements of trust depending on the message participant), and for this reason, it is more important (and less complicated) to ensure authenticity and integrity at protocol-level as message contents is still readable throughout the protocol stack. But as soon as the message leaves the “stack” it can be scramble into “garbage” when transmitted over the air and then reassembled by a receiving node before being fed in “the clear” up the stack at the receiving end.

There are methods and possibilities to provide encryption also in software, but if this is done, it is my recommendation that this is done after integrity- and authentication information has been provided to the message (if this is desired). Integrity and authentication is of course not mandatory and some might be happy with only having encryption to cover their need for security. I, however, have only focused on integrity and authenticity while at the same time keeping the current message routing mechanisms intact and therefore leave the matter of secrecy to be implemented in the “physical” transport layer. With the integrity and authenticity handled in the protocol it ought to be enough for a simple encryption (nonce-less AES with a PSK for instance) on the message as it is sent to the RF backend. Atmel does provide such circuits as well but I have not investigated the matter further as it given the current size of the ethernet gateway sketch is close to the size limit on an Arduino Nano, so it will be difficult to fit this into some existing gateway designs.
Also it is worth to consider that the state of a lock can just as readily be determined by simply looking at the door in question or attempting to open it, so obfuscating this information will not necessarily deter an attacker in any way.
Nevertheless, I do acknowledge that people find the fact that all information is sent “in the clear” even if it require some technical effort for an intruder to obtain and inspect this information. So I do encourage the use of encrypting transport layers.
This is however not covered by this implementation.
This might change in the future as more powerful platforms emerge which permit more complex security schemes and better hardware acceleration.

Modules

 Signing related debug messages
 Explanation of the abstract signing related debug messages.
 
 Signing troubleshooting
 Typical signing related failure cases and how to solve them.
 
MySensors.h
API declaration for MySensors.