diff --git a/drivers/at86rf2xx/Makefile b/drivers/at86rf2xx/Makefile index 48422e909a..5750f200f5 100644 --- a/drivers/at86rf2xx/Makefile +++ b/drivers/at86rf2xx/Makefile @@ -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 diff --git a/drivers/at86rf2xx/aes_spi.c b/drivers/at86rf2xx/aes_spi.c new file mode 100644 index 0000000000..eb79393e9a --- /dev/null +++ b/drivers/at86rf2xx/aes_spi.c @@ -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 + * @} + */ + +#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); +} diff --git a/drivers/at86rf2xx/include/at86rf2xx_aes.h b/drivers/at86rf2xx/include/at86rf2xx_aes.h new file mode 100644 index 0000000000..f03d9606f2 --- /dev/null +++ b/drivers/at86rf2xx/include/at86rf2xx_aes.h @@ -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 + */ +#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 */ +/** @} */ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 9eb7e96993..6ca6b4bb82 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -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