/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.c
C | 525 lines | 350 code | 82 blank | 93 comment | 82 complexity | 5cabbf6000808fd65ae01ec8c630e429 MD5 | raw file
- /*
- * 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;
- }