process() altered the message buffer pending signing when
called in sign() causing the wrong message to be sent to the
signing backend. This is resolved by copying the original
message before processing incoming messages to make sure
the original message is kept. After it is successfully signed,
it is copied back to its original location again.
Also, the old 'ack' message buffer is renamed to tmpMsg to
indicate its use as a temporary message buffer for various
purposes.
The sketch closely resembles the RelayActuator example.
The difference is that this sketch require gateway to sign
all messages addressed to the actuator.
The dummy signing driver backend is used. But with this commit all
framework logic for managing signed messages in the MySensors
ecosystem is implemented and enables more sophisticated signing
backends to be added later on.
For a sensor (or gateway) that require a gateway to send signed
messages to it, add 'true' as the fifth argument to 'begin'.
The gateway will automatically inform a node of it's signing
requirements as soon as it receivs the nodes signing preference.
It is important to understand that if the gateway require
signing, it will in this implementation only require signing from
nodes that require signing by the gateway.
If the sensor requires signing from another node on the network
which it communicates directly with, it needs to send 'true' in
an internal message of type I_REQUEST_SIGNING.
ATSHA204 emulated signing backend. The emulated ATSHA204
implementation offers pseudo random number generation and
HMAC-SHA256 authentication compatible with a "physical"
ATSHA204.
NOTE: Key is stored in clear text in the Arduino firmware.
Therefore, the use of this back-end could compromise the key
used in the signed message infrastructure if device is lost
and its memory dumped.
The seed for the random number generated is sampled from an
analog pin. The pin is set in MyConfig.h using RANDOMSEED_PIN.
The pin should be unconnected.
The key to use for HMAC calculations must match the key used by
other nodes this node will exchange signed messages with. The key
for ATSHA204 emulator is set in MyConfig.h using hmacKey.
Default SDA pin is A3 for single wire communication.
The pin is selected in MyConfig.h.
I2C variant of ATSHA204 is not supported.
Messages are signed using HMAC-SHA256 where some parts of the
message digest are ATSHA204 specific.
The dummy signing driver implements the most rudimentary form of
signing. No pre-shared key is used, nonce is simply incremeted
each turn and signature is only calculated on the fist byte using
data XOR nonce.
This driver is intended for library debugging and sensor network
integrity verification (signed messages will force the radio to
transmit all 32 bytes of data).
It does check SIGNING_IDENTIFIER byte to avoid illegal mixing of
signing backends in the network (as seen by this node) and it does
verify proper execution order on the API.
The dummy driver rejects all other signing backend protocols.
Signing backend is selected in MyConfig.h
The signing driver framework resembles the radio driver framework
in the sense that it relies on MyConfig.h for driver specific
settings. This allows the constructor to be clean and the API less
likely to need change.
The API is designed with function pairs for sender and receiver of
a signed message.
The sender of a signed message uses putNonce() and signMsg()
and the receiver of a signed message uses getNonce() and
verifyMsg().
In addition, receiver is expected to call checkTimer() at regular
intervals to make sure the message session does not time out.
The program flow is that the sender transmit, after determining
that the message needs signing, a request to the receiver for a
nonce (I_GET_NONCE). The receiver calls getNonce() to obtain a
nonce and transmits the nonce back to the sender
(I_GET_NONCE_RESPONSE).
The sender stores the received nonce in the driver with putNonce()
and then calls signMsg() to sign the message to be transmitted.
The receiver then calls verifyMsg() to authenticate the signed
message using the nonce transmitted earlier.
The flow is described below:
---------------- -------- ---------- ------------------
|senders driver| |sender| |receiver| |receivers driver|
---------------- -------- ---------- ------------------
| | I_GET_NONCE | getNonce() |
| |------------------->|------------->|
| | | |
| setNonce() |I_GET_NONCE_RESPONSE| |
|<-----------|<-------------------|<-------------|
| signMsg() | | |
|<-----------| | verifyMsg() |
|----------->|------------------->|------------->|
| | | OK / not OK |
| | |<-------------|
It is expected that all signing schemes is built upon this
principle.
One bit in the protocol version field is converted to a sign
indicator. '1' means the message carries a signature in the
unused part of the payload data buffer.
Three new internal message types have been defined:
* I_REQUEST_SIGNING carries a boolean and is used to exchange
signing requirement information between
nodes.
If the I_REQUEST_SIGNING carries 'true'
the receiver is informed that the sender
require properly signed messages in order
to be able to accept the messages.
* I_GET_NONCE is passed from sender to a receiver that
require signing tellig it to submit a
cryptographic 'nonce' that the sender needs
in order to be able to sign the message it
intend to send. The I_GET_NONCE carries no
payload.
* I_GET_NONCE_RESPONSE is sent by the receiver of a signed
message in response to I_GET_NONCE.
The first byte of the payload is a signing
identifier informing the sender of the
signed message about the type of signature
the receiver is expecting.
New default pin is A3.
New option to skip UART confirmation: SKIP_UART_CONFIRMATION
This option prohibits the possibility to auto-generate key as there
will probably not be a way to show the generated key to the user.
More copy+paste friendly serial output of the generated key for
insertion into personalization sketch.
This sketch is used to personalize the ATSHA204 crypto
circuit.
This is required in order to use the device for secure
communication.
The sketch also supports random key generation.
To personalize a ATSHA204 device, do the following:
1. Ensure the correct pin is used for the ATSHA204.
2. Execute the sketch without other changes to verify
that it can communicate properly with the device.
3g. For a device used in a gateway:
Enable LOCK_CONFIGURATION to lock the configuration
and enable random key generation as well as key storage.
4g. Execute the sketch to lock the configuration and obtain
a unique key. Be sure to note down the key printed in the
UART log as it has been stored in the chip and will never
be accessible again (a new key is calculated on subsequent
runs).
The key can still be changed.
5g. Enable SKIP_KEY_STORAGE to prevent generating new random
keys on sketch re-execution.
3n. For a device used as a node:
Enable USER_KEY_DATA and enter your private key data
in user_key_data.
Then enable LOCK_CONFIGURATION to lock the configuration
4n. Execute the sketch to lock the configuration and store
the user-supplied key.
5n. Optionally: Enable SKIP_KEY_STORAGE to prevent re-writing
the user supplied key on sketch re-execution.
6. Optionally: Enable LOCK_DATA to prevent the key to be
changed.
Locking operations are recommended to include CRC
and since sha204 library internally carries the proper
algorithm for this, it has now been refactored to support
both static and incremental calculations needed for both
command marchalling and locking.
MySensors will have native support for sha204 and the
source for usage and personalization of sha204 will be
much more elaborate than this example so it does not
provide additional understanding for the chip.
Taken from the sha204_library folder in
https://github.com/jimblom/sha204-Breakout
Commit 8e1ac05ef987b1869605ad067db2bdbaec1c109f
ATSHA204 is a crypto cirquit from Atmel that enables
SHA256-based MAC and HMAC calculations as well as
secure key storage and random number generation.
This can be used to sign messages passed between
sensor nodes and prevent both man-in-the-middle and
replay attacking.
This is a preparation for handling multiple interrupts in delay().
It also reduces the size of the interrupt-related variables and
arguments to int8_t as that should be ample enough for any Arduino
implementation.
The difference between the interrupt driven binary switch example and
the normal binary switch example is the following:
* Interrupt example does not use debouncer because it rely on loop()
iterating over time (but it sleeps between iterations)
* Interrupt example is more power conservative because it sleeps as soon
as it has sent updated data and no activity happens on the pin
* Interrupt example is limited to only two IO pins for the sensor, due
to limitations in the Arduino HW. The example uses the preprocessor to
ensure that this is not misconfigured or sleep function can not be
expected to behave as intended.