Skip to content

Commit

Permalink
Merge pull request #15150 from fabian18/ieee802154_security
Browse files Browse the repository at this point in the history
Initial implementation of IEEE 802.15.4 security
  • Loading branch information
benpicco authored Dec 9, 2020
2 parents b801d57 + 9c45cf1 commit 1477a34
Show file tree
Hide file tree
Showing 25 changed files with 1,543 additions and 35 deletions.
87 changes: 87 additions & 0 deletions drivers/at86rf2xx/at86rf2xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,91 @@
#include "luid.h"
#include "byteorder.h"
#include "net/ieee802154.h"
#if IS_USED(IEEE802154_SECURITY)
#include "net/ieee802154_security.h"
#endif
#include "net/gnrc.h"
#include "at86rf2xx_registers.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_netdev.h"
#if IS_USED(MODULE_AT86RF2XX_AES_SPI)
#include "at86rf2xx_aes.h"
#endif

#define ENABLE_DEBUG 0
#include "debug.h"

#if IS_USED(MODULE_AT86RF2XX_AES_SPI) && \
IS_USED(MODULE_IEEE802154_SECURITY)
/**
* @brief Pass the 802.15.4 encryption key to the transceiver hardware
*
* @param[in] dev Abstract security device descriptor
* @param[in] key Encryption key to be used
* @param[in] key_size Size of the encryption key in bytes
*/
static void _at86rf2xx_set_key(ieee802154_sec_dev_t *dev,
const uint8_t *key, uint8_t key_size)
{
(void)key_size;
at86rf2xx_aes_key_write_encrypt((at86rf2xx_t *)dev->ctx, key);
}

/**
* @brief Compute CBC-MAC from IEEE 802.15.4 security context
*
* @param[in] dev Abstract security device descriptor
* @param[out] cipher Buffer to store cipher blocks
* @param[in] iv Initial vector
* @param[in] plain Input data blocks
* @param[in] nblocks Number of blocks
*/
static void _at86rf2xx_cbc(const ieee802154_sec_dev_t *dev,
uint8_t *cipher,
uint8_t *iv,
const uint8_t *plain,
uint8_t nblocks)
{
at86rf2xx_aes_cbc_encrypt((at86rf2xx_t *)dev->ctx,
(aes_block_t *)cipher,
NULL,
iv,
(aes_block_t *)plain,
nblocks);
}

/**
* @brief Perform ECB encryption
*
* @param[in] dev Abstract security device descriptor
* @param[out] cipher Output cipher blocks
* @param[in] plain Plain blocks
* @param[in] nblocks Number of blocks
*/
static void _at86rf2xx_ecb(const ieee802154_sec_dev_t *dev,
uint8_t *cipher,
const uint8_t *plain,
uint8_t nblocks)
{
at86rf2xx_aes_ecb_encrypt((at86rf2xx_t *)dev->ctx,
(aes_block_t *)cipher,
NULL,
(aes_block_t *)plain,
nblocks);

}
/**
* @brief Struct that contains IEEE 802.15.4 security operations
* which are implemented, using the transceiver´s hardware
* crypto capabilities
*/
static const ieee802154_radio_cipher_ops_t _at86rf2xx_cipher_ops = {
.set_key = _at86rf2xx_set_key,
.ecb = _at86rf2xx_ecb,
.cbc = _at86rf2xx_cbc
};
#endif /* IS_USED(MODULE_AT86RF2XX_COMMON_AES_SPI) && \
IS_USED(MODULE_IEEE802154_SECURITY) */

void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params, uint8_t index)
{
Expand Down Expand Up @@ -152,6 +229,16 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
/* clear interrupt flags */
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);

