Connect Tutorial 5 - Communication Features: Security
10/277/2019 | 01:33 PM
This is the fifth tutorial in a series that demonstrates "the essentials" of building applications based on Silicon Labs Connect. See Connect Tutorial Series: Table of Contents for an overview of topics addressed in the series, general pre-requisites to ensure you get the most out of the exercises, and definitive Connect references for when you're ready to dive deeper.
The previous tutorial (Communication Features: Acknowledge and Message Queue) fortified simple radio operations with built-in Connect features to yield more resilient wireless communication and reduce application overhead. We'll now examine how to augment this configuration with the built-in security features available to Connect-based applications.
To conduct the following exercises, you'll need two Wireless Starter Kit (WSTK) boards, each equipped with a (preferably identical) radio board. The example application relies on CLI through the WSTK VCOM (over USB) port to issue commands and display status information.
Application Example: AES Encryption
Historically, security was - at best - an afterthought in the race to capture market share in the nascent IoT. You may even have heard the joke "The S in IoT stands for security" (credit:@tkadlec). After years of widespread public incidents attributed to IoT devices, lessons-learned led to heightened awareness and ultimately an industry-wide push to directly address the risk profiles of our modern, thoroughly-connected world.
One fundamental tenet of IoT security is the encryption of messages over-the-air (OTA). The example below demonstrates how easy it is to use Connect's built-in encryption support. Currently, Connect can implement AES or XXTEA ciphers - AES is strongly recommended (the inferior XXTEA is a remnant of support for 8bit devices on which AES was not feasible).
Important note: Connect supports security in a binary fashion - it is either enabled or disabled, on a per-message basis. This tutorial discusses the AES encryption component, as it requires application participation for key management. However, encryption is just one benefit (data confidentiality) of many (including data authenticity and replay protection) that Connect provides with "out of the box" security. A message integrity code (MIC) and frame counter (to resist replay attacks) are managed entirely by the Connect MAC layer. More detail on security in Connect is presented later in Traffic Analysis: Addressing, Acknowledgement, and Security
We'll build upon the example developed during the previous tutorial (Communication Features: Acknowledge and Message Queue). To begin, we recommend that you start from that project and extend it as instructed below. Feel free to use the attached "solution" files in your project instead, or simply for reference as you proceed through the steps below.
Modify the AppBuilder Configuration
We'll need only a few minor changes to the tutorial 4 example project. To include AES encryption support, select the Security AES plugin in AppBuilder / Plugins in the Connect Stack section, and deselect the Security AES Stub option.
Make two command line configuration changes so we can manipulate the AES feature via CLI:
set-tx-options now needs a second "u" argument (to enable/disable encryption)
add new command set-key to set the encryption key (string argument, "b") at run time
Remember to save the .isc file and [Generate] the project again to apply these updates.
For future reference: if you plan to implement additional application-layer security in your project (and leverage hardware acceleration via the mbedTLS library), select AppBuilder / Plugins / Connect Utility / mbed TLS to safely share crypto resources with Connect.
Source Code Modifications
Of course, we'll need a placeholder for the default security key. Since Connect implements AES-128 encryption, the key size is 16 Bytes. These 16 Bytes are loaded into a structure of type EmberKeyData (which has a single member, contents[]):
To apply the security key, the following API has to be called:
emberSetSecurityKey(&securityKey);
We'll call this API any time we want to change the key, but also in commissionCommand(void) to ensure the default key is applied when the network is first created. As AES is a symmetric-key algorithm, this single key is used for both encryption of sent messages and decryption of received messages.
void commissionCommand(void) {
EmberStatus status;
EmberNodeId nodeId;
EmberNetworkParameters params;
// Initialize the security key to the default key prior to forming the
// network.
emberSetSecurityKey(&securityKey);
nodeId = emberUnsignedCommandArgument(0);
params.panId = PAN_ID;
params.radioChannel = RADIO_CHANNEL;
params.radioTxPower = RADIO_TX_POWER;
status = emberJoinCommissioned(EMBER_DIRECT_DEVICE,
nodeId,
¶ms);
if ( status != EMBER_SUCCESS ) {
emberAfCorePrintln("Commissioning failed, 0x%x", status);
}
}
To support our new run time key change command (usage: set-key <16 byte security key>), we implement its corresponding command handler:
void setSecurityKeyCommand(void)
{
EmberKeyData key;
emberCopyKeyArgument(0, &key);
if (emberSetSecurityKey(&key) == EMBER_SUCCESS) {
uint8_t i;
emberAfCorePrint("Security key set {");
for (i = 0; i < EMBER_ENCRYPTION_KEY_SIZE; i++) {
emberAfCorePrint("%x", key.contents[i]);
}
emberAfCorePrintln("}");
} else {
emberAfCorePrintln("Security key set failed");
}
}
To enable the encryption of outgoing messages, we need only add EMBER_OPTIONS_SECURITY_ENABLED to the options passed to emberMessageSend(). For convenience, we've added a second input parameter to the set-tx-options command - in addition to ACK requested, it now expects a second argument: security enabled (0 to disable, 1 to enable). The handler for set-tx-options is extended to accommodate the new parameter:
Successful reception of an encrypted message requires that the same security key be used by both the sender and receiver. However, the receiving device does not dictate security (this is set by the sender) - it merely evaluates the "security enabled" bit present on any inbound message to determine whether or not a decryption operation is required. Any received messages with that bit cleared (i.e. unencrypted messages) will therefore be treated as valid. This can present a security concern if a device with security enabled (i.e. it is transmitting encrypted outbound messages) converses with a remote device that is not encrypting its responses.
To avoid this scenario, use the EMBER_OPTIONS_SECURITY_ENABLED flag in the options member of Connect's EmberIncomingMessage structure to filter out any unwanted messages (i.e. when the flag is set in TX options, but not in an incoming message). The updated callback implementation below prints a warning when those conditions are present:
void emberAfIncomingMessageCallback(EmberIncomingMessage *message) {
// your code here
if((txOptions & EMBER_OPTIONS_SECURITY_ENABLED) && !(message->options & EMBER_OPTIONS_SECURITY_ENABLED)) {
// In normal circumstances if security is enabled but the message is not
// encrypted it should be ignored to avoid security issues
emberAfAppPrintln("warning: security is enabled, but the incoming message is not encrypted");
}
emberAfAppPrint("incoming message: from: 0x%02x, options=0x%1x, endpoint=%d, length=%d, payload=[",
message->source,
message->options,
message->endpoint,
message->length);
for(int cnt = 0; cnt < message->length; cnt++) {
emberAfAppPrint("%c", message->payload[cnt]);
}
emberAfAppPrintln("]");
}
Using the Example Application
As in the previous tutorial (Communication Features: Acknowledge and Message Queue), compile and download the firmware to the devices, and open terminals for both. To set up a connection, call commission 1 on device 1, and call commission 2 on device 2. To test the communication, call send 2 1 "message" 1 on device 1.
To turn on message encryption for device 1, simply enable security (this will also request ACKs, as the first parameter is 1) by issuing:
> set-tx-options 1 1
ACK is requested, security is enabled
Ensure that security is disabled (this is the default setting) on device 2 by issuing:
> set-tx-options 1 0
ACK is requested, security is disabled
Now transmit an unencrypted message from device 2 to device 1 with send 1 1 "message" 1. Device 1 will receive the message, but observe that security is disabled in the options member and warn of this condition over CLI:
warning: security is enabled, but the incoming message is not encrypted
incoming message: from: 0x0002, options=0x02, endpoint=1, length=7, payload=[message]
Enable security on device 2 also, and device 1 will now happily receive encrypted messages:
On only one of the devices, "break" the communication by changing its key from the default:
> set-key {00112233445566778899aabbccddeeff}
Security key set {00112233445566778899AABBCCDDEEFF}
With the keys on each device out of sync, messages sent with security enabled will fail to be received (this example application drops such messages without notifying the CLI). Set the same key on both devices and the receiver will again successfully decrypt and report each message reception.
Notes
The security key is stored in flash memory, so in theory it is not necessary to apply the key on every boot. This is useful for devices after power cycle or reset that rejoin a network that has over time migrated security keys.
The selection of the "all 0xAA" key used in this example was deliberate, as messages encrypted with this key are automatically decrypted by Simplicity Studio's built-in network analyzer. This tool enables convenient debugging of encrypted communications, and is covered in depth in the Traffic Analysis: Addressing, Acknowledgement, and Security tutorial.
Conclusion
Combining the CLI and enhanced radio messaging from prior tutorials with built-in Connect security features, this tutorial demonstrated message encryption in a Direct Mode Connect network. Discussion of additional security features (beyond encryption) is presented in Traffic Analysis: Addressing, Acknowledgement, and Security.
Connect Tutorial 5 - Communication Features: Security
This is the fifth tutorial in a series that demonstrates "the essentials" of building applications based on Silicon Labs Connect. See Connect Tutorial Series: Table of Contents for an overview of topics addressed in the series, general pre-requisites to ensure you get the most out of the exercises, and definitive Connect references for when you're ready to dive deeper.
The previous tutorial (Communication Features: Acknowledge and Message Queue) fortified simple radio operations with built-in Connect features to yield more resilient wireless communication and reduce application overhead. We'll now examine how to augment this configuration with the built-in security features available to Connect-based applications.
To conduct the following exercises, you'll need two Wireless Starter Kit (WSTK) boards, each equipped with a (preferably identical) radio board. The example application relies on CLI through the WSTK VCOM (over USB) port to issue commands and display status information.
Application Example: AES Encryption
Historically, security was - at best - an afterthought in the race to capture market share in the nascent IoT. You may even have heard the joke "The S in IoT stands for security" (credit:@tkadlec). After years of widespread public incidents attributed to IoT devices, lessons-learned led to heightened awareness and ultimately an industry-wide push to directly address the risk profiles of our modern, thoroughly-connected world.
One fundamental tenet of IoT security is the encryption of messages over-the-air (OTA). The example below demonstrates how easy it is to use Connect's built-in encryption support. Currently, Connect can implement AES or XXTEA ciphers - AES is strongly recommended (the inferior XXTEA is a remnant of support for 8bit devices on which AES was not feasible).
Important note: Connect supports security in a binary fashion - it is either enabled or disabled, on a per-message basis. This tutorial discusses the AES encryption component, as it requires application participation for key management. However, encryption is just one benefit (data confidentiality) of many (including data authenticity and replay protection) that Connect provides with "out of the box" security. A message integrity code (MIC) and frame counter (to resist replay attacks) are managed entirely by the Connect MAC layer. More detail on security in Connect is presented later in Traffic Analysis: Addressing, Acknowledgement, and Security
We'll build upon the example developed during the previous tutorial (Communication Features: Acknowledge and Message Queue). To begin, we recommend that you start from that project and extend it as instructed below. Feel free to use the attached "solution" files in your project instead, or simply for reference as you proceed through the steps below.
Modify the AppBuilder Configuration
We'll need only a few minor changes to the tutorial 4 example project. To include AES encryption support, select the Security AES plugin in AppBuilder / Plugins in the Connect Stack section, and deselect the Security AES Stub option.
Make two command line configuration changes so we can manipulate the AES feature via CLI:
set-tx-options
now needs a second "u
" argument (to enable/disable encryption)set-key
to set the encryption key (string argument, "b
") at run timeRemember to save the .isc file and [Generate] the project again to apply these updates.
For future reference: if you plan to implement additional application-layer security in your project (and leverage hardware acceleration via the mbedTLS library), select AppBuilder / Plugins / Connect Utility / mbed TLS to safely share crypto resources with Connect.
Source Code Modifications
Of course, we'll need a placeholder for the default security key. Since Connect implements AES-128 encryption, the key size is 16 Bytes. These 16 Bytes are loaded into a structure of type
EmberKeyData
(which has a single member,contents[]
):To apply the security key, the following API has to be called:
We'll call this API any time we want to change the key, but also in
commissionCommand(void)
to ensure the default key is applied when the network is first created. As AES is a symmetric-key algorithm, this single key is used for both encryption of sent messages and decryption of received messages.To support our new run time key change command (usage:
set-key <16 byte security key>
), we implement its corresponding command handler:To enable the encryption of outgoing messages, we need only add
EMBER_OPTIONS_SECURITY_ENABLED
to the options passed toemberMessageSend()
. For convenience, we've added a second input parameter to theset-tx-options
command - in addition to ACK requested, it now expects a second argument: security enabled (0
to disable,1
to enable). The handler forset-tx-options
is extended to accommodate the new parameter:Successful reception of an encrypted message requires that the same security key be used by both the sender and receiver. However, the receiving device does not dictate security (this is set by the sender) - it merely evaluates the "security enabled" bit present on any inbound message to determine whether or not a decryption operation is required. Any received messages with that bit cleared (i.e. unencrypted messages) will therefore be treated as valid. This can present a security concern if a device with security enabled (i.e. it is transmitting encrypted outbound messages) converses with a remote device that is not encrypting its responses.
To avoid this scenario, use the
EMBER_OPTIONS_SECURITY_ENABLED
flag in theoptions
member of Connect'sEmberIncomingMessage
structure to filter out any unwanted messages (i.e. when the flag is set in TX options, but not in an incoming message). The updated callback implementation below prints a warning when those conditions are present:Using the Example Application
As in the previous tutorial (Communication Features: Acknowledge and Message Queue), compile and download the firmware to the devices, and open terminals for both. To set up a connection, call
commission 1
on device 1, and callcommission 2
on device 2. To test the communication, callsend 2 1 "message" 1
on device 1.To turn on message encryption for device 1, simply enable security (this will also request ACKs, as the first parameter is
1
) by issuing:Ensure that security is disabled (this is the default setting) on device 2 by issuing:
Now transmit an unencrypted message from device 2 to device 1 with
send 1 1 "message" 1
. Device 1 will receive the message, but observe that security is disabled in the options member and warn of this condition over CLI:Enable security on device 2 also, and device 1 will now happily receive encrypted messages:
On only one of the devices, "break" the communication by changing its key from the default:
With the keys on each device out of sync, messages sent with security enabled will fail to be received (this example application drops such messages without notifying the CLI). Set the same key on both devices and the receiver will again successfully decrypt and report each message reception.
Notes
The security key is stored in flash memory, so in theory it is not necessary to apply the key on every boot. This is useful for devices after power cycle or reset that rejoin a network that has over time migrated security keys.
The selection of the "all
0xAA
" key used in this example was deliberate, as messages encrypted with this key are automatically decrypted by Simplicity Studio's built-in network analyzer. This tool enables convenient debugging of encrypted communications, and is covered in depth in the Traffic Analysis: Addressing, Acknowledgement, and Security tutorial.Conclusion
Combining the CLI and enhanced radio messaging from prior tutorials with built-in Connect security features, this tutorial demonstrated message encryption in a Direct Mode Connect network. Discussion of additional security features (beyond encryption) is presented in Traffic Analysis: Addressing, Acknowledgement, and Security.
For more information on the Connect security implementation, see UG235.02: Using Silicon Labs Connect with IEEE 802.15.4 and UG235.03: Architecture of the Silicon Labs Connect Stack.
API References
Functions
emberAfIncomingMessageCallback()
emberSetSecurityKey()
emberCopyKeyArgument()
Type definitions
EmberStatus
EmberNetworkParameters
EmberNodeId
EmberIncomingMessage
EmberKeyData
Defines
EMBER_SUCCESS
EMBER_ENCRYPTION_KEY_SIZE
EMBER_OPTIONS_ACK_REQUESTED
EMBER_OPTIONS_SECURITY_ENABLED