summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes
diff options
context:
space:
mode:
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.c525
-rw-r--r--FreeRTOS/Demo/T-HEAD_CB2201_CDK/csi/csi_driver/csky/common/aes/ck_aes.h54
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