#if IS_USED(MODULE_IEEE802154_SECURITY) && \
IS_USED(MODULE_AT86RF2XX_AES_SPI)
dev->netdev.sec_ctx.dev.cipher_ops = &_at86rf2xx_cipher_ops;
dev->netdev.sec_ctx.dev.ctx = dev;
/* All configurations of the security module, the SRAM content,
and keys are reset during DEEP_SLEEP or RESET state. */
at86rf2xx_aes_key_write_encrypt(dev,
dev->netdev.sec_ctx.cipher.context.context);
#endif

/* State to return after receiving or transmitting */
dev->idle_state = AT86RF2XX_PHY_STATE_RX;
/* go into RX state */
Expand Down
19 changes: 19 additions & 0 deletions drivers/at86rf2xx/at86rf2xx_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
#include "at86rf2xx_netdev.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_registers.h"
#if IS_USED(MODULE_AT86RF2XX_AES_SPI)
#include "at86rf2xx_aes.h"
#endif

#define ENABLE_DEBUG 0
#include "debug.h"
Expand Down Expand Up @@ -665,6 +668,22 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)

#endif /* MODULE_NETDEV_IEEE802154_OQPSK */

#if IS_USED(MODULE_AT86RF2XX_COMMON_AES_SPI) && \
IS_USED(MODULE_IEEE802154_SECURITY)
case NETOPT_ENCRYPTION_KEY:
assert(len >= IEEE802154_SEC_KEY_LENGTH);
at86rf2xx_aes_key_write_encrypt(dev, val);
if (memcmp(dev->netdev.sec_ctx.cipher.context.context, val, len)) {
/* If the key changes, the frame conter can be reset to 0*/
dev->netdev.sec_ctx.frame_counter = 0;
}
memcpy(dev->netdev.sec_ctx.cipher.context.context, val,
IEEE802154_SEC_KEY_LENGTH);
res = IEEE802154_SEC_KEY_LENGTH;
break;
#endif /* IS_USED(MODULE_AT86RF2XX_AES_SPI) && \
IS_USED(MODULE_IEEE802154_SECURITY) */

default:
break;
}
Expand Down
6 changes: 6 additions & 0 deletions drivers/include/net/netdev/ieee802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

#include "net/eui_provider.h"
#include "net/ieee802154.h"
#if IS_USED(MODULE_IEEE802154_SECURITY)
#include "net/ieee802154_security.h"
#endif
#include "net/gnrc/nettype.h"
#include "net/netopt.h"
#include "net/netdev.h"
Expand Down Expand Up @@ -116,6 +119,9 @@ typedef struct {
uint8_t page; /**< channel page */
uint16_t flags; /**< flags as defined above */
int16_t txpower; /**< tx power in dBm */
#if IS_USED(MODULE_IEEE802154_SECURITY) || defined (Doxygen)
ieee802154_sec_context_t sec_ctx; /**< security context */
#endif
/** @} */
} netdev_ieee802154_t;

Expand Down
44 changes: 43 additions & 1 deletion drivers/netdev/ieee802154.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ void netdev_ieee802154_reset(netdev_ieee802154_t *dev)
/* Initialize PAN ID and call netdev::set to propagate it */
dev->pan = CONFIG_IEEE802154_DEFAULT_PANID;
dev->netdev.driver->set(&dev->netdev, NETOPT_NID, &dev->pan, sizeof(dev->pan));

#if IS_USED(MODULE_IEEE802154_SECURITY)
ieee802154_sec_init(&dev->sec_ctx);
const netopt_enable_t e = NETOPT_ENABLE;
netdev_ieee802154_set(dev, NETOPT_ENCRYPTION, &e, sizeof(e));
#endif
}

static inline uint16_t _get_ieee802154_pdu(netdev_ieee802154_t *dev)
Expand Down Expand Up @@ -115,6 +121,18 @@ int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value,
*((uint16_t *)value) = (uint16_t)dev->chan;
res = sizeof(dev->chan);
break;
#if IS_USED(MODULE_IEEE802154_SECURITY)
case NETOPT_ENCRYPTION:
assert(max_len == sizeof(netopt_enable_t));
if (dev->flags & NETDEV_IEEE802154_SECURITY_EN) {
*((netopt_enable_t *)value) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)value) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */
case NETOPT_ACK_REQ:
assert(max_len == sizeof(netopt_enable_t));
if (dev->flags & NETDEV_IEEE802154_ACK_REQ) {
Expand Down Expand Up @@ -159,6 +177,9 @@ int netdev_ieee802154_get(netdev_ieee802154_t *dev, netopt_t opt, void *value,

*((uint16_t *)value) = (_get_ieee802154_pdu(dev)
- IEEE802154_MAX_HDR_LEN)
#if IS_USED(MODULE_IEEE802154_SECURITY)
-IEEE802154_MAX_AUX_HDR_LEN
#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */
- IEEE802154_FCS_LEN;
res = sizeof(uint16_t);
break;
Expand Down Expand Up @@ -219,6 +240,28 @@ int netdev_ieee802154_set(netdev_ieee802154_t *dev, netopt_t opt, const void *va
dev->pan = *((uint16_t *)value);
res = sizeof(dev->pan);
break;
#if IS_USED(MODULE_IEEE802154_SECURITY)
case NETOPT_ENCRYPTION:
assert(len == sizeof(netopt_enable_t));
if ((*(bool *)value)) {
dev->flags |= NETDEV_IEEE802154_SECURITY_EN;
}
else {
dev->flags &= ~NETDEV_IEEE802154_SECURITY_EN;
}
res = sizeof(netopt_enable_t);
break;
case NETOPT_ENCRYPTION_KEY:
assert(len >= IEEE802154_SEC_KEY_LENGTH);
if (memcmp(dev->sec_ctx.cipher.context.context, value, len)) {
/* If the key changes, the frame conter can be reset to 0*/
dev->sec_ctx.frame_counter = 0;
}
memcpy(dev->sec_ctx.cipher.context.context, value,
IEEE802154_SEC_KEY_LENGTH);
res = IEEE802154_SEC_KEY_LENGTH;
break;
#endif /* IS_USED(MODULE_IEEE802154_SECURITY) */
case NETOPT_ACK_REQ:
if ((*(bool *)value)) {
dev->flags |= NETDEV_IEEE802154_ACK_REQ;
Expand Down Expand Up @@ -283,5 +326,4 @@ int netdev_ieee802154_dst_filter(netdev_ieee802154_t *dev, const uint8_t *mhr)

return 1;
}

/** @} */
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ PSEUDOMODULES += gnrc_txtsnd
PSEUDOMODULES += heap_cmd
PSEUDOMODULES += i2c_scan
PSEUDOMODULES += ieee802154_radio_hal
PSEUDOMODULES += ieee802154_security
PSEUDOMODULES += ieee802154_submac
PSEUDOMODULES += ina3221_alerts
PSEUDOMODULES += l2filter_blacklist
Expand Down
6 changes: 6 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ ifneq (,$(filter sys_bus_%,$(USEMODULE)))
USEMODULE += core_msg_bus
endif

ifneq (,$(filter ieee802154_security,$(USEMODULE)))
USEMODULE += crypto
USEMODULE += crypto_aes
USEMODULE += cipher_modes
endif

ifneq (,$(filter rtt_cmd,$(USEMODULE)))
FEATURES_REQUIRED += periph_rtt
endif
Expand Down
100 changes: 100 additions & 0 deletions sys/include/net/ieee802154/radio.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,64 @@ struct ieee802154_radio_ops {
int (*set_rx_mode)(ieee802154_dev_t *dev, ieee802154_rx_mode_t mode);
};

/**
* @brief Forward declaration of the radio cipher ops structure
*/
typedef struct ieee802154_radio_cipher_ops ieee802154_radio_cipher_ops_t;

/**
* @brief Forward declaration of the IEEE802.15.4 security device descriptor
*/
typedef struct ieee802154_sec_dev ieee802154_sec_dev_t;

/**
* @brief IEEE802.15.4 security device descriptor
*/
struct ieee802154_sec_dev {
/**
* @brief Pointer to the operations of the device
*/
const struct ieee802154_radio_cipher_ops *cipher_ops;
/**
* @brief pointer to the context of the device
*/
void *ctx;
};

struct ieee802154_radio_cipher_ops {
/**
* @brief Function to set the encryption key for the
* next cipher operation
*
* @param[in] dev Security device descriptor
* @param[in] key Key to be used for the next cipher operation
* @param[in] key_size key size in bytes
*/
void (*set_key)(ieee802154_sec_dev_t *dev,
const uint8_t *key, uint8_t key_size);
/**
* @brief Function to perform ECB encryption
*
* @param[in] dev Security device descriptor
* @param[out] cipher Output cipher blocks
* @param[in] plain Input plain blocks
* @param[in] nblocks Number of blocks
*/
void (*ecb)(const ieee802154_sec_dev_t *dev, uint8_t *cipher,
const uint8_t *plain, uint8_t nblocks);
/**
* @brief Function to compute CBC-MAC
*
* @param[in] dev Security device descriptor
* @param[in] cipher Output cipher blocks
* @param[in, out] iv in: IV; out: computed MIC
* @param[in] plain Input plain blocks
* @param[in] nblocks Number of blocks
*/
void (*cbc)(const ieee802154_sec_dev_t *dev, uint8_t *cipher,
uint8_t *iv, const uint8_t *plain, uint8_t nblocks);
};

/**
* @brief Shortcut to @ref ieee802154_radio_ops::write
*
Expand Down Expand Up @@ -1155,6 +1213,48 @@ static inline int ieee802154_radio_set_rx_mode(ieee802154_dev_t *dev,
return dev->driver->set_rx_mode(dev, mode);
}

/**
* @brief Shortcut to ieee802154_sec_dev_t::ieee802154_radio_cipher_ops_t::set_key
*
* @param[in] dev IEEE802.15.4 security device descriptor
* @param[in] key Encryption key
* @param[in] key_size Size of the key in bytes
*/
static inline void ieee802154_radio_cipher_set_key(ieee802154_sec_dev_t *dev,
const uint8_t *key, uint8_t key_size)
{
dev->cipher_ops->set_key(dev->ctx, key, key_size);
}

/**
* @brief Shortcut to ieee802154_sec_dev_t::ieee802154_radio_cipher_ops_t::ecb
*
* @param[in] dev IEEE802.15.4 security device descriptor
* @param[out] cipher Output cipher blocks
* @param[in] plain Input plain blocks
* @param[in] nblocks Number of blocks
*/
static inline void ieee802154_radio_cipher_ecb(const ieee802154_sec_dev_t *dev, uint8_t *cipher,
const uint8_t *plain, uint8_t nblocks)
{
dev->cipher_ops->ecb(dev->ctx, cipher, plain, nblocks);
}

/**
* @brief Shortcut to ieee802154_sec_dev_t::ieee802154_radio_cipher_ops_t::cbc
*
* @param[in] dev IEEE802.15.4 security device descriptor
* @param[out] cipher Output cipher blocks
* @param[in] iv Initial vector to be XOR´ed to the first plain block
* @param[in] plain Input plain blocks
* @param[in] nblocks Number of blocks
*/
static inline void ieee802154_radio_cipher_cbc(const ieee802154_sec_dev_t *dev, uint8_t *cipher,
uint8_t *iv, const uint8_t *plain, uint8_t nblocks)
{
dev->cipher_ops->cbc(dev->ctx, cipher, iv, plain, nblocks);
}

#ifdef __cplusplus
}
#endif
Expand Down
Loading

0 comments on commit 1477a34

Please sign in to comment.