1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #14113 from fabian18/at86rf2xx_spi_security_module

drivers/at86rf2xx; spi security module (AES)
This commit is contained in:
benpicco 2020-08-12 23:14:12 +02:00 committed by GitHub
commit add10b5fab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 885 additions and 0 deletions

View File

@ -1 +1,7 @@
# exclude submodule sources from *.c wildcard source selection
SRC := $(filter-out aes_spi.c,$(wildcard *.c))
# enable submodules
SUBMODULES := 1
include $(RIOTBASE)/Makefile.base

350
drivers/at86rf2xx/aes_spi.c Normal file
View File

@ -0,0 +1,350 @@
/* Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_at86rf2xx
* @{
*
* @file
* @brief Implementation of at86rf2xx SPI security module (AES)
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
* @}
*/
#include "xtimer.h"
#include "periph/spi.h"
#include "at86rf2xx_aes.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define AES_DEBUG(...) DEBUG("[at86rf2xx_aes_spi]: "__VA_ARGS__)
#define AT86RF2XX_CMD_SRAM_READ (0b00000000)
#define AT86RF2XX_CMD_SRAM_WRITE (0b01000000)
static inline
void at86rf2xx_spi_get_bus(const at86rf2xx_t *dev)
{
spi_acquire(dev->params.spi, dev->params.cs_pin, SPI_MODE_0, dev->params.spi_clk);
}
static inline
void at86rf2xx_spi_release_bus(const at86rf2xx_t *dev)
{
spi_release(dev->params.spi);
}
static inline
uint8_t _aes_status(at86rf2xx_t *dev)
{
spi_transfer_byte(dev->params.spi, dev->params.cs_pin, true,
AT86RF2XX_CMD_SRAM_READ);
spi_transfer_byte(dev->params.spi, dev->params.cs_pin, true,
AT86RF2XX_REG__AES_STATUS);
return spi_transfer_byte(dev->params.spi, dev->params.cs_pin, false, 0);
}
static inline
void _aes_wait_for_result(at86rf2xx_t *dev)
{
xtimer_usleep(AT86RF2XX_AES_DELAY_US);
uint8_t status = _aes_status(dev);
/*
If this assert fires, there probably is an implementation error.
The error bit is set before the transceiver has processed a data block.
There are two cases:
1. The delay between initiating an AES operation and sending the next cfg
to AT86RF2XX_REG__AES_CTRL was too short. Meaning the transceiver
did not have enough time to process the current block.
2. Less then 16 bytes of data have been sent to the transceiver.
Both should not occur in the code.
*/
assert(!(status & AT86RF2XX_AES_STATUS_MASK__AES_ER));
while (!(status & AT86RF2XX_AES_STATUS_MASK__AES_DONE)) {
AES_DEBUG("status: %02x\n", status);
status = _aes_status(dev);
}
}
static inline
void _aes_open_read(at86rf2xx_t *dev, uint8_t addr)
{
spi_transfer_byte(dev->params.spi, dev->params.cs_pin, true,
AT86RF2XX_CMD_SRAM_READ);
spi_transfer_byte(dev->params.spi, dev->params.cs_pin, true,
addr);
}
static inline
void _aes_open_write(at86rf2xx_t *dev, uint8_t addr)
{
spi_transfer_byte(dev->params.spi, dev->params.cs_pin, true,
AT86RF2XX_CMD_SRAM_WRITE);
spi_transfer_byte(dev->params.spi, dev->params.cs_pin, true,
addr);
}
static inline
void _aes_transfer_bytes(at86rf2xx_t *dev, bool cont, const void* out,
void* in, size_t len)
{
spi_transfer_bytes(dev->params.spi, dev->params.cs_pin, cont, out,
in, len);
}
static inline
void _aes_save_key(at86rf2xx_t *dev, uint8_t cfg, uint8_t key[AT86RF2XX_AES_BLOCK_SIZE])
{
_aes_open_write(dev, AT86RF2XX_REG__AES_CTRL);
_aes_transfer_bytes(dev, false, &cfg, NULL, sizeof(cfg));
_aes_open_read(dev, AT86RF2XX_REG__AES_KEY_START);
_aes_transfer_bytes(dev, false, NULL, key, AT86RF2XX_AES_KEY_LENGTH);
}
static inline
void _aes_transfer_block(at86rf2xx_t *dev, uint8_t cfg, uint8_t mirror,
const aes_block_t src, aes_block_t dst)
{
/*
cfg:
value which tells the AES engine what kind of data is coming in
mirror:
must be the same value as cfg but depending on whether the bit
AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST is set, the transceiver
will process the incoming block, or not
src:
current data block of 16 bytes to be sent to the AES engine
dst:
if not NULL, dst stores the processed data block of the
block that has been sent to the AES engine most recently
*/
/* access SRAM register AES_CTRL for writing */
_aes_open_write(dev, AT86RF2XX_REG__AES_CTRL);
/* MOSI: send configuration to the AES_CTRL register */
_aes_transfer_bytes(dev, true, &cfg, NULL, sizeof(cfg));
/* MOSI: send first byte of the current block (block_i) */
_aes_transfer_bytes(dev, true, src, NULL, 1);
/* MOSI: send the last 15 bytes of block_i */
/* MISO: get the first 15 bytes of the most recently processed block (block_i-1) */
_aes_transfer_bytes(dev, true, src + 1, dst, AT86RF2XX_AES_BLOCK_SIZE - 1);
/* MOSI: send the mirrored cfg value and initiate the processing of block_i (or not) */
/* MISO: get the last byte of block_i-1 */
_aes_transfer_bytes(dev, false, &mirror,
dst ? dst + AT86RF2XX_AES_BLOCK_SIZE - 1 : NULL, 1);
}
void at86rf2xx_aes_key_read_encrypt(at86rf2xx_t *dev,
uint8_t key[AT86RF2XX_AES_KEY_LENGTH])
{
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
at86rf2xx_spi_get_bus(dev);
_aes_save_key(dev, cfg, key);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_key_write_encrypt(at86rf2xx_t *dev,
const uint8_t key[AT86RF2XX_AES_KEY_LENGTH])
{
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
at86rf2xx_spi_get_bus(dev);
_aes_open_write(dev, AT86RF2XX_REG__AES_CTRL);
_aes_transfer_bytes(dev, true, &cfg, NULL, sizeof(cfg));
_aes_transfer_bytes(dev, false, key, NULL, AT86RF2XX_AES_KEY_LENGTH);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_key_read_decrypt(at86rf2xx_t *dev,
uint8_t key[AT86RF2XX_AES_KEY_LENGTH])
{
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
at86rf2xx_spi_get_bus(dev);
_aes_save_key(dev, cfg, key);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_key_write_decrypt(at86rf2xx_t *dev,
const uint8_t key[AT86RF2XX_AES_KEY_LENGTH])
{
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
at86rf2xx_spi_get_bus(dev);
_aes_open_write(dev, AT86RF2XX_REG__AES_CTRL);
_aes_transfer_bytes(dev, true, &cfg, NULL, sizeof(cfg));
_aes_transfer_bytes(dev, false, key, NULL, AT86RF2XX_AES_KEY_LENGTH);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_ecb_encrypt(at86rf2xx_t *dev,
aes_block_t *cipher,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *plain,
uint8_t nblocks)
{
if (!nblocks) {
return;
}
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
uint8_t mirror = cfg | AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST;
at86rf2xx_spi_get_bus(dev);
_aes_transfer_block(dev, cfg, mirror, plain[0], NULL);
_aes_wait_for_result(dev);
if (key) {
cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
_aes_save_key(dev, cfg, key);
}
cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
for (unsigned i = 1; i < nblocks; i++) {
_aes_transfer_block(dev, cfg, mirror, plain[i],
cipher ? cipher[i - 1] : NULL);
_aes_wait_for_result(dev);
}
/* send dummy bytes to get the last block of cipher text */
mirror &= ~AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST;
_aes_transfer_block(dev, cfg, mirror, plain[0],
cipher ? cipher[nblocks - 1] : NULL);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_ecb_decrypt(at86rf2xx_t *dev,
aes_block_t *plain,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *cipher,
uint8_t nblocks)
{
if (!nblocks) {
return;
}
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
uint8_t mirror = cfg | AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST;
at86rf2xx_spi_get_bus(dev);
_aes_transfer_block(dev, cfg, mirror, cipher[0], NULL);
_aes_wait_for_result(dev);
if (key) {
cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
_aes_save_key(dev, cfg, key);
}
cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
for (unsigned i = 1; i < nblocks; i++) {
_aes_transfer_block(dev, cfg, mirror, cipher[i],
plain ? plain[i - 1] : NULL);
_aes_wait_for_result(dev);
}
/* send dummy bytes to get the last block of plain text */
mirror &= ~AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST;
_aes_transfer_block(dev, cfg, mirror, cipher[0],
plain ? plain[nblocks - 1] : NULL);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_cbc_encrypt(at86rf2xx_t *dev,
aes_block_t *cipher,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
uint8_t iv[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *plain,
uint8_t nblocks)
{
if (!nblocks) {
return;
}
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
uint8_t mirror = cfg | AT86RF2XX_AES_CTRL_MIRROR_AES_REQUEST__START;
/* The first block has to be ECB encrypted because there is no
cipher result to be XOR´ed from the last round.
Instead an "initial vector" is XOR´ed to the first block
of plain text. */
uint8_t first[AT86RF2XX_AES_BLOCK_SIZE];
for (unsigned i = 0; i < AT86RF2XX_AES_BLOCK_SIZE; i++) {
first[i] = plain[0][i] ^ iv[i];
}
at86rf2xx_spi_get_bus(dev);
_aes_transfer_block(dev, cfg, mirror, first, NULL);
_aes_wait_for_result(dev);
if (key) {
cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
_aes_save_key(dev, cfg, key);
}
cfg = AT86RF2XX_AES_CTRL_AES_MODE__CBC |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
mirror = cfg | AT86RF2XX_AES_CTRL_MIRROR_AES_REQUEST__START;
for (unsigned i = 1; i < nblocks; i++) {
_aes_transfer_block(dev, cfg, mirror, plain[i],
cipher ? cipher[i - 1] : NULL);
_aes_wait_for_result(dev);
}
/* send dummy bytes to get the last block of cipher text */
uint8_t *mac = cipher ? cipher[nblocks - 1] : iv;
mirror &= ~AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST;
_aes_transfer_block(dev, cfg, mirror, plain[0], mac);
at86rf2xx_spi_release_bus(dev);
}
void at86rf2xx_aes_cbc_decrypt(at86rf2xx_t *dev,
aes_block_t *plain,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
uint8_t iv[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *cipher,
uint8_t nblocks)
{
if (!nblocks) {
return;
}
uint8_t cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
uint8_t mirror = cfg | AT86RF2XX_AES_CTRL_MIRROR_AES_REQUEST__START;
at86rf2xx_spi_get_bus(dev);
_aes_transfer_block(dev, cfg, mirror, cipher[0], NULL);
_aes_wait_for_result(dev);
if (key) {
cfg = AT86RF2XX_AES_CTRL_AES_MODE__KEY |
AT86RF2XX_AES_CTRL_AES_DIR__ENC;
_aes_save_key(dev, cfg, key);
}
const uint8_t *xor = iv;
cfg = AT86RF2XX_AES_CTRL_AES_MODE__ECB |
AT86RF2XX_AES_CTRL_AES_DIR__DEC;
for (unsigned i = 1; i < nblocks; i++) {
_aes_transfer_block(dev, cfg, mirror, cipher[i],
plain ? plain[i - 1] : NULL);
_aes_wait_for_result(dev);
if (plain) {
for (unsigned j = 0; j < AT86RF2XX_AES_BLOCK_SIZE; j++) {
plain[i - 1][j] ^= xor[j];
}
xor = cipher[i - 1];
}
}
/* send dummy bytes to get the last block of plain text */
uint8_t *mac = plain ? plain[nblocks - 1] : iv;
mirror &= ~AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST;
_aes_transfer_block(dev, cfg, mirror, cipher[0], mac);
if (plain) {
for (unsigned j = 0; j < AT86RF2XX_AES_BLOCK_SIZE; j++) {
plain[nblocks - 1][j] ^= xor[j];
}
}
at86rf2xx_spi_release_bus(dev);
}

View File

@ -0,0 +1,242 @@
/*
* Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup drivers_at86rf2xx
*
* The extended feature set of at86rf2xx transceivers comprises a
* hardware implementation of AES. There are two supported block
* cipher modes, ECB and CBC.
*
* @{
*
* @file
* @brief Interface of the at86rf2xx security module (AES)
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*/
#ifndef AT86RF2XX_AES_H
#define AT86RF2XX_AES_H
#include "at86rf2xx.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief AES key length in bits
*/
#define AT86RF2XX_AES_KEY_BITS (128U)
/**
* @brief AES key length in bytes
*/
#define AT86RF2XX_AES_KEY_LENGTH ((AT86RF2XX_AES_KEY_BITS) / 8)
/**
* @brief AES block size in bytes
*/
#define AT86RF2XX_AES_BLOCK_SIZE ((AT86RF2XX_AES_KEY_BITS) / 8)
/**
* @brief Time to complete the AES algorithm in us
*/
#define AT86RF2XX_AES_DELAY_US (24)
/**
* @name AES rigister addresses
* @{
*/
#define AT86RF2XX_REG__AES_STATUS (0x82)
#define AT86RF2XX_REG__AES_CTRL (0x83)
#define AT86RF2XX_REG__AES_KEY_START (0x84)
#define AT86RF2XX_REG__AES_KEY_END (0x93)
#define AT86RF2XX_REG__AES_DATA_START (0x84)
#define AT86RF2XX_REG__AES_DATA_END (0x93)
#define AT86RF2XX_REG__AES_CTRL_MIRROR (0x94)
/** @} */
/**
* @name Layout of register AES_STATUS
* @{
*/
#define AT86RF2XX_AES_STATUS_MASK__AES_ER (0x80)
#define AT86RF2XX_AES_STATUS_MASK__AES_DONE (0x01)
#define AT86RF2XX_AES_STATUS_AES_ER__NO_ERROR (0x00)
#define AT86RF2XX_AES_STATUS_AES_ER__ERROR (0x80)
#define AT86RF2XX_AES_STATUS_AES_DONE__NOT_DONE (0x00)
#define AT86RF2XX_AES_STATUS_AES_DONE__DONE (0x01)
/** @} */
/**
* @name Layout of register AES_CTRL
* @{
*/
#define AT86RF2XX_AES_CTRL_MASK__AES_REQUEST (0x80)
#define AT86RF2XX_AES_CTRL_MASK__AES_MODE (0x70)
#define AT86RF2XX_AES_CTRL_MASK__AES_DIR (0x08)
#define AT86RF2XX_AES_CTRL_AES_REQUEST__IDLE (0x00)
#define AT86RF2XX_AES_CTRL_AES_REQUEST__START (0x80)
#define AT86RF2XX_AES_CTRL_AES_MODE__ECB (0x00)
#define AT86RF2XX_AES_CTRL_AES_MODE__KEY (0x10)
#define AT86RF2XX_AES_CTRL_AES_MODE__CBC (0x20)
#define AT86RF2XX_AES_CTRL_AES_DIR__ENC (0x00)
#define AT86RF2XX_AES_CTRL_AES_DIR__DEC (0x08)
/** @} */
/**
* @name Layout of register AES_CTRL_MIRROR
* @{
*/
#define AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_REQUEST (0x80)
#define AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_MODE (0x70)
#define AT86RF2XX_AES_CTRL_MIRROR_MASK__AES_DIR (0x08)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_REQUEST__IDLE (0x00)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_REQUEST__START (0x80)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_MODE__ECB (0x00)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_MODE__KEY (0x10)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_MODE__CBC (0x20)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_DIR__ENC (0x00)
#define AT86RF2XX_AES_CTRL_MIRROR_AES_DIR__DEC (0x08)
/** @} */
/**
* @brief An AES block
*
* AES works on blocks of 16 bytes
*/
typedef uint8_t aes_block_t[AT86RF2XX_AES_BLOCK_SIZE];
/**
* @brief Read the AES key used for encryption
*
* @param[in] dev Device
* @param[out] key Buffer to store the key
*/
void at86rf2xx_aes_key_read_encrypt(at86rf2xx_t *dev,
uint8_t key[AT86RF2XX_AES_KEY_LENGTH]);
/**
* @brief Write the AES key used for encryption
*
* It is important to write the encryption key, before encryption is done
*
* @param[in] dev Device
* @param[in] key Buffer which stores the key
*/
void at86rf2xx_aes_key_write_encrypt(at86rf2xx_t *dev,
const uint8_t key[AT86RF2XX_AES_KEY_LENGTH]);
/**
* @brief Read the AES key used for decryption
*
* @param[in] dev Device
* @param[out] key Buffer to store the key
*/
void at86rf2xx_aes_key_read_decrypt(at86rf2xx_t *dev,
uint8_t key[AT86RF2XX_AES_KEY_LENGTH]);
/**
* @brief Write the AES key used for decryption
*
* It is important to write the decryption key, before decryption is done
*
* @param[in] dev Device
* @param[in] key Buffer which stores the key
*/
void at86rf2xx_aes_key_write_decrypt(at86rf2xx_t *dev,
const uint8_t key[AT86RF2XX_AES_KEY_LENGTH]);
/**
* @brief Perform AES algorithm and encrypt data blocks
* in @p plain to cipher data blocks, using ECB mode
*
* @note The encryption key must have been written before.
*
* @param[in] dev Device
* @param[out] cipher If not NULL, cipher data blocks
* @param[out] key If not NULL, last round encryption key is stored
* @param[in] plain Plain data blocks
* @param[in] nblocks Number of blocks
*/
void at86rf2xx_aes_ecb_encrypt(at86rf2xx_t *dev,
aes_block_t *cipher,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *plain,
uint8_t nblocks);
/**
* @brief Perform AES algorithm and decrypt data blocks
* in @p cipher to plain data blocks, using ECB mode
*
* @note The decryption key must have been written before.
*
* @param[in] dev Device
* @param[out] plain If not NULL, plain data blocks
* @param[out] key If not NULL, last round decryption key is stored
* @param[in] cipher Cipher data blocks
* @param[in] nblocks Number of blocks
*/
void at86rf2xx_aes_ecb_decrypt(at86rf2xx_t *dev,
aes_block_t *plain,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *cipher,
uint8_t nblocks);
/**
* @brief Perform AES algorithm and encrypt data blocks
* in @p plain to cipher data blocks, using CBC mode
*
* @note The encryption key must have been written before.
*
* @param[in] dev Device
* @param[out] cipher If not NULL, cipher blocks
* @param[out] key If not NULL, last round encryption key is stored
* @param[in,out] iv in: initial vector, out: last cipher block if cipher is NULL
* @param[in] plain Plain data blocks
* @param[in] nblocks Number of blocks
*/
void at86rf2xx_aes_cbc_encrypt(at86rf2xx_t *dev,
aes_block_t *cipher,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
uint8_t iv[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *plain,
uint8_t nblocks);
/**
* @brief Perform AES algorithm and decrypt data blocks
* in @p cipher to plain data blocks, using CBC mode
*
* @note The decryption key must have been written before.
*
* @param[in] dev Device
* @param[out] plain If not NUll, plain data blocks
* @param[out] key If not NULL, last round decryption key is stored
* @param[in,out] iv in: initial vector, out: last plain block if plain is NULL
* @param[in] cipher Cipher data blocks
* @param[in] nblocks Number of blocks
*/
void at86rf2xx_aes_cbc_decrypt(at86rf2xx_t *dev,
aes_block_t *plain,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
uint8_t iv[AT86RF2XX_AES_BLOCK_SIZE],
const aes_block_t *cipher,
uint8_t nblocks);
#ifdef __cplusplus
}
#endif
#endif /* AT86RF2XX_AES_H */
/** @} */

View File

@ -132,6 +132,7 @@ PSEUDOMODULES += at86rf23%
PSEUDOMODULES += at86rf21%
PSEUDOMODULES += at86rfa1
PSEUDOMODULES += at86rfr2
PSEUDOMODULES += at86rf2xx_aes_spi
NO_PSEUDOMODULES += at86rf215
# include variants of the BME680 drivers as pseudo modules

View File

@ -0,0 +1,23 @@
include ../Makefile.tests_common
DISABLE_MODULE += auto_init_at86rf2xx
# define the driver to be used for selected boards
ifneq (,$(filter samr21-xpro,$(BOARD)))
DRIVER := at86rf233
endif
ifneq (,$(filter iotlab-m3 fox,$(BOARD)))
DRIVER := at86rf231
endif
ifneq (,$(filter mulle,$(BOARD)))
DRIVER := at86rf212b
endif
# use the at86rf231 as fallback device
DRIVER ?= at86rf231
# include the selected driver
USEMODULE += $(DRIVER)
USEMODULE += at86rf2xx_aes_spi
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,7 @@
BOARD_INSUFFICIENT_MEMORY := \
arduino-duemilanove \
arduino-nano \
arduino-uno \
atmega328p \
stm32f030f4-demo \
#

View File

@ -0,0 +1,238 @@
/*
* Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for at86rf2xx security module (AES)
*
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
* @}
*/
#include <stdio.h>
#include <string.h>
#include "xtimer.h"
#include "at86rf2xx.h"
#include "at86rf2xx_params.h"
#include "at86rf2xx_aes.h"
#ifndef KEY_1
#define KEY_1 { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b, \
0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 }
#endif
#ifndef IV_1
#define IV_1 { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30, \
0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 }
#endif
#ifndef PLAIN_1
#define PLAIN_1 { 'S', 'i', 'n', 'g', 'l', 'e', ' ', 'b', \
'l', 'o', 'c', 'k', ' ', 'm', 's', 'g' }
#endif
#ifndef KEY_2
#define KEY_2 { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, \
0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a }
#endif
#ifndef IV_2
#define IV_2 { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, \
0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 }
#endif
#ifndef PLAIN_2
#define PLAIN_2 { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, \
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, \
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }
#endif
#ifndef KEY_3
#define KEY_3 { 0x6c, 0x3e, 0xa0, 0x47, 0x76, 0x30, 0xce, 0x21, \
0xa2, 0xce, 0x33, 0x4a, 0xa7, 0x46, 0xc2, 0xcd }
#endif
#ifndef IV_3
#define IV_3 { 0xc7, 0x82, 0xdc, 0x4c, 0x09, 0x8c, 0x66, 0xcb, \
0xd9, 0xcd, 0x27, 0xd8, 0x25, 0x68, 0x2c, 0x81 }
#endif
#ifndef PLAIN_3
#define PLAIN_3 { 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', \
'a', ' ', '4', '8', '-', 'b', 'y', 't', \
'e', ' ', 'm', 'e', 's', 's', 'a', 'g', \
'e', ' ', '(', 'e', 'x', 'a', 'c', 't', \
'l', 'y', ' ', '3', ' ', 'A', 'E', 'S', \
' ', 'b', 'l', 'o', 'c', 'k', 's', ')' }
#endif
#ifndef KEY_4
#define KEY_4 { 0x56, 0xe4, 0x7a, 0x38, 0xc5, 0x59, 0x89, 0x74, \
0xbc, 0x46, 0x90, 0x3d, 0xba, 0x29, 0x03, 0x49 }
#endif
#ifndef IV_4
#define IV_4 { 0x8c, 0xe8, 0x2e, 0xef, 0xbe, 0xa0, 0xda, 0x3c, \
0x44, 0x69, 0x9e, 0xd7, 0xdb, 0x51, 0xb7, 0xd9 }
#endif
#ifndef PLAIN_4
#define PLAIN_4 { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, \
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, \
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, \
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, \
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, \
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, \
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, \
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf }
#endif
#ifndef KEY_5
#define KEY_5 { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, \
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf }
#endif
#ifndef IV_5
#define IV_5 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
#endif
#ifndef PLAIN_5
#define PLAIN_5 { 0x59, 0xac, 0xde, 0x48, 0x00, 0x00, 0x00, 0x00, \
0x01, 0x00, 0x00, 0x00, 0x05, 0x06, 0x00, 0x01, \
0x00, 0x1d, 0x2b, 0xdc, 0x84, 0x21, 0x43, 0x02, \
0x00, 0x00, 0x00, 0x00, 0x48, 0xde, 0xac, 0xff, \
0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x48, 0xde, \
0xac, 0x06, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, \
0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
#endif
static void _event_cb(netdev_t *dev, netdev_event_t event)
{
/* Ignore interrupts */
(void)dev;
(void)event;
}
static void _ecb(at86rf2xx_t *dev,
aes_block_t *plain,
uint8_t key[AT86RF2XX_AES_KEY_LENGTH],
aes_block_t *cipher,
uint8_t nblocks)
{
at86rf2xx_aes_key_write_encrypt(dev, key);
at86rf2xx_aes_ecb_encrypt(dev, cipher, key, plain, nblocks);
memset(plain, 0, AT86RF2XX_AES_BLOCK_SIZE * nblocks);
at86rf2xx_aes_key_write_decrypt(dev, key);
at86rf2xx_aes_ecb_decrypt(dev, plain, key, cipher, nblocks);
}
static void _cbc(at86rf2xx_t *dev,
aes_block_t *plain,
uint8_t key[AT86RF2XX_AES_BLOCK_SIZE],
uint8_t iv[AT86RF2XX_AES_BLOCK_SIZE],
aes_block_t *cipher,
uint8_t nblocks)
{
at86rf2xx_aes_key_write_encrypt(dev, key);
at86rf2xx_aes_cbc_encrypt(dev, cipher, key, iv, plain, nblocks);
memset(plain, 0, AT86RF2XX_AES_BLOCK_SIZE * nblocks);
at86rf2xx_aes_key_write_decrypt(dev, key);
at86rf2xx_aes_cbc_decrypt(dev, plain, key, iv, cipher, nblocks);
}
int main(void)
{
at86rf2xx_t dev;
bool success = true;
at86rf2xx_setup(&dev, &at86rf2xx_params[0]);
dev.netdev.netdev.event_callback = _event_cb;
if (dev.netdev.netdev.driver->init(&dev.netdev.netdev) != 0) {
return EXIT_FAILURE;
}
puts("START");
{
uint8_t k[] = KEY_1;
uint8_t p[] = PLAIN_1;
uint8_t c[sizeof(p)];
uint8_t n = sizeof(p) / AT86RF2XX_AES_BLOCK_SIZE;
_ecb(&dev, (aes_block_t *)p, k, (aes_block_t *)c, n);
if (!memcmp(p, (uint8_t[])PLAIN_1, sizeof(p))) {
puts("ECB test 1 done");
}
else {
success = false;
puts("ECB test 1 failed");
}
}
{
uint8_t k[] = KEY_2;
uint8_t p[] = PLAIN_2;
uint8_t c[sizeof(p)];
uint8_t n = sizeof(p) / AT86RF2XX_AES_BLOCK_SIZE;
_ecb(&dev, (aes_block_t *)p, k, (aes_block_t *)c, n);
if (!memcmp(p, (uint8_t[])PLAIN_2, sizeof(p))) {
puts("ECB test 2 done");
}
else {
success = false;
puts("ECB test 2 failed");
}
}
{
uint8_t k[] = KEY_3;
uint8_t v[] = IV_3;
uint8_t p[] = PLAIN_3;
uint8_t c[sizeof(p)];
uint8_t n = sizeof(p) / AT86RF2XX_AES_BLOCK_SIZE;
_cbc(&dev, (aes_block_t *)p, k, v, (aes_block_t *)c, n);
if (!memcmp(p, (uint8_t[])PLAIN_3, sizeof(p))) {
puts("CBC test 1 done");
}
else {
success = false;
puts("CBC test 1 failed");
}
}
{
uint8_t k[] = KEY_4;
uint8_t v[] = IV_4;
uint8_t p[] = PLAIN_4;
uint8_t c[sizeof(p)];
uint8_t n = sizeof(p) / AT86RF2XX_AES_BLOCK_SIZE;
_cbc(&dev, (aes_block_t *)p, k, v, (aes_block_t *)c, n);
if (!memcmp(p, (uint8_t[])PLAIN_4, sizeof(p))) {
puts("CBC test 2 done");
}
else {
success = false;
puts("CBC test 2 failed");
}
}
{
uint8_t k[] = KEY_5;
uint8_t v[] = IV_5;
uint8_t p[] = PLAIN_5;
uint8_t c[sizeof(p)];
uint8_t n = sizeof(p) / AT86RF2XX_AES_BLOCK_SIZE;
_cbc(&dev, (aes_block_t *)p, k, v, (aes_block_t *)c, n);
if (!memcmp(p, (uint8_t[])PLAIN_5, sizeof(p))) {
puts("CBC test 3 done");
}
else {
success = false;
puts("CBC test 3 failed");
}
}
if (success) {
puts("SUCCESS");
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
import sys
from testrunner import run
def testfunc(child):
child.expect('START')
child.expect('ECB test 1 done')
child.expect('ECB test 2 done')
child.expect('CBC test 1 done')
child.expect('CBC test 2 done')
child.expect('CBC test 3 done')
child.expect('SUCCESS')
if __name__ == "__main__":
sys.exit(run(testfunc))