cc2538: aes: Add support for generic operations

Add generic AES functions that should be able to support all the modes
of operation of the hardware AES crypto engine, i.e. ECB, CBC, CTR,
CBC-MAC, GCM, and CCM.

This makes it possible to easily implement these modes of operation
without duplicating code.

Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau.dev@gmail.com>
This commit is contained in:
Benoît Thébaudeau 2015-12-20 22:04:49 +01:00
parent ca919ab0b0
commit baef75752e
4 changed files with 291 additions and 341 deletions

View file

@ -42,9 +42,11 @@
*/
#include "contiki.h"
#include "dev/rom-util.h"
#include "dev/nvic.h"
#include "dev/aes.h"
#include "reg.h"
#include <stdbool.h>
#include <stdint.h>
/*---------------------------------------------------------------------------*/
uint8_t
@ -53,7 +55,7 @@ aes_load_keys(const void *keys, uint8_t key_size, uint8_t count,
{
uint32_t aes_key_store_size;
uint32_t areas;
uint64_t aligned_keys[16];
uint64_t aligned_keys[AES_KEY_AREAS * 128 / 8 / sizeof(uint64_t)];
int i;
if(REG(AES_CTRL_ALG_SEL) != 0x00000000) {
@ -63,7 +65,8 @@ aes_load_keys(const void *keys, uint8_t key_size, uint8_t count,
/* 192-bit keys must be padded to 256 bits */
if(key_size == AES_KEY_STORE_SIZE_KEY_SIZE_192) {
for(i = 0; i < count; i++) {
rom_util_memcpy(&aligned_keys[i << 2], &((uint64_t *)keys)[i * 3], 24);
rom_util_memcpy(&aligned_keys[i << 2], &((const uint64_t *)keys)[i * 3],
192 / 8);
aligned_keys[(i << 2) + 3] = 0;
}
}
@ -148,5 +151,181 @@ aes_load_keys(const void *keys, uint8_t key_size, uint8_t count,
return CRYPTO_SUCCESS;
}
/*---------------------------------------------------------------------------*/
uint8_t
aes_auth_crypt_start(uint32_t ctrl, uint8_t key_area, const void *iv,
const void *adata, uint16_t adata_len,
const void *data_in, void *data_out, uint16_t data_len,
struct process *process)
{
if(REG(AES_CTRL_ALG_SEL) != 0x00000000) {
return CRYPTO_RESOURCE_IN_USE;
}
/* Workaround for AES registers not retained after PM2 */
REG(AES_CTRL_INT_CFG) = AES_CTRL_INT_CFG_LEVEL;
REG(AES_CTRL_INT_EN) = AES_CTRL_INT_EN_DMA_IN_DONE |
AES_CTRL_INT_EN_RESULT_AV;
REG(AES_CTRL_ALG_SEL) = AES_CTRL_ALG_SEL_AES;
REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_IN_DONE |
AES_CTRL_INT_CLR_RESULT_AV;
REG(AES_KEY_STORE_READ_AREA) = key_area;
/* Wait until key is loaded to the AES module */
while(REG(AES_KEY_STORE_READ_AREA) & AES_KEY_STORE_READ_AREA_BUSY);
/* Check for Key Store read error */
if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) {
/* Clear the Keystore Read error bit */
REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_KEY_ST_RD_ERR;
/* Disable the master control / DMA clock */
REG(AES_CTRL_ALG_SEL) = 0x00000000;
return AES_KEYSTORE_READ_ERROR;
}
if(iv != NULL) {
/* Write initialization vector */
REG(AES_AES_IV_0) = ((const uint32_t *)iv)[0];
REG(AES_AES_IV_1) = ((const uint32_t *)iv)[1];
REG(AES_AES_IV_2) = ((const uint32_t *)iv)[2];
REG(AES_AES_IV_3) = ((const uint32_t *)iv)[3];
}
/* Program AES authentication/crypto operation */
REG(AES_AES_CTRL) = ctrl;
/* Write the length of the payload block (lo) */
REG(AES_AES_C_LENGTH_0) = data_len;
/* Write the length of the payload block (hi) */
REG(AES_AES_C_LENGTH_1) = 0;
/* For combined modes only (CCM or GCM) */
if(ctrl & (AES_AES_CTRL_CCM | AES_AES_CTRL_GCM)) {
/* Write the length of the AAD data block (may be non-block size-aligned) */
REG(AES_AES_AUTH_LENGTH) = adata_len;
if(adata_len != 0) {
/* Configure DMAC to fetch the AAD data
* Enable DMA channel 0 */
REG(AES_DMAC_CH0_CTRL) = AES_DMAC_CH_CTRL_EN;
/* Base address of the AAD data buffer */
REG(AES_DMAC_CH0_EXTADDR) = (uint32_t)adata;
/* AAD data length in bytes */
REG(AES_DMAC_CH0_DMALENGTH) = adata_len;
/* Wait for completion of the AAD data transfer, DMA_IN_DONE */
while(!(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_IN_DONE));
/* Check for the absence of error */
if(REG(AES_CTRL_INT_STAT) & AES_CTRL_INT_STAT_DMA_BUS_ERR) {
/* Clear the DMA error */
REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR;
/* Disable the master control / DMA clock */
REG(AES_CTRL_ALG_SEL) = 0x00000000;
return CRYPTO_DMA_BUS_ERROR;
}
}
}
/* Clear interrupt status */
REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_IN_DONE |
AES_CTRL_INT_CLR_RESULT_AV;
if(process != NULL) {
crypto_register_process_notification(process);
nvic_interrupt_unpend(NVIC_INT_AES);
nvic_interrupt_enable(NVIC_INT_AES);
}
/* Enable result available bit in interrupt enable */
REG(AES_CTRL_INT_EN) = AES_CTRL_INT_EN_RESULT_AV;
if(data_len != 0) {
/* Configure DMAC
* Enable DMA channel 0 */
REG(AES_DMAC_CH0_CTRL) = AES_DMAC_CH_CTRL_EN;
/* Base address of the input payload data buffer */
REG(AES_DMAC_CH0_EXTADDR) = (uint32_t)data_in;
/* Input payload data length in bytes */
REG(AES_DMAC_CH0_DMALENGTH) = data_len;
if(data_out != NULL) {
/* Enable DMA channel 1 */
REG(AES_DMAC_CH1_CTRL) = AES_DMAC_CH_CTRL_EN;
/* Base address of the output payload data buffer */
REG(AES_DMAC_CH1_EXTADDR) = (uint32_t)data_out;
/* Output payload data length in bytes */
REG(AES_DMAC_CH1_DMALENGTH) = data_len;
}
}
return CRYPTO_SUCCESS;
}
/*---------------------------------------------------------------------------*/
uint8_t
aes_auth_crypt_check_status(void)
{
return !!(REG(AES_CTRL_INT_STAT) &
(AES_CTRL_INT_STAT_DMA_BUS_ERR | AES_CTRL_INT_STAT_KEY_ST_WR_ERR |
AES_CTRL_INT_STAT_KEY_ST_RD_ERR | AES_CTRL_INT_STAT_RESULT_AV));
}
/*---------------------------------------------------------------------------*/
uint8_t
aes_auth_crypt_get_result(void *iv, void *tag)
{
uint32_t aes_ctrl_int_stat;
aes_ctrl_int_stat = REG(AES_CTRL_INT_STAT);
/* Clear the error bits */
REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_BUS_ERR |
AES_CTRL_INT_CLR_KEY_ST_WR_ERR |
AES_CTRL_INT_CLR_KEY_ST_RD_ERR;
nvic_interrupt_disable(NVIC_INT_AES);
crypto_register_process_notification(NULL);
/* Disable the master control / DMA clock */
REG(AES_CTRL_ALG_SEL) = 0x00000000;
if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_DMA_BUS_ERR) {
return CRYPTO_DMA_BUS_ERROR;
}
if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_KEY_ST_WR_ERR) {
return AES_KEYSTORE_WRITE_ERROR;
}
if(aes_ctrl_int_stat & AES_CTRL_INT_STAT_KEY_ST_RD_ERR) {
return AES_KEYSTORE_READ_ERROR;
}
if(iv != NULL || tag != NULL) {
/* Read result
* Wait for the context ready bit */
while(!(REG(AES_AES_CTRL) & AES_AES_CTRL_SAVED_CONTEXT_READY));
if(iv != NULL) {
/* Read the initialization vector registers */
((uint32_t *)iv)[0] = REG(AES_AES_IV_0);
((uint32_t *)iv)[1] = REG(AES_AES_IV_1);
((uint32_t *)iv)[2] = REG(AES_AES_IV_2);
((uint32_t *)iv)[3] = REG(AES_AES_IV_3);
}
if(tag != NULL) {
/* Read the tag registers */
((uint32_t *)tag)[0] = REG(AES_AES_TAG_OUT_0);
((uint32_t *)tag)[1] = REG(AES_AES_TAG_OUT_1);
((uint32_t *)tag)[2] = REG(AES_AES_TAG_OUT_2);
((uint32_t *)tag)[3] = REG(AES_AES_TAG_OUT_3);
}
}
/* Clear the interrupt status */
REG(AES_CTRL_INT_CLR) = AES_CTRL_INT_CLR_DMA_IN_DONE |
AES_CTRL_INT_CLR_RESULT_AV;
return CRYPTO_SUCCESS;
}
/** @} */