/*
|
* Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
|
* its subsidiaries and affiliates (collectly called MKSEMI).
|
*
|
* All rights reserved.
|
*
|
* Redistribution and use in source and binary forms, with or without
|
* modification, are permitted provided that the following conditions are met:
|
*
|
* 1. Redistributions of source code must retain the above copyright notice,
|
* this list of conditions and the following disclaimer.
|
*
|
* 2. Redistributions in binary form, except as embedded into an MKSEMI
|
* integrated circuit in a product or a software update for such product,
|
* must reproduce the above copyright notice, this list of conditions and
|
* the following disclaimer in the documentation and/or other materials
|
* provided with the distribution.
|
*
|
* 3. Neither the name of MKSEMI nor the names of its contributors may be used
|
* to endorse or promote products derived from this software without
|
* specific prior written permission.
|
*
|
* 4. This software, with or without modification, must only be used with a
|
* MKSEMI integrated circuit.
|
*
|
* 5. Any software provided in binary form under this license must not be
|
* reverse engineered, decompiled, modified and/or disassembled.
|
*
|
* THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
* MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
*/
|
|
#include "mk_aes.h"
|
#include "mk_clock.h"
|
#include "mk_reset.h"
|
#include "mk_trace.h"
|
#include "string.h"
|
|
#if defined(__ICCARM__) && defined(XIP_EN)
|
#pragma default_function_attributes = __ramfunc
|
#endif
|
|
#if AES_DMA_MODE_EN
|
static void aes_dma_callback(void *ch, uint32_t err_code);
|
#endif
|
|
static struct AES_HANDLE_T aes_handle[AES_MAX_NUM] = {
|
{
|
.base = AES,
|
.irq = AES_IRQn,
|
.dma_in_ch = DMA_CH2,
|
.dma_out_ch = DMA_CH3,
|
.config =
|
{
|
.key = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf},
|
.int_en = false,
|
.dma_en = true,
|
.din_burst_size = 1,
|
.dout_burst_size = 1,
|
},
|
},
|
};
|
|
#define MACTAG_IS_VALID(x) \
|
((((aes_handle[x].base->CTRL1) & (AES_CTRL1_MODE(AES_MODE_CCM) | AES_CTRL1_DIR(AES_DIR_DECRYPT))) == \
|
(AES_CTRL1_MODE(AES_MODE_CCM) | AES_CTRL1_DIR(AES_DIR_DECRYPT))) \
|
? (((aes_handle[x].base->STATUS) & AES_STATUS_MIC_VALID_MSK) ? (AES_MIN_VALID) : (AES_MIN_INVALID)) \
|
: (AES_MIN_INVALID))
|
|
int aes_open(enum AES_DEV_T id, struct AES_CFG_T *config)
|
{
|
if (id >= AES_MAX_NUM)
|
{
|
return DRV_ERROR;
|
}
|
else
|
{
|
// check if the AES is using by HW or not
|
|
// enable AES clock
|
clock_enable(CLOCK_AES);
|
reset_module(RESET_MODULE_AES);
|
}
|
|
if (config)
|
{
|
memcpy(&aes_handle[id].config, config, sizeof(struct AES_CFG_T));
|
}
|
|
#if AES_INT_MODE_EN
|
if (aes_handle[id].config.int_en)
|
{
|
NVIC_SetPriority(aes_handle[id].irq, IRQ_PRIORITY_REALTIME);
|
NVIC_ClearPendingIRQ(aes_handle[id].irq);
|
NVIC_EnableIRQ(aes_handle[id].irq);
|
}
|
#endif
|
|
aes_handle[id].state = AES_STATE_READY;
|
|
return DRV_OK;
|
}
|
|
int aes_close(enum AES_DEV_T id)
|
{
|
if (id >= AES_MAX_NUM)
|
{
|
return DRV_ERROR;
|
}
|
// check if the AES is using by HW or not
|
#if AES_INT_MODE_EN
|
if (aes_handle[id].config.int_en)
|
{
|
NVIC_DisableIRQ(aes_handle[id].irq);
|
NVIC_ClearPendingIRQ(aes_handle[id].irq);
|
}
|
#endif
|
// disable AES clock
|
clock_disable(CLOCK_AES);
|
|
aes_handle[id].state = AES_STATE_RESET;
|
|
return DRV_OK;
|
}
|
|
int aes_clear(enum AES_DEV_T id)
|
{
|
// clear AES
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
|
if (aes_handle[id].state == AES_STATE_BUSY)
|
{
|
aes_handle[id].state = AES_STATE_READY;
|
}
|
|
return DRV_OK;
|
}
|
|
int aes_update_key(enum AES_DEV_T id, uint8_t key[16])
|
{
|
memcpy(&aes_handle[id].config.key[0], key, 16);
|
return DRV_OK;
|
}
|
|
void aes_set_state(enum AES_DEV_T id, enum AES_STATE_T state)
|
{
|
aes_handle[id].state |= state;
|
}
|
|
void aes_clr_state(enum AES_DEV_T id, enum AES_STATE_T state)
|
{
|
aes_handle[id].state &= ~state;
|
}
|
|
uint8_t aes_get_state(enum AES_DEV_T id)
|
{
|
return (uint8_t)aes_handle[id].state;
|
}
|
|
#if defined(__GNUC__)
|
#pragma GCC diagnostic push
|
#pragma GCC diagnostic ignored "-Wcast-qual"
|
#endif
|
|
static int aes_engin_run(enum AES_DEV_T id, uint8_t *input, uint8_t *output, uint16_t input_len, uint16_t output_len)
|
{
|
uint32_t lock = int_lock();
|
|
// update state
|
switch (aes_handle[id].state)
|
{
|
case AES_STATE_READY:
|
aes_handle[id].state = AES_STATE_BUSY;
|
break;
|
case AES_STATE_BUSY:
|
int_unlock(lock);
|
return DRV_BUSY;
|
case AES_STATE_BREAK:
|
case AES_STATE_CONFLICT:
|
case AES_STATE_RESET:
|
case AES_STATE_TIMEOUT:
|
case AES_STATE_ERROR:
|
int_unlock(lock);
|
return DRV_ERROR;
|
}
|
|
aes_handle[id].input = input;
|
aes_handle[id].output = output;
|
aes_handle[id].input_len = input_len;
|
aes_handle[id].input_count = 0;
|
aes_handle[id].output_len = output_len;
|
aes_handle[id].output_count = 0;
|
int_unlock(lock);
|
|
// start AES engin
|
aes_handle[id].base->CTRL0 = AES_CTRL0_START_MSK;
|
|
if (aes_handle[id].config.dma_en)
|
{
|
#if AES_DMA_MODE_EN
|
// enable DMA
|
aes_handle[id].base->DMA_EN = AES_DMA_EN_DIN_DMA_EN_MSK | AES_DMA_EN_DOUT_DMA_EN_MSK |
|
AES_DMA_EN_DIN_DMA_BURST_SIZE(aes_handle[id].config.din_burst_size) |
|
AES_DMA_EN_DIUT_DMA_BURST_SIZE(aes_handle[id].config.dout_burst_size);
|
|
struct DMA_CH_CFG_T aes_out_dma_cfg = {
|
.fifo_th = DMA_FIFO_TH_1,
|
.src_burst_size = DMA_SRC_BURST_SIZE_1,
|
.src_width = DMA_WIDTH_1B,
|
.dst_width = DMA_WIDTH_1B,
|
.src_addr_ctrl = DMA_ADDR_FIXED,
|
.dst_addr_ctrl = DMA_ADDR_INC,
|
.src_req_sel = DMA_REQ_AES_TX,
|
.dst_req_sel = DMA_REQ_MEM,
|
};
|
|
dma_open(aes_handle[id].dma_out_ch, &aes_out_dma_cfg);
|
dma_transfer(aes_handle[id].dma_out_ch, (uint8_t *)&aes_handle[id].base->DOUT, output, output_len, aes_dma_callback);
|
|
struct DMA_CH_CFG_T aes_in_dma_cfg = {
|
.fifo_th = DMA_FIFO_TH_1,
|
.src_burst_size = DMA_SRC_BURST_SIZE_1,
|
.src_width = DMA_WIDTH_1B,
|
.dst_width = DMA_WIDTH_1B,
|
.src_addr_ctrl = DMA_ADDR_INC,
|
.dst_addr_ctrl = DMA_ADDR_FIXED,
|
.src_req_sel = DMA_REQ_MEM,
|
.dst_req_sel = DMA_REQ_AES_RX,
|
};
|
|
dma_open(aes_handle[id].dma_in_ch, &aes_in_dma_cfg);
|
// bump up DMA IRQ priority for calling AES from interrupt handler
|
NVIC_SetPriority(DMA_IRQn, IRQ_PRIORITY_REALTIME);
|
dma_transfer(aes_handle[id].dma_in_ch, input, (uint8_t *)&aes_handle[id].base->DIN, input_len, NULL);
|
#endif
|
}
|
else if (aes_handle[id].config.int_en)
|
{
|
#if AES_INT_MODE_EN
|
// write the first block data in
|
uint32_t tx_free = GET_BIT_FIELD(aes_handle[id].base->STATUS, AES_STATUS_DIN_BUF_SPACE_MSK, AES_STATUS_DIN_BUF_SPACE_POS);
|
uint8_t len = (uint8_t)MIN(tx_free, aes_handle[id].input_len - aes_handle[id].input_count);
|
for (uint8_t i = 0; i < len; i++)
|
{
|
REG_WRITE_BYTE(&aes_handle[id].base->DIN, aes_handle[id].input[aes_handle[id].input_count + i]);
|
}
|
aes_handle[id].input_count += len;
|
// enable interrupt
|
aes_handle[id].base->INTR_EN =
|
AES_INTR_EN_DONE_EN_MSK | AES_INTR_EN_DIN_OVERFLOW_EN_MSK | AES_INTR_EN_DIN_EMPTY_EN_MSK | AES_INTR_EN_DOUT_NOT_EMPTY_EN_MSK;
|
#endif
|
}
|
else
|
{
|
#if AES_POLL_MODE_EN
|
// polling
|
while ((aes_handle[id].input_count < aes_handle[id].input_len) || (aes_handle[id].output_count < aes_handle[id].output_len))
|
{
|
// write a block data in
|
uint32_t tx_free = GET_BIT_FIELD(aes_handle[id].base->STATUS, AES_STATUS_DIN_BUF_SPACE_MSK, AES_STATUS_DIN_BUF_SPACE_POS);
|
uint8_t len = (uint8_t)MIN(tx_free, aes_handle[id].input_len - aes_handle[id].input_count);
|
for (uint8_t i = 0; i < len; i++)
|
{
|
REG_WRITE_BYTE(&aes_handle[id].base->DIN, aes_handle[id].input[aes_handle[id].input_count + i]);
|
}
|
aes_handle[id].input_count += len;
|
|
// read a block result out
|
uint32_t rx_cnt = GET_BIT_FIELD(aes_handle[id].base->STATUS, AES_STATUS_DOUT_BUF_CNT_MSK, AES_STATUS_DOUT_BUF_CNT_POS);
|
len = (uint8_t)MIN(rx_cnt, aes_handle[id].output_len - aes_handle[id].output_count);
|
for (uint8_t i = 0; i < len; i++)
|
{
|
aes_handle[id].output[aes_handle[id].output_count + i] = REG_READ_BYTE(&aes_handle[id].base->DOUT);
|
}
|
aes_handle[id].output_count += len;
|
}
|
|
uint8_t aes_state = aes_get_state(id);
|
if (aes_state & AES_STATE_BREAK)
|
{
|
return DRV_ERROR;
|
}
|
else if (aes_state & AES_STATE_CONFLICT)
|
{
|
return DRV_ERROR;
|
}
|
|
aes_handle[id].is_valid = MACTAG_IS_VALID(id);
|
|
// update state
|
aes_handle[id].state = AES_STATE_READY;
|
|
if (aes_handle[id].callback)
|
{
|
aes_handle[id].callback(&id, aes_handle[id].output_count);
|
}
|
#endif
|
}
|
|
return DRV_OK;
|
}
|
|
static int aes_encrypt(enum AES_DEV_T id, uint8_t *input, uint8_t *output, uint16_t input_len, uint16_t output_len)
|
{
|
aes_handle[id].base->CTRL1 &= ~AES_CTRL1_DIR_MSK;
|
|
return aes_engin_run(id, input, output, input_len, output_len);
|
}
|
|
static int aes_decrypt(enum AES_DEV_T id, uint8_t *input, uint8_t *output, uint16_t input_len, uint16_t output_len)
|
{
|
aes_handle[id].base->CTRL1 |= AES_CTRL1_DIR_MSK;
|
|
// derive decipher key
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
// save CTRL1 register
|
uint32_t ctrl1 = aes_handle[id].base->CTRL1;
|
aes_handle[id].base->CTRL1 = AES_CTRL1_MODE(AES_MODE_DKEY);
|
aes_handle[id].base->CTRL0 = AES_CTRL0_START_MSK;
|
|
// wait decipher key ready, this is pretty fast.
|
while ((aes_handle[id].base->STATUS & AES_STATUS_DONE_MSK) == 0)
|
{
|
}
|
|
// restore CTRL1
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
aes_handle[id].base->CTRL1 = ctrl1;
|
|
return aes_engin_run(id, input, output, input_len, output_len);
|
}
|
|
int aes_crypt_ecb(enum AES_DEV_T id, enum AES_DIR_T mode, uint8_t *input, uint8_t *output, uint16_t len, drv_callback_t callback)
|
{
|
ASSERT(output != NULL, "output address is NULL");
|
ASSERT(((len % 16) == 0) && (len >= 16), "len invalid");
|
|
aes_handle[id].callback = callback;
|
|
// 1. clear AES
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
|
// 2. configure mode and direction (encryption or decryption)
|
aes_handle[id].base->CTRL1 = AES_CTRL1_MODE(AES_MODE_ECB) | AES_CTRL1_DIR(mode);
|
|
// 3. configure payload length
|
aes_handle[id].base->CTRL2 = AES_CTRL2_PLEN(len);
|
|
// 4. configure key
|
memcpy((uint8_t *)&aes_handle[id].base->KEY[0], &aes_handle[id].config.key[0], 16);
|
|
if (mode == AES_DIR_ENCRYPT)
|
{
|
return aes_encrypt(id, input, output, len, len);
|
}
|
else if (mode == AES_DIR_DECRYPT)
|
{
|
return aes_decrypt(id, input, output, len, len);
|
}
|
return DRV_ERROR;
|
}
|
|
int aes_crypt_cbc(enum AES_DEV_T id, enum AES_DIR_T mode, uint8_t iv[16], uint8_t *input, uint8_t *output, uint16_t len, drv_callback_t callback)
|
{
|
ASSERT(output != NULL, "output address is NULL");
|
ASSERT(((len % 16) == 0) && (len >= 16), "len invalid");
|
|
aes_handle[id].callback = callback;
|
|
// 1. clear AES
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
|
// 2. configure mode and direction (encryption or decryption)
|
aes_handle[id].base->CTRL1 = AES_CTRL1_MODE(AES_MODE_CBC) | AES_CTRL1_DIR(mode);
|
|
// 3. configure payload length
|
aes_handle[id].base->CTRL2 = AES_CTRL2_PLEN(len);
|
|
// 4. configure key
|
memcpy((uint8_t *)&aes_handle[id].base->KEY[0], &aes_handle[id].config.key[0], 16);
|
|
// 5. configure iv
|
memcpy((uint8_t *)&aes_handle[id].base->IV[0], iv, 16);
|
|
if (mode == AES_DIR_ENCRYPT)
|
{
|
return aes_encrypt(id, input, output, len, len);
|
}
|
else if (mode == AES_DIR_DECRYPT)
|
{
|
return aes_decrypt(id, input, output, len, len);
|
}
|
return DRV_ERROR;
|
}
|
|
int aes_crypt_ctr(enum AES_DEV_T id, uint8_t initial_counter[16], uint8_t *input, uint8_t *output, uint16_t len, drv_callback_t callback)
|
{
|
ASSERT(output != NULL, "output address is NULL");
|
ASSERT(((len % 16) == 0) && (len >= 16), "len invalid");
|
|
aes_handle[id].callback = callback;
|
|
// 1. clear AES
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
|
// 2. configure mode
|
aes_handle[id].base->CTRL1 = AES_CTRL1_MODE(AES_MODE_CTR) | AES_CTRL1_DIR(AES_DIR_ENCRYPT);
|
|
// 3. configure payload length
|
aes_handle[id].base->CTRL2 = AES_CTRL2_PLEN(len);
|
|
// 4. configure key
|
memcpy((uint8_t *)&aes_handle[id].base->KEY[0], &aes_handle[id].config.key[0], 16);
|
|
// 5. configure initial counter
|
memcpy((uint8_t *)&aes_handle[id].base->IV[0], initial_counter, 16);
|
|
return aes_encrypt(id, input, output, len, len);
|
}
|
|
int aes_crypt_ccm(enum AES_DEV_T id, enum AES_CCM_MODE opt, struct AES_CCM_CONTEXT_T *cxt, drv_callback_t callback)
|
{
|
ASSERT(cxt != NULL, "cxt is NULL");
|
uint8_t q;
|
uint8_t i;
|
uint8_t CTR_ZERO[16];
|
uint16_t data_len;
|
int ret = 0;
|
enum AES_DIR_T mode;
|
if ((AES_CCM_ENCRYPT_AND_AUTH == opt) || (AES_CCM_DECRYPT_AND_AUTH == opt))
|
{
|
// CCM mac size [4, 6, 8, 10, 12, 14, 16]
|
if ((cxt->mac_size < 4) || (cxt->mac_size > 16) || ((cxt->mac_size & 0x01) != 0))
|
{
|
ret = MK_AES_CCM_ERROR_MAC_SIZE;
|
goto err;
|
}
|
// CCM nonce size [7 ... 13]
|
if ((cxt->nonce_size < 7) || (cxt->nonce_size > 16))
|
{
|
ret = MK_AES_CCM_ERROR_NONCE_SIZE;
|
goto err;
|
}
|
}
|
else
|
{
|
// CCM* mac size [0, 4, 8, 16]
|
if ((cxt->mac_size | 0x1C) != 0x1C)
|
{
|
ret = MK_AES_CCM_ERROR_MAC_SIZE;
|
goto err;
|
}
|
// CCM* nonce size [13] */
|
if (cxt->nonce_size != 13)
|
{
|
ret = MK_AES_CCM_ERROR_NONCE_SIZE;
|
goto err;
|
}
|
}
|
if ((AES_CCM_ENCRYPT_AND_AUTH == opt) || (AES_CCM_STAR_ENCRYPT_AND_AUTH == opt))
|
{
|
mode = AES_DIR_ENCRYPT;
|
if (cxt->output_buf_size < (cxt->data_in_len + cxt->mac_size))
|
{
|
ret = MK_AES_CCM_ERROR_OUTPUT_BUF_NOT_ENOUGH;
|
goto err;
|
}
|
}
|
else
|
{
|
mode = AES_DIR_DECRYPT;
|
if (cxt->output_buf_size < (cxt->data_in_len - cxt->mac_size))
|
{
|
ret = MK_AES_CCM_ERROR_OUTPUT_BUF_NOT_ENOUGH;
|
goto err;
|
}
|
}
|
|
// The maximum length of authentication data supported by the MK8000 is 65517 bytes
|
if (cxt->adata_len > 0xFFED)
|
{
|
ret = MK_AES_CCM_ERROR_ADATA_LEN_NOT_SUPPORT;
|
goto err;
|
}
|
|
if (cxt->input_buf_size < (cxt->adata_len + cxt->data_in_len + 18))
|
{
|
ret = MK_AES_CCM_ERROR_INPUT_BUF_NOT_ENOUGH;
|
goto err;
|
}
|
|
// Formatting of B0
|
/* |----------------------------------------------|
|
* |Octet number | 0 | 1....15-q | 16-q...15 |
|
* |----------------------------------------------|
|
* |Contents | Flags | Nonce | q |
|
* |----------------------------------------------|
|
*/
|
// Formatting of the Flags Octet in B0
|
// tag_size - The octet length of the MAC
|
/* |----------------------------------------------------------------------------------|
|
* |Bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
* |----------------------------------------------------------------------------------|
|
* |Contents | Reserved | Adata | (tag_size-2)/2 | q-1 |
|
* |----------------------------------------------------------------------------------|
|
*/
|
// q = Block Size - 1 byte(flags) - Nonce size
|
q = 16 - 1 - cxt->nonce_size;
|
// B0 Initialize
|
cxt->input_buf[0] = (cxt->adata_len > 0) ? 0x40 : 0x00;
|
cxt->input_buf[0] |= ((cxt->mac_size - 2) / 2) << 3;
|
cxt->input_buf[0] |= q - 1;
|
memcpy(cxt->input_buf + 1, cxt->nonce, cxt->nonce_size);
|
|
if (AES_DIR_ENCRYPT == mode)
|
{
|
for (i = 0, data_len = cxt->data_in_len; i < q; i++, data_len >>= 8)
|
{
|
cxt->input_buf[15 - i] = (uint8_t)(data_len & 0xFF);
|
}
|
}
|
else
|
{
|
for (i = 0, data_len = (cxt->data_in_len - cxt->mac_size); i < q; i++, data_len >>= 8)
|
{
|
cxt->input_buf[15 - i] = (uint8_t)(data_len & 0xFF);
|
}
|
}
|
|
// Formatting of B1
|
// If 0 < auth_data_len < 2^16-2^8, then auth_data_len is encoded as [a]16, two octets.
|
// If 2^16-2^8 <= auth_data_len <= 2^32, then auth_data_len is encoded as 0xff || 0xfe || [a]32, six octets.
|
// If 2^32 <= auth_data_len <= 2^64, then auth_data_len is encoded as 0xff || 0xff || [a]64, ten octets.
|
// note - padding to a block boundary
|
/* |-------------------------------------------------------|
|
* |Octet number | 0-1 | 2-16 |
|
* |-------------------------------------------------------|
|
* | 0 < a < 2^16-2^8 | 2 bytes | 14 bytes auth_data |
|
* |-------------------------------------------------------|
|
* |-------------------------------------------------------|
|
* | 2^16-2^8 <= a <= 2^32 | 6 bytes | 10 bytes auth_data |
|
* |-------------------------------------------------------|
|
* |-------------------------------------------------------|
|
* | 2^16-2^8 <= a <= 2^32 | 10 bytes | 6 bytes auth_data |
|
* |-------------------------------------------------------|
|
*
|
* auth_data_len = 65536, auth_data[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
|
* eg. encoded 0xFF || 0xFE || [len]32 auth_data[10]
|
* 0xFF 0xFE 0x00 0x01 0x00 0x00 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
|
*/
|
|
// B1 Initialize
|
if (cxt->adata_len > 0)
|
{
|
cxt->input_buf[16] = (uint8_t)((cxt->adata_len >> 8) & 0xFF);
|
cxt->input_buf[17] = (uint8_t)(cxt->adata_len & 0xFF);
|
memcpy(cxt->input_buf + 18, cxt->adata, cxt->adata_len);
|
data_len = 18 + cxt->adata_len;
|
}
|
else
|
{
|
data_len = 16;
|
}
|
|
if ((uint32_t)cxt->data_in != (uint32_t)cxt->input_buf + data_len)
|
{
|
memcpy(cxt->input_buf + data_len, cxt->data_in, cxt->data_in_len);
|
}
|
// Formatting of CTRi
|
/* |----------------------------------------------|
|
* |Octet number | 0 | 1....15-q | 16-q...15 |
|
* |----------------------------------------------|
|
* |Contents | Flags | Nonce | q(Counter) |
|
* |----------------------------------------------|
|
*/
|
// Formatting of the Flags Field in CTRi
|
/* |--------------------------------------------------------------------------|
|
* |Bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
* |--------------------------------------------------------------------------|
|
* |Contents | Reserved | Reserved | 0 | 0 | 0 | q-1 |
|
* |--------------------------------------------------------------------------|
|
*/
|
// Initialize CTR0
|
// The counter starts counting from 0
|
memset(CTR_ZERO, 0, 16);
|
// Flags = q - 1
|
CTR_ZERO[0] = q - 1;
|
// copy nonce
|
memcpy(CTR_ZERO + 1, cxt->nonce, cxt->nonce_size);
|
|
aes_handle[id].callback = callback;
|
|
// 1. clear AES
|
aes_handle[id].base->CTRL0 = AES_CTRL0_CLEAR_MSK;
|
if (AES_DIR_ENCRYPT == mode)
|
{
|
// 2. configure mode
|
aes_handle[id].base->CTRL1 = AES_CTRL1_MODE(AES_MODE_CCM) | AES_CTRL1_MIC_LEN(cxt->mac_size);
|
|
// 3. configure payload length, and associate length (include 16 bytes nonce)
|
aes_handle[id].base->CTRL2 = AES_CTRL2_PLEN(cxt->data_in_len) | AES_CTRL2_ALEN(data_len);
|
}
|
else
|
{
|
// 2. configure mode
|
aes_handle[id].base->CTRL1 = AES_CTRL1_MODE(AES_MODE_CCM) | AES_CTRL1_MIC_LEN(cxt->mac_size);
|
|
// 3. configure payload length, and associate length (include 16 bytes nonce)
|
aes_handle[id].base->CTRL2 = AES_CTRL2_PLEN(cxt->data_in_len - cxt->mac_size) | AES_CTRL2_ALEN(data_len);
|
}
|
|
// 4. configure key
|
memcpy((uint8_t *)&aes_handle[id].base->KEY[0], &aes_handle[id].config.key[0], 16);
|
|
// 5. configure initial counter
|
memcpy((uint8_t *)&aes_handle[id].base->IV[0], CTR_ZERO, 16);
|
|
if (AES_DIR_ENCRYPT == mode)
|
{
|
ret = aes_encrypt(id, cxt->input_buf, cxt->output_buf, data_len + cxt->data_in_len, cxt->data_in_len + cxt->mac_size);
|
}
|
else
|
{
|
ret = aes_decrypt(id, cxt->input_buf, cxt->output_buf, data_len + cxt->data_in_len, cxt->data_in_len - cxt->mac_size);
|
}
|
|
err:
|
#if 0
|
switch (ret)
|
{
|
case MK_AES_CCM_ERROR_MAC_SIZE:
|
LOG_INFO(TRACE_MODULE_DRIVER, "MAC size ERR\r\n");
|
break;
|
case MK_AES_CCM_ERROR_NONCE_SIZE:
|
LOG_INFO(TRACE_MODULE_DRIVER, "Nonce size ERR\r\n");
|
break;
|
case MK_AES_CCM_ERROR_INPUT_BUF_NOT_ENOUGH:
|
LOG_INFO(TRACE_MODULE_DRIVER, "Insufficient input buffer space ERR\r\n");
|
break;
|
case MK_AES_CCM_ERROR_OUTPUT_BUF_NOT_ENOUGH:
|
LOG_INFO(TRACE_MODULE_DRIVER, "Insufficient output buffer space ERR\r\n");
|
break;
|
case MK_AES_CCM_ERROR_ADATA_LEN_NOT_SUPPORT:
|
LOG_INFO(TRACE_MODULE_DRIVER, "Length of authentication data shall be limited to 65517 bytes\r\n");
|
break;
|
}
|
#else
|
if (ret)
|
{
|
LOG_ERROR(TRACE_MODULE_DRIVER, "AES ERR code %d\r\n", ret);
|
}
|
#endif
|
return ret;
|
}
|
|
enum AES_MIN_CHE_T aes_ccm_dec_mic_isvalid(enum AES_DEV_T id)
|
{
|
return aes_handle[id].is_valid;
|
}
|
|
#if AES_DMA_MODE_EN
|
static void aes_dma_callback(void *ch, uint32_t err_code)
|
{
|
enum AES_DEV_T id = AES_ID0;
|
uint8_t ch_num = *(uint8_t *)ch;
|
|
if (ch_num == aes_handle[id].dma_out_ch)
|
{
|
if (err_code == DMA_INT_TYPE_DONE)
|
{
|
// finished - update statue
|
aes_handle[id].state = AES_STATE_READY;
|
}
|
else
|
{
|
aes_handle[id].state |= AES_STATE_ERROR;
|
}
|
|
aes_handle[id].is_valid = MACTAG_IS_VALID(id);
|
|
if (aes_handle[id].callback)
|
{
|
aes_handle[id].callback(&id, aes_handle[id].output_len);
|
}
|
|
// restore DMA IRQ priority
|
NVIC_SetPriority(DMA_IRQn, IRQ_PRIORITY_HIGH);
|
}
|
else
|
{
|
ASSERT(0, "Unexpected dma channel\r\n");
|
}
|
}
|
#endif
|
|
void AES_IRQHandler(void)
|
{
|
#if AES_INT_MODE_EN
|
enum AES_DEV_T id = AES_ID0;
|
|
uint8_t len = 0;
|
uint32_t int_stat = aes_handle[id].base->INTR_STATUS;
|
|
aes_handle[id].is_valid = MACTAG_IS_VALID(id);
|
|
if (int_stat & AES_INTR_STATUS_DIN_OVERFLOW_MSK)
|
{
|
// clear interrupt status
|
aes_handle[id].base->INTR_STATUS = AES_INTR_STATUS_DIN_OVERFLOW_MSK;
|
ASSERT(0, "AES input overflow\r\n");
|
}
|
else if (int_stat & AES_INTR_STATUS_DOUT_UNDERFLOW_MSK)
|
{
|
// clear interrupt status
|
aes_handle[id].base->INTR_STATUS = AES_INTR_STATUS_DOUT_UNDERFLOW_MSK;
|
LOG_INFO(TRACE_MODULE_DRIVER, "AES output underflow\r\n");
|
}
|
else if (int_stat & AES_INTR_STATUS_DONE_MSK)
|
{
|
// clear interrupt status
|
aes_handle[id].base->INTR_STATUS = AES_INTR_STATUS_DONE_MSK;
|
// LOG_INFO(TRACE_MODULE_DRIVER, "AES done\r\n");
|
}
|
else
|
{
|
if (int_stat & AES_INTR_STATUS_DIN_EMPTY_MSK)
|
{
|
len = (uint8_t)MIN(16, aes_handle[id].input_len - aes_handle[id].input_count);
|
if (len)
|
{
|
for (uint8_t i = 0; i < len; i++)
|
{
|
REG_WRITE_BYTE(&aes_handle[id].base->DIN, aes_handle[id].input[aes_handle[id].input_count + i]);
|
}
|
aes_handle[id].input_count += len;
|
}
|
else
|
{
|
// disable tx empty interrupt
|
aes_handle[id].base->INTR_EN &= ~AES_INTR_EN_DIN_EMPTY_EN_MSK;
|
}
|
}
|
|
if (int_stat & AES_INTR_STATUS_DOUT_NOT_EMPTY_MSK)
|
{
|
uint32_t rx_cnt = GET_BIT_FIELD(aes_handle[id].base->STATUS, AES_STATUS_DOUT_BUF_CNT_MSK, AES_STATUS_DOUT_BUF_CNT_POS);
|
len = (uint8_t)MIN(rx_cnt, aes_handle[id].output_len - aes_handle[id].output_count);
|
for (uint8_t i = 0; i < len; i++)
|
{
|
uint8_t byte = REG_READ_BYTE(&aes_handle[id].base->DOUT);
|
aes_handle[id].output[aes_handle[id].output_count + i] = byte;
|
}
|
aes_handle[id].output_count += len;
|
}
|
|
if (aes_handle[id].output_count >= aes_handle[id].output_len)
|
{
|
// done - update state
|
aes_handle[id].state = AES_STATE_READY;
|
|
// disable all interrupt
|
aes_handle[id].base->INTR_EN = 0;
|
|
if (aes_handle[id].callback)
|
{
|
aes_handle[id].callback(&id, aes_handle[id].output_count);
|
}
|
}
|
}
|
#endif
|
}
|
|
#if defined(__GNUC__)
|
#pragma GCC diagnostic pop
|
#endif
|
|
#if defined(__ICCARM__) && defined(XIP_EN)
|
#pragma default_function_attributes =
|
#endif
|