diff options
Diffstat (limited to 'FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes')
-rw-r--r-- | FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.c | 525 | ||||
-rw-r--r-- | FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.h | 54 |
2 files changed, 579 insertions, 0 deletions
diff --git a/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.c b/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.c new file mode 100644 index 000000000..f1e88973c --- /dev/null +++ b/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * @file ck_aes.c + * @brief CSI Source File for aes driver + * @version V1.0 + * @date 02. June 2017 + ******************************************************************************/ +#include <string.h> +#include "csi_core.h" +#include "drv_aes.h" +#include "ck_aes.h" + +#define ERR_AES(errno) (CSI_DRV_ERRNO_AES_BASE | errno) +#define AES_NULL_PARA_CHK(para) \ + do { \ + if (para == NULL) { \ + return ERR_AES(EDRV_PARAMETER); \ + } \ + } while (0) +static ck_aes_reg_t *aes_reg = NULL; +volatile static uint8_t block_cal_done = 0; + +typedef struct { + uint32_t base; + uint32_t irq; + void *iv; + uint8_t *result_out; + uint32_t len; + aes_event_cb_t cb; + aes_mode_e mode; + aes_key_len_bits_e keylen; + aes_endian_mode_e endian; + aes_crypto_mode_e enc; + aes_status_t status; +} ck_aes_priv_t; + +extern int32_t target_get_aes_count(void); +extern int32_t target_get_aes(int32_t idx, uint32_t *base, uint32_t *irq); + +static ck_aes_priv_t aes_handle[CONFIG_AES_NUM]; + +/* Driver Capabilities */ +static const aes_capabilities_t driver_capabilities = { + .ecb_mode = 1, /* ECB mode */ + .cbc_mode = 1, /* CBC mode */ + .cfb_mode = 0, /* CFB mode */ + .ofb_mode = 0, /* OFB mode */ + .ctr_mode = 0, /* CTR mode */ + .bits_128 = 1, /* 128bits key length mode */ + .bits_192 = 1, /* 192bits key lenght mode */ + .bits_256 = 1 /* 256bits key length mode */ +}; + +extern int32_t target_get_aes(int32_t idx, uint32_t *base, uint32_t *irq); +extern int32_t target_get_aes_count(void); +// +// Functions +// + +static inline void aes_set_opcode(aes_crypto_mode_e opcode) +{ + aes_reg->ctrl &= ~(3 << AES_OPCODE_OFFSET); //clear bit[7:6] + aes_reg->ctrl |= (opcode << AES_OPCODE_OFFSET); //set opcode +} + +static inline void aes_set_endian(aes_endian_mode_e endian) +{ + if (endian == AES_ENDIAN_LITTLE) { + aes_reg->ctrl &= ~AES_LITTLE_ENDIAN; + } else { + aes_reg->ctrl |= AES_LITTLE_ENDIAN; + } +} + +static inline uint32_t aes_set_keylen(aes_key_len_bits_e keylength) +{ + aes_reg->ctrl &= ~(3 << AES_KEY_LEN_OFFSET); //clear bit[5:4] + aes_reg->ctrl |= (keylength << AES_KEY_LEN_OFFSET);// Set key length + + return 0; +} + +static inline void aes_set_mode(aes_mode_e mode) +{ + aes_reg->ctrl &= ~(1 << AES_MODE_OFFSET); //clear bit 3 + aes_reg->ctrl |= (mode << AES_MODE_OFFSET); //set mode +} + +static inline void aes_enable(void) +{ + aes_reg->ctrl |= (1 << AES_WORK_ENABLE_OFFSET); +} + +static inline void aes_disable(void) +{ + aes_reg->ctrl &= ~(1 << AES_WORK_ENABLE_OFFSET); +} + +static inline void aes_enable_interrupt(void) +{ + aes_reg->ctrl |= (1 << AES_INT_ENABLE_OFFSET); +} + +static inline void aes_disable_interrupt(void) +{ + aes_reg->ctrl &= ~(1 << AES_INT_ENABLE_OFFSET); +} + +static inline void aes_clear_interrupt(void) +{ + aes_reg->state = 0x0; +} + +static inline uint32_t aes_get_intstatus(uint32_t AES_IT) +{ + return (aes_reg->state & AES_IT) ? 1 : 0; +} + +static void aes_set_key(void *context, uint8_t *key, aes_key_len_bits_e keylen, uint32_t enc, uint32_t endian) +{ + uint8_t keynum = 0; + + if (keylen == AES_KEY_LEN_BITS_128) { + keynum = 4; + } else if (keylen == AES_KEY_LEN_BITS_192) { + keynum = 6; + } else if (keylen == AES_KEY_LEN_BITS_256) { + keynum = 8; + } + + uint32_t i; + uint32_t temp = 0; + /* set key according to the endian mode */ + if (endian == AES_ENDIAN_LITTLE) { + for (i = 0; i < keynum; i++) { + temp = key[3] << 24 | key[2] << 16 | key[1] << 8 | key[0]; + aes_reg->key[keynum - 1 - i] = temp; + key += 4; + } + } else if (endian == AES_ENDIAN_BIG) { + for (i = 0; i < keynum; i++) { + temp = key[3] << 24 | key[2] << 16 | key[1] << 8 | key[0]; + aes_reg->key[i] = temp; + key += 4; + } + } + + if (enc == AES_CRYPTO_MODE_DECRYPT) { + aes_set_opcode(AES_CRYPTO_KEYEXP); /* if the mode is decrypt before decrypt you have to keyexpand */ + aes_enable(); +// while(block_cal_done == 0); +// block_cal_done = 0; + + while (aes_get_intstatus(AES_IT_KEYINT)); + + aes_set_opcode(AES_CRYPTO_MODE_DECRYPT); + } else if (enc == AES_CRYPTO_MODE_ENCRYPT) { + aes_set_opcode(AES_CRYPTO_MODE_ENCRYPT); + } + + aes_disable(); +} + +static void aes_set_iv(uint32_t mode, uint32_t endian, uint8_t *iv) +{ + uint32_t temp; + uint32_t i; + /* set iv if the mode is CBC */ + if (mode == AES_MODE_CBC) { + if (endian == AES_ENDIAN_BIG) { + for (i = 0; i < 4; i++) { + temp = iv[3] << 24 | iv[2] << 16 | iv[1] << 8 | iv[0]; + aes_reg->iv[i] = temp; + iv += 4; + } + } else if (endian == AES_ENDIAN_LITTLE) { + for (i = 0; i < 4; i++) { + temp = iv[3] << 24 | iv[2] << 16 | iv[1] << 8 | iv[0]; + aes_reg->iv[3 - i] = temp; + iv += 4; + } + } + } +} + +static int aes_crypto(void *context, uint8_t *in, uint8_t *out, + uint32_t len, uint8_t *iv, uint32_t mode, uint32_t endian, uint32_t enc) +{ + + uint32_t temp[4]; + aes_set_iv(mode, endian, iv); + + uint32_t i = 0; + uint32_t j = 0; + /* set the text before aes calculating */ + for (i = 0; i < len; i = i + 16) { + for (j = 0; j < 4; j++) { + temp[j] = in[3] << 24 | in[2] << 16 | in[1] << 8 | in[0]; + if (endian == AES_ENDIAN_BIG) { + aes_reg->datain[j] = temp[j]; + } else if (endian == AES_ENDIAN_LITTLE) { + aes_reg->datain[3 - j] = temp[j]; + } + + in += 4; + } + aes_enable(); + + while(block_cal_done == 0); + block_cal_done = 0; + + if (enc == AES_CRYPTO_MODE_ENCRYPT && mode == AES_MODE_CBC) { + aes_set_iv(mode, endian, out); + memcpy(iv, out, 16); + out += 16; + } else if (enc == AES_CRYPTO_MODE_DECRYPT && mode == AES_MODE_CBC) { + aes_set_iv(mode, endian, (uint8_t *)&temp); + memcpy(iv, temp, 16); + } + } + + return 0; +} + +void ck_aes_irqhandler(int32_t idx) +{ + ck_aes_priv_t *aes_priv = &aes_handle[idx]; + + volatile uint32_t j; + uint32_t tmp = 0; + /* get the result after aes calculating*/ + if (aes_priv->result_out != NULL) { + for (j = 0; j < 4; j++) { + if (aes_priv->endian == AES_ENDIAN_BIG) { + tmp = aes_reg->dataout[j]; + } else if (aes_priv->endian == AES_ENDIAN_LITTLE) { + tmp = aes_reg->dataout[3 - j]; + } + + memcpy(aes_priv->result_out, &tmp, 4); + aes_priv->result_out += 4; + aes_priv->len -= 4; + } + } + + block_cal_done = 1; + /* disable aes and clear the aes interrupt */ + aes_disable(); + aes_clear_interrupt(); + + /* execute the callback function */ + if (aes_priv->len == 0) { + if (aes_priv->cb) { + aes_priv->cb(AES_EVENT_CRYPTO_COMPLETE); + } + } +} + +/** + \brief get aes instance count. + \return aes handle count +*/ +int32_t csi_aes_get_instance_count(void) +{ + return target_get_aes_count(); +} + +/** + \brief Initialize AES Interface. 1. Initializes the resources needed for the AES interface 2.registers event callback function + \param[in] idx must not exceed return value of csi_aes_get_instance_count(). + \param[in] cb_event Pointer to \ref aes_event_cb_t + \return return aes handle if success +*/ +aes_handle_t csi_aes_initialize(int32_t idx, aes_event_cb_t cb_event) +{ + + if (idx < 0 || idx >= CONFIG_AES_NUM) { + return NULL; + } + + uint32_t irq = 0u; + uint32_t base = 0u; + /* obtain the aes information */ + int32_t real_idx = target_get_aes(idx, &base, &irq); + + if (real_idx != idx) { + return NULL; + } + + ck_aes_priv_t *aes_priv = &aes_handle[idx]; + + aes_priv->base = base; + aes_priv->irq = irq; + + /* initialize the aes context */ + aes_reg = (ck_aes_reg_t *)(aes_priv->base); + aes_priv->cb = cb_event; + aes_priv->iv = NULL; + aes_priv->len = 16; + aes_priv->result_out = NULL; + aes_priv->mode = AES_MODE_CBC; + aes_priv->keylen = AES_KEY_LEN_BITS_128; + aes_priv->endian = AES_ENDIAN_LITTLE; + aes_priv->status.busy = 0; + + aes_enable_interrupt(); /* enable the aes interrupt */ + + drv_nvic_enable_irq(aes_priv->irq); /* enable the aes bit in nvic */ + + return (aes_handle_t)aes_priv; +} + +/** + \brief De-initialize AES Interface. stops operation and releases the software resources used by the interface + \param[in] handle aes handle to operate. + \return error code +*/ +int32_t csi_aes_uninitialize(aes_handle_t handle) +{ + AES_NULL_PARA_CHK(handle); + + ck_aes_priv_t *aes_priv = handle; + aes_priv->cb = NULL; + + aes_disable_interrupt(); /* disable the aes interrupt */ + + drv_nvic_disable_irq(aes_priv->irq); + + return 0; +} + +/** + \brief Get driver capabilities. + \param[in] handle aes handle to operate. + \return \ref aes_capabilities_t +*/ +aes_capabilities_t csi_aes_get_capabilities(aes_handle_t handle) +{ + return driver_capabilities; +} + +/** + \brief config aes mode. + \param[in] handle aes handle to operate. + \param[in] mode \ref aes_mode_e + \param[in] keylen_bits \ref aes_key_len_bits_e + \param[in] endian \ref aes_endian_mode_e + \param[in] arg Pointer to the iv address when mode is cbc_mode + \return error code +*/ +int32_t csi_aes_config(aes_handle_t handle, aes_mode_e mode, aes_key_len_bits_e keylen_bits, aes_endian_mode_e endian, uint32_t arg) +{ + AES_NULL_PARA_CHK(handle); + + ck_aes_priv_t *aes_priv = handle; + aes_reg = (ck_aes_reg_t *)(aes_priv->base); + + /* config the aes mode */ + switch (mode) { + case AES_MODE_CBC: + aes_priv->iv = (void *)arg; + aes_priv->mode = mode; + aes_set_mode(mode); + break; + + case AES_MODE_ECB: + aes_priv->mode = mode; + aes_set_mode(mode); + break; + + case AES_MODE_CFB: + case AES_MODE_OFB: + case AES_MODE_CTR: + return ERR_AES(EDRV_UNSUPPORTED); + + default: + return ERR_AES(EDRV_PARAMETER); + } + + /* config the key length */ + switch (keylen_bits) { + case AES_KEY_LEN_BITS_128: + case AES_KEY_LEN_BITS_192: + case AES_KEY_LEN_BITS_256: + aes_priv->keylen = keylen_bits; + aes_set_keylen(keylen_bits); + break; + + default: + return ERR_AES(EDRV_PARAMETER); + } + + /* config the endian mode */ + switch (endian) { + case AES_ENDIAN_LITTLE: + aes_priv->endian = endian; + aes_set_endian(endian); + break; + + case AES_ENDIAN_BIG: + aes_priv->endian = endian; + aes_set_endian(endian); + break; + + default: + return ERR_AES(EDRV_PARAMETER); + } + + return 0; +} + +/** + \brief set crypto key. + \param[in] handle aes handle to operate. + \param[in] context aes information context(NULL when hardware implementation) + \param[in] key Pointer to the key buf + \param[in] key_len Pointer to the aes_key_len_bits_e + \param[in] enc \ref aes_crypto_mode_e + \return error code +*/ +int32_t csi_aes_set_key(aes_handle_t handle, void *context, void *key, aes_key_len_bits_e key_len, aes_crypto_mode_e enc) +{ + AES_NULL_PARA_CHK(handle); + AES_NULL_PARA_CHK(key); + if ((key_len != AES_KEY_LEN_BITS_128 && + key_len != AES_KEY_LEN_BITS_192 && + key_len != AES_KEY_LEN_BITS_256) || + (enc != AES_CRYPTO_MODE_ENCRYPT && + enc != AES_CRYPTO_MODE_DECRYPT)) { + return ERR_AES(EDRV_PARAMETER); + } + + ck_aes_priv_t *aes_priv = handle; + aes_priv->enc = enc; + aes_set_key(context, key, key_len, enc, aes_priv->endian); + + return 0; +} + +/** + \brief encrypt or decrypt + \param[in] handle aes handle to operate. + \param[in] context aes information context(NULL when hardware implementation) + \param[in] in Pointer to the Source data + \param[out] out Pointer to the Result data. + \param[in] len the Source data len. + \param[in] padding \ref aes_padding_mode_e. + \return error code +*/ +int32_t csi_aes_crypto(aes_handle_t handle, void *context, void *in, void *out, uint32_t len, aes_padding_mode_e padding) +{ + AES_NULL_PARA_CHK(handle); + AES_NULL_PARA_CHK(in); + AES_NULL_PARA_CHK(out); + AES_NULL_PARA_CHK(len); + + ck_aes_priv_t *aes_priv = handle; + + aes_priv->status.busy = 1; + + uint8_t left_len = len & 0xf; + switch (padding) { + case AES_PADDING_MODE_NO: + if (left_len) { + return ERR_AES(EDRV_PARAMETER); + } + + /* crypto in padding no mode */ + aes_priv->result_out = out; + aes_priv->len = len; + aes_crypto(context, in, out, len, aes_priv->iv, aes_priv->mode, aes_priv->endian, aes_priv->enc); + break; + + case AES_PADDING_MODE_ZERO: + if (left_len == 0) { + return ERR_AES(EDRV_PARAMETER); + } + + uint8_t i = 0; + for (i = 0; i < (16 - left_len); i++) { + *((uint8_t *)in + len + i) = 0x0; + } + + /* crypto in padding zero mode */ + aes_priv->result_out = out; + aes_priv->len = len + 16 -left_len; + aes_crypto(context, in, out, len + 16 - left_len, aes_priv->iv, aes_priv->mode, aes_priv->endian, aes_priv->enc); + break; + + case AES_PADDING_MODE_PKCS5: + return ERR_AES(EDRV_UNSUPPORTED); + + default: + return ERR_AES(EDRV_PARAMETER); + } + + aes_priv->status.busy = 0; + return 0; +} + +/** + \brief Get AES status. + \param[in] handle aes handle to operate. + \return AES status \ref aes_status_t +*/ +aes_status_t csi_aes_get_status(aes_handle_t handle) +{ + ck_aes_priv_t *aes_priv = handle; + return aes_priv->status; +} diff --git a/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.h b/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.h new file mode 100644 index 000000000..976ccad61 --- /dev/null +++ b/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 C-SKY Microsystems Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/****************************************************************************** + * @file ck_aes.h + * @brief header file for aes driver + * @version V1.0 + * @date 02. June 2017 + ******************************************************************************/ +#ifndef _CK_AES_H_ +#define _CK_AES_H_ + +#include <stdio.h> +#include "drv_aes.h" +#include "soc.h" + +#define AES_LITTLE_ENDIAN 0x00000100 + +#define AES_MAX_KEY_LENGTH 32 +#define AES_IT_DATAINT 0x4 +#define AES_IT_KEYINT 0x2 +#define AES_IT_BUSY 0x1 +#define AES_IT_ALL 0x7 +#define AES_CRYPTO_KEYEXP 0x2 + +#define AES_WORK_ENABLE_OFFSET 0 +#define AES_INT_ENABLE_OFFSET 2 +#define AES_MODE_OFFSET 3 +#define AES_KEY_LEN_OFFSET 4 +#define AES_OPCODE_OFFSET 6 + +typedef struct { + __IOM uint32_t datain[4]; /* Offset: 0x000 (R/W) Data input 0~127 */ + __IOM uint32_t key[8]; /* Offset: 0x010 (R/W) Key 0~255 */ + __IOM uint32_t iv[4]; /* Offset: 0x030 (R/W) Initial Vector: 0~127 */ + __IOM uint32_t ctrl; /* Offset: 0x040 (R/W) AES Control Register */ + __IOM uint32_t state; /* Offset: 0x044 (R/W) AES State Register */ + __IOM uint32_t dataout[4]; /* Offset: 0x048 (R/W) Data Output 0~31 */ +} ck_aes_reg_t; + +#endif |