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:
commit
add10b5fab
@ -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
350
drivers/at86rf2xx/aes_spi.c
Normal 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);
|
||||
}
|
242
drivers/at86rf2xx/include/at86rf2xx_aes.h
Normal file
242
drivers/at86rf2xx/include/at86rf2xx_aes.h
Normal 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 */
|
||||
/** @} */
|
@ -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
|
||||
|
23
tests/driver_at86rf2xx_aes/Makefile
Normal file
23
tests/driver_at86rf2xx_aes/Makefile
Normal 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
|
7
tests/driver_at86rf2xx_aes/Makefile.ci
Normal file
7
tests/driver_at86rf2xx_aes/Makefile.ci
Normal file
@ -0,0 +1,7 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
arduino-duemilanove \
|
||||
arduino-nano \
|
||||
arduino-uno \
|
||||
atmega328p \
|
||||
stm32f030f4-demo \
|
||||
#
|
238
tests/driver_at86rf2xx_aes/main.c
Normal file
238
tests/driver_at86rf2xx_aes/main.c
Normal 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;
|
||||
}
|
18
tests/driver_at86rf2xx_aes/tests/01-run.py
Executable file
18
tests/driver_at86rf2xx_aes/tests/01-run.py
Executable 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))
|
Loading…
Reference in New Issue
Block a user