From dfd527ee484a2724d84d1288bd8ecf777aa9617f Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 17 Jul 2024 16:28:33 +0200 Subject: [PATCH 1/4] drivers: crypto: Add support for cc23x0 AES Add support for AES module to cc23x0 SoC. The driver supports the following modes: - ECB encryption only (since decryption is not supported by the HW) - CTR - CCM Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- drivers/crypto/CMakeLists.txt | 1 + drivers/crypto/Kconfig | 1 + drivers/crypto/Kconfig.cc23x0 | 15 + drivers/crypto/crypto_cc23x0.c | 689 +++++++++++++++++++++++++ dts/bindings/crypto/ti,cc23x0-aes.yaml | 15 + 5 files changed, 721 insertions(+) create mode 100644 drivers/crypto/Kconfig.cc23x0 create mode 100644 drivers/crypto/crypto_cc23x0.c create mode 100644 dts/bindings/crypto/ti,cc23x0-aes.yaml diff --git a/drivers/crypto/CMakeLists.txt b/drivers/crypto/CMakeLists.txt index 59d02d44ad97..5094377abb13 100644 --- a/drivers/crypto/CMakeLists.txt +++ b/drivers/crypto/CMakeLists.txt @@ -14,4 +14,5 @@ zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA crypto_it8xxx2_sha.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_IT8XXX2_SHA_V2 crypto_it8xxx2_sha_v2.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_MCUX_DCP crypto_mcux_dcp.c) zephyr_library_sources_ifdef(CONFIG_CRYPTO_SI32 crypto_si32.c) +zephyr_library_sources_ifdef(CONFIG_CRYPTO_CC23X0 crypto_cc23x0.c) zephyr_library_link_libraries_ifdef(CONFIG_MBEDTLS mbedTLS) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index a1b147b12bfa..9a7bdb89b54e 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -84,5 +84,6 @@ source "drivers/crypto/Kconfig.it8xxx2" source "drivers/crypto/Kconfig.mcux_dcp" source "drivers/crypto/Kconfig.si32" source "drivers/crypto/Kconfig.smartbond" +source "drivers/crypto/Kconfig.cc23x0" endif # CRYPTO diff --git a/drivers/crypto/Kconfig.cc23x0 b/drivers/crypto/Kconfig.cc23x0 new file mode 100644 index 000000000000..8e2cae28536a --- /dev/null +++ b/drivers/crypto/Kconfig.cc23x0 @@ -0,0 +1,15 @@ +# CC23X0 AES accelerator configuration options + +# Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +config CRYPTO_CC23X0 + bool "CC23X0 AES accelerator driver" + default y + depends on DT_HAS_TI_CC23X0_AES_ENABLED + help + Enable TI CC23X0 AES accelerator driver. + This driver supports the following modes: + - ECB (Electronic Code Book) encryption only (decryption not supported by the hardware) + - CTR (Counter) + - CCM (CTR with CBC-MAC) diff --git a/drivers/crypto/crypto_cc23x0.c b/drivers/crypto/crypto_cc23x0.c new file mode 100644 index 000000000000..09f79567d57e --- /dev/null +++ b/drivers/crypto/crypto_cc23x0.c @@ -0,0 +1,689 @@ +/* + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_aes + +#include +LOG_MODULE_REGISTER(crypto_cc23x0, CONFIG_CRYPTO_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#define CRYPTO_CC23_CAP (CAP_RAW_KEY | CAP_SEPARATE_IO_BUFS | \ + CAP_SYNC_OPS | CAP_NO_IV_PREFIX) + +#define CRYPTO_CC23_INT_MASK AES_IMASK_AESDONE + +/* CCM mode: see https://datatracker.ietf.org/doc/html/rfc3610 for reference */ +#define CCM_CC23_MSG_LEN_SIZE_MIN 2 +#define CCM_CC23_MSG_LEN_SIZE_MAX 8 + +#define CCM_CC23_NONCE_LEN_SIZE_MIN (AES_BLOCK_SIZE - CCM_CC23_MSG_LEN_SIZE_MAX - 1) +#define CCM_CC23_NONCE_LEN_SIZE_MAX (AES_BLOCK_SIZE - CCM_CC23_MSG_LEN_SIZE_MIN - 1) + +#define CCM_CC23_AD_LEN_SIZE 2 +#define CCM_CC23_AD_DATA_SIZE_MAX (AES_BLOCK_SIZE - CCM_CC23_AD_LEN_SIZE) + +#define CCM_CC23_TAG_SIZE_MIN 4 +#define CCM_CC23_TAG_SIZE_MAX 16 + +#define CCM_CC23_BYTE_GET(idx, val) FIELD_GET(0xff << ((idx) << 3), (val)) + +#define CCM_CC23_B0_GET(ad_len, tag_len, len_size) \ + (((ad_len) ? 1 << 6 : 0) + (((tag_len) - 2) << 2) + ((len_size) - 1)) + +/* + * The Finite State Machine (FSM) processes the data in a column-fashioned way, + * processing 2 columns/cycle, completing 10 rounds in 20 cycles. With three cycles + * of pre-processing, the execution/encryption time is 23 cycles. + */ +#define CRYPTO_CC23_OP_TIMEOUT K_CYC(23 << 1) + +struct crypto_cc23x0_data { + struct k_mutex device_mutex; + struct k_sem aes_done; +}; + +static void crypto_cc23x0_isr(const struct device *dev) +{ + struct crypto_cc23x0_data *data = dev->data; + uint32_t status; + + status = AESGetMaskedInterruptStatus(); + + if (status & AES_IMASK_AESDONE) { + k_sem_give(&data->aes_done); + } + + AESClearInterrupt(status); +} + +static void crypto_cc23x0_cleanup(void) +{ + AESClearAUTOCFGTrigger(); + AESClearAUTOCFGBusHalt(); + AESClearTXTAndBUF(); +} + +static int crypto_cc23x0_ecb_encrypt(struct cipher_ctx *ctx, struct cipher_pkt *pkt) +{ + const struct device *dev = ctx->device; + struct crypto_cc23x0_data *data = dev->data; + int in_bytes_processed = 0; + int out_bytes_processed = 0; + int ret; + + if (pkt->out_buf_max < ROUND_UP(pkt->in_len, AES_BLOCK_SIZE)) { + LOG_ERR("Output buffer too small"); + return -EINVAL; + } + + k_mutex_lock(&data->device_mutex, K_FOREVER); + + /* Load key */ + AESWriteKEY(ctx->key.bit_stream); + + /* Configure source buffer and encryption triggers */ + AESSetAUTOCFG(AES_AUTOCFG_AESSRC_BUF | + AES_AUTOCFG_TRGAES_RDTXT3 | + AES_AUTOCFG_TRGAES_WRBUF3S); + + /* Write first block of input to trigger encryption */ + AESWriteBUF(pkt->in_buf); + in_bytes_processed += AES_BLOCK_SIZE; + + do { + if (in_bytes_processed < pkt->in_len) { + /* Preload next input block */ + AESWriteBUF(&pkt->in_buf[in_bytes_processed]); + in_bytes_processed += AES_BLOCK_SIZE; + } else { + /* Avoid triggering a spurious encryption upon reading the final output */ + AESClearAUTOCFGTrigger(); + } + + /* Wait for AES operation completion */ + ret = k_sem_take(&data->aes_done, CRYPTO_CC23_OP_TIMEOUT); + if (ret) { + goto cleanup; + } + + LOG_DBG("AES operation completed"); + + /* + * Read output and trigger encryption of next input that was + * preloaded at the start of this loop. + */ + AESReadTXT(&pkt->out_buf[out_bytes_processed]); + out_bytes_processed += AES_BLOCK_SIZE; + } while (out_bytes_processed < pkt->in_len); + +cleanup: + crypto_cc23x0_cleanup(); + k_mutex_unlock(&data->device_mutex); + pkt->out_len = out_bytes_processed; + + return ret; +} + +static int crypto_cc23x0_ctr(struct cipher_ctx *ctx, struct cipher_pkt *pkt, uint8_t *iv) +{ + const struct device *dev = ctx->device; + struct crypto_cc23x0_data *data = dev->data; + uint32_t ctr_len = ctx->mode_params.ctr_info.ctr_len >> 3; + uint8_t ctr[AES_BLOCK_SIZE] = { 0 }; + uint8_t last_buf[AES_BLOCK_SIZE] = { 0 }; + int bytes_remaining = pkt->in_len; + int bytes_processed = 0; + int block_size; + int iv_len; + int ret; + + if (pkt->out_buf_max < ROUND_UP(pkt->in_len, AES_BLOCK_SIZE)) { + LOG_ERR("Output buffer too small"); + return -EINVAL; + } + + k_mutex_lock(&data->device_mutex, K_FOREVER); + + /* Load key */ + AESWriteKEY(ctx->key.bit_stream); + + /* Configure source buffer and encryption triggers */ + AESSetAUTOCFG(AES_AUTOCFG_AESSRC_BUF | + AES_AUTOCFG_TRGAES_RDTXT3 | + AES_AUTOCFG_TRGAES_WRBUF3S | + AES_AUTOCFG_CTRENDN_BIGENDIAN | + AES_AUTOCFG_CTRSIZE_CTR128); + + /* Write the counter value to the AES engine to trigger first encryption */ + iv_len = (ctx->ops.cipher_mode == CRYPTO_CIPHER_MODE_CCM) ? + AES_BLOCK_SIZE : (ctx->keylen - ctr_len); + memcpy(ctr, iv, iv_len); + AESWriteBUF(ctr); + + do { + /* Wait for AES operation completion */ + ret = k_sem_take(&data->aes_done, CRYPTO_CC23_OP_TIMEOUT); + if (ret) { + goto cleanup; + } + + LOG_DBG("AES operation completed"); + + /* XOR input data with encrypted counter block to form ciphertext */ + if (bytes_remaining > AES_BLOCK_SIZE) { + block_size = AES_BLOCK_SIZE; + AESWriteTXTXOR(&pkt->in_buf[bytes_processed]); + } else { + block_size = bytes_remaining; + memcpy(last_buf, &pkt->in_buf[bytes_processed], block_size); + AESWriteTXTXOR(last_buf); + + /* + * Do not auto-trigger encrypt and increment of counter + * value for last block of data. + */ + AESClearAUTOCFGTrigger(); + } + + /* + * Read the output ciphertext and trigger the encryption + * of the next counter block + */ + AESReadTXT(&pkt->out_buf[bytes_processed]); + + bytes_processed += block_size; + bytes_remaining -= block_size; + } while (bytes_remaining > 0); + +cleanup: + crypto_cc23x0_cleanup(); + k_mutex_unlock(&data->device_mutex); + pkt->out_len = bytes_processed; + + return ret; +} + +static int crypto_cc23x0_cmac(struct cipher_ctx *ctx, struct cipher_pkt *pkt, + uint8_t *b0, uint8_t *b1) +{ + const struct device *dev = ctx->device; + struct crypto_cc23x0_data *data = dev->data; + uint32_t iv[AES_BLOCK_SIZE_WORDS] = { 0 }; + uint8_t last_buf[AES_BLOCK_SIZE] = { 0 }; + int bytes_remaining = pkt->in_len; + int bytes_processed = 0; + int block_size; + int ret; + + if (pkt->out_buf_max < AES_BLOCK_SIZE) { + LOG_ERR("Output buffer too small"); + return -EINVAL; + } + + k_mutex_lock(&data->device_mutex, K_FOREVER); + + /* Load key */ + AESWriteKEY(ctx->key.bit_stream); + + /* Configure source buffer and encryption triggers */ + AESSetAUTOCFG(AES_AUTOCFG_AESSRC_TXTXBUF | + AES_AUTOCFG_TRGAES_WRBUF3 | + AES_AUTOCFG_BUSHALT_EN); + + /* Write zero'd IV */ + AESWriteIV32(iv); + + if (b0) { + /* Load input block */ + AESWriteBUF(b0); + + /* Wait for AES operation completion */ + ret = k_sem_take(&data->aes_done, CRYPTO_CC23_OP_TIMEOUT); + if (ret) { + goto out; + } + + LOG_DBG("AES operation completed (block 0)"); + } + + if (b1) { + /* Load input block */ + AESWriteBUF(b1); + + /* Wait for AES operation completion */ + ret = k_sem_take(&data->aes_done, CRYPTO_CC23_OP_TIMEOUT); + if (ret) { + goto out; + } + + LOG_DBG("AES operation completed (block 1)"); + } + + do { + /* Load input block */ + if (bytes_remaining >= AES_BLOCK_SIZE) { + block_size = AES_BLOCK_SIZE; + AESWriteBUF(&pkt->in_buf[bytes_processed]); + } else { + block_size = bytes_remaining; + memcpy(last_buf, &pkt->in_buf[bytes_processed], block_size); + AESWriteBUF(last_buf); + } + + /* Wait for AES operation completion */ + ret = k_sem_take(&data->aes_done, CRYPTO_CC23_OP_TIMEOUT); + if (ret) { + goto out; + } + + LOG_DBG("AES operation completed (data)"); + + bytes_processed += block_size; + bytes_remaining -= block_size; + } while (bytes_remaining > 0); + + /* Read tag */ + AESReadTag(pkt->out_buf); + +out: + crypto_cc23x0_cleanup(); + k_mutex_unlock(&data->device_mutex); + pkt->out_len = bytes_processed; + + return ret; +} + +static int crypto_cc23x0_ccm_check_param(struct cipher_ctx *ctx, struct cipher_aead_pkt *aead_op) +{ + uint16_t ad_len = aead_op->ad_len; + uint16_t tag_len = ctx->mode_params.ccm_info.tag_len; + uint16_t nonce_len = ctx->mode_params.ccm_info.nonce_len; + + if (aead_op->pkt->out_buf_max < ROUND_UP(aead_op->pkt->in_len, AES_BLOCK_SIZE)) { + LOG_ERR("Output buffer too small"); + return -EINVAL; + } + + if (tag_len < CCM_CC23_TAG_SIZE_MIN || tag_len > CCM_CC23_TAG_SIZE_MAX || tag_len & 1) { + LOG_ERR("CCM parameter invalid (tag_len must be an even value from %d to %d)", + CCM_CC23_TAG_SIZE_MIN, CCM_CC23_TAG_SIZE_MAX); + return -EINVAL; + } + + if (nonce_len < CCM_CC23_NONCE_LEN_SIZE_MIN || nonce_len > CCM_CC23_NONCE_LEN_SIZE_MAX) { + LOG_ERR("CCM parameter invalid (nonce_len must be a value from %d to %d)", + CCM_CC23_NONCE_LEN_SIZE_MIN, CCM_CC23_NONCE_LEN_SIZE_MAX); + return -EINVAL; + } + + if (ad_len > CCM_CC23_AD_DATA_SIZE_MAX) { + LOG_ERR("CCM parameter invalid (ad_len max = %d)", CCM_CC23_AD_DATA_SIZE_MAX); + return -EINVAL; + } + + return 0; +} + +static int crypto_cc23x0_ccm_encrypt(struct cipher_ctx *ctx, + struct cipher_aead_pkt *aead_op, uint8_t *nonce) +{ + struct cipher_pkt tag_pkt = { 0 }; + struct cipher_pkt data_pkt = { 0 }; + uint8_t tag[AES_BLOCK_SIZE] = { 0 }; + uint8_t b0[AES_BLOCK_SIZE] = { 0 }; + uint8_t b1[AES_BLOCK_SIZE] = { 0 }; + uint8_t ctri[AES_BLOCK_SIZE] = { 0 }; + uint32_t msg_len = aead_op->pkt->in_len; + uint16_t ad_len = aead_op->ad_len; + uint16_t tag_len = ctx->mode_params.ccm_info.tag_len; + uint16_t nonce_len = ctx->mode_params.ccm_info.nonce_len; + uint8_t len_size = AES_BLOCK_SIZE - nonce_len - 1; + int ret; + int i; + + ret = crypto_cc23x0_ccm_check_param(ctx, aead_op); + if (ret) { + return ret; + } + + /* + * Build the first block B0 required for CMAC computation. + * ============================================ + * Block B0 formatting per RFC3610: + * Octet Number Contents + * ------------ --------- + * 0 Flags + * 1 ... 15-L Nonce N + * 16-L ... 15 l(m), MSB first + * + * Flags in octet 0 of B0: + * Bit Number Contents + * ---------- ---------------------- + * 7 Reserved (always zero) + * 6 Adata = 1 if l(a) > 0, 0 otherwise + * 5 ... 3 M' = (M - 2) / 2 where M = Number of octets in authentication field + * 2 ... 0 L' = L - 1 where L = Number of octets in length field + * ============================================ + */ + b0[0] = CCM_CC23_B0_GET(aead_op->ad_len, tag_len, len_size); + + for (i = 0 ; i < sizeof(msg_len) ; i++) { + b0[AES_BLOCK_SIZE - 1 - i] = CCM_CC23_BYTE_GET(i, msg_len); + } + + memcpy(&b0[1], nonce, nonce_len); + + /* + * Build the second block B1 for additional data (header). + * ============================================ + * Block B1 formatting per RFC3610, for 0 < l(a) < (2^16 - 2^8): + * Octet Number Contents + * ------------ --------- + * 0 ... 1 l(a), MSB first + * 2 ... N Header data + * N+1 ... 15 Zero padding + * ============================================ + */ + for (i = 0 ; i < sizeof(ad_len) ; i++) { + b1[CCM_CC23_AD_LEN_SIZE - 1 - i] = CCM_CC23_BYTE_GET(i, ad_len); + } + + memcpy(&b1[CCM_CC23_AD_LEN_SIZE], aead_op->ad, ad_len); + + /* Calculate the authentication tag by passing B0, B1, and data to CMAC function. */ + LOG_DBG("Compute CMAC"); + + data_pkt.in_buf = aead_op->pkt->in_buf; + data_pkt.in_len = aead_op->pkt->in_len; + data_pkt.out_buf = tag; + data_pkt.out_buf_max = AES_BLOCK_SIZE; + + ret = crypto_cc23x0_cmac(ctx, &data_pkt, b0, b1); + if (ret) { + return ret; + } + + /* + * Prepare the initial counter block CTR1 for the CTR mode. + * ============================================ + * Block CTRi formatting per RFC3610: + * Octet Number Contents + * ------------ --------- + * 0 Flags + * 1 ... 15-L Nonce N + * 16-L ... 15 Counter i, MSB first + * + * Flags in octet 0 of CTR0: + * Bit Number Contents + * ---------- ---------------------- + * 7 Reserved (always zero) + * 6 Reserved (always zero) + * 5 ... 3 Zero + * 2 ... 0 L' = L - 1 where L = Number of octets in length field + * ============================================ + */ + ctri[0] = len_size - 1; + memcpy(&ctri[1], nonce, nonce_len); + ctri[AES_BLOCK_SIZE - 1] = 1; + + /* Encrypt the data using the counter block CTR1. */ + LOG_DBG("Encrypt data"); + + ret = crypto_cc23x0_ctr(ctx, aead_op->pkt, ctri); + if (ret) { + return ret; + } + + /* Encrypt the authentication tag using the counter block CTR0. */ + LOG_DBG("Encrypt tag"); + + ctri[AES_BLOCK_SIZE - 1] = 0; + + tag_pkt.in_buf = tag; + tag_pkt.in_len = tag_len; + tag_pkt.out_buf = aead_op->tag; + tag_pkt.out_buf_max = AES_BLOCK_SIZE; + + return crypto_cc23x0_ctr(ctx, &tag_pkt, ctri); +} + +static int crypto_cc23x0_ccm_decrypt(struct cipher_ctx *ctx, + struct cipher_aead_pkt *aead_op, uint8_t *nonce) +{ + struct cipher_pkt tag_pkt = { 0 }; + struct cipher_pkt data_pkt = { 0 }; + uint8_t enc_tag[AES_BLOCK_SIZE] = { 0 }; + uint8_t calc_tag[AES_BLOCK_SIZE] = { 0 }; + uint8_t b0[AES_BLOCK_SIZE] = { 0 }; + uint8_t b1[AES_BLOCK_SIZE] = { 0 }; + uint8_t ctri[AES_BLOCK_SIZE] = { 0 }; + uint32_t msg_len = aead_op->pkt->in_len; + uint16_t ad_len = aead_op->ad_len; + uint16_t tag_len = ctx->mode_params.ccm_info.tag_len; + uint16_t nonce_len = ctx->mode_params.ccm_info.nonce_len; + uint8_t len_size = AES_BLOCK_SIZE - nonce_len - 1; + int ret; + int i; + + ret = crypto_cc23x0_ccm_check_param(ctx, aead_op); + if (ret) { + return ret; + } + + /* Prepare the initial counter block CTR1 for the CTR mode. */ + ctri[0] = len_size - 1; + memcpy(&ctri[1], nonce, nonce_len); + ctri[AES_BLOCK_SIZE - 1] = 1; + + /* Decrypt the data using the counter block CTR1. */ + LOG_DBG("Decrypt data"); + + ret = crypto_cc23x0_ctr(ctx, aead_op->pkt, ctri); + if (ret) { + goto clear_out_buf; + } + + /* Build the first block B0 required for CMAC computation. */ + b0[0] = CCM_CC23_B0_GET(aead_op->ad_len, tag_len, len_size); + + for (i = 0 ; i < sizeof(msg_len) ; i++) { + b0[AES_BLOCK_SIZE - 1 - i] = CCM_CC23_BYTE_GET(i, msg_len); + } + + memcpy(&b0[1], nonce, nonce_len); + + /* Build the second block B1 for additional data (header). */ + for (i = 0 ; i < sizeof(ad_len) ; i++) { + b1[CCM_CC23_AD_LEN_SIZE - 1 - i] = CCM_CC23_BYTE_GET(i, ad_len); + } + + memcpy(&b1[CCM_CC23_AD_LEN_SIZE], aead_op->ad, ad_len); + + /* + * Calculate the authentication tag by passing B0, B1, and decrypted data + * to CMAC function. + */ + LOG_DBG("Compute CMAC"); + + data_pkt.in_buf = aead_op->pkt->out_buf; + data_pkt.in_len = aead_op->pkt->out_len; + data_pkt.out_buf = calc_tag; + data_pkt.out_buf_max = AES_BLOCK_SIZE; + + ret = crypto_cc23x0_cmac(ctx, &data_pkt, b0, b1); + if (ret) { + goto clear_out_buf; + } + + /* Encrypt the recalculated authentication tag using the counter block CTR0. */ + LOG_DBG("Encrypt tag"); + + ctri[AES_BLOCK_SIZE - 1] = 0; + + tag_pkt.in_buf = calc_tag; + tag_pkt.in_len = tag_len; + tag_pkt.out_buf = enc_tag; + tag_pkt.out_buf_max = AES_BLOCK_SIZE; + + ret = crypto_cc23x0_ctr(ctx, &tag_pkt, ctri); + if (ret) { + goto clear_out_buf; + } + + /* + * Compare the recalculated encrypted authentication tag with the one supplied by the app. + * If they match, the decrypted data is returned. Otherwise, the authentication has failed + * and the output buffer is zero'd. + */ + LOG_DBG("Check tag"); + + if (!memcmp(enc_tag, aead_op->tag, tag_len)) { + return 0; + } + + LOG_ERR("Invalid tag"); + ret = -EINVAL; + +clear_out_buf: + memset(aead_op->pkt->out_buf, 0, msg_len); + + return ret; +} + +static int crypto_cc23x0_session_setup(const struct device *dev, + struct cipher_ctx *ctx, + enum cipher_algo algo, + enum cipher_mode mode, + enum cipher_op op_type) +{ + if (ctx->flags & ~(CRYPTO_CC23_CAP)) { + LOG_ERR("Unsupported feature"); + return -EINVAL; + } + + if (algo != CRYPTO_CIPHER_ALGO_AES) { + LOG_ERR("Unsupported algo"); + return -EINVAL; + } + + if (mode != CRYPTO_CIPHER_MODE_ECB && + mode != CRYPTO_CIPHER_MODE_CTR && + mode != CRYPTO_CIPHER_MODE_CCM) { + LOG_ERR("Unsupported mode"); + return -EINVAL; + } + + if (ctx->keylen != 16U) { + LOG_ERR("%u key size is not supported", ctx->keylen); + return -EINVAL; + } + + if (!ctx->key.bit_stream) { + LOG_ERR("No key provided"); + return -EINVAL; + } + + if (op_type == CRYPTO_CIPHER_OP_ENCRYPT) { + switch (mode) { + case CRYPTO_CIPHER_MODE_ECB: + ctx->ops.block_crypt_hndlr = crypto_cc23x0_ecb_encrypt; + break; + case CRYPTO_CIPHER_MODE_CTR: + ctx->ops.ctr_crypt_hndlr = crypto_cc23x0_ctr; + break; + case CRYPTO_CIPHER_MODE_CCM: + ctx->ops.ccm_crypt_hndlr = crypto_cc23x0_ccm_encrypt; + break; + default: + return -EINVAL; + } + } else { + switch (mode) { + case CRYPTO_CIPHER_MODE_ECB: + LOG_ERR("ECB decryption not supported by the hardware"); + return -EINVAL; + case CRYPTO_CIPHER_MODE_CTR: + ctx->ops.ctr_crypt_hndlr = crypto_cc23x0_ctr; + break; + case CRYPTO_CIPHER_MODE_CCM: + ctx->ops.ccm_crypt_hndlr = crypto_cc23x0_ccm_decrypt; + break; + default: + return -EINVAL; + } + } + + ctx->ops.cipher_mode = mode; + ctx->device = dev; + + return 0; +} + +static int crypto_cc23x0_session_free(const struct device *dev, + struct cipher_ctx *ctx) +{ + ARG_UNUSED(dev); + + ctx->ops.ccm_crypt_hndlr = NULL; + ctx->device = NULL; + + return 0; +} + +static int crypto_cc23x0_query_caps(const struct device *dev) +{ + ARG_UNUSED(dev); + + return CRYPTO_CC23_CAP; +} + +static int crypto_cc23x0_init(const struct device *dev) +{ + struct crypto_cc23x0_data *data = dev->data; + + IRQ_CONNECT(DT_INST_IRQN(0), + DT_INST_IRQ(0, priority), + crypto_cc23x0_isr, + DEVICE_DT_INST_GET(0), + 0); + irq_enable(DT_INST_IRQN(0)); + + CLKCTLEnable(CLKCTL_BASE, CLKCTL_LAES); + + AESSetIMASK(CRYPTO_CC23_INT_MASK); + + k_mutex_init(&data->device_mutex); + k_sem_init(&data->aes_done, 0, 1); + + return 0; +} + +static DEVICE_API(crypto, crypto_enc_funcs) = { + .cipher_begin_session = crypto_cc23x0_session_setup, + .cipher_free_session = crypto_cc23x0_session_free, + .query_hw_caps = crypto_cc23x0_query_caps, +}; + +static struct crypto_cc23x0_data crypto_cc23x0_dev_data; + +DEVICE_DT_INST_DEFINE(0, + crypto_cc23x0_init, + NULL, + &crypto_cc23x0_dev_data, + NULL, + POST_KERNEL, + CONFIG_CRYPTO_INIT_PRIORITY, + &crypto_enc_funcs); diff --git a/dts/bindings/crypto/ti,cc23x0-aes.yaml b/dts/bindings/crypto/ti,cc23x0-aes.yaml new file mode 100644 index 000000000000..6a1348dcea54 --- /dev/null +++ b/dts/bindings/crypto/ti,cc23x0-aes.yaml @@ -0,0 +1,15 @@ +# Copyright (c) Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +description: TI CC23X0 AES accelerator. + +compatible: "ti,cc23x0-aes" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true From 38eafb2883fe664a0b9483223f9a93afc47eb43d Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 24 Jul 2024 16:50:47 +0200 Subject: [PATCH 2/4] dts: arm: ti: cc23x0: Add crypto support Add support for AES module to cc23x0 SoC. Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- dts/arm/ti/cc23x0.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index 6b307980ce3e..71e418ea4fac 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -79,6 +79,13 @@ clocks = <&sysclk>; status = "disabled"; }; + + aes: aes@400c0000 { + compatible = "ti,cc23x0-aes"; + reg = <0x400c0000 0x120>; + interrupts = <9 0>; + status = "disabled"; + }; }; }; From a51d7d405417eb728381f3b9e43e1253b46f78bd Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 24 Jul 2024 16:50:56 +0200 Subject: [PATCH 3/4] boards: ti: lp_em_cc2340r5: Add crypto support Enable AES module. Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts index 64d3e1502075..0b138441ddb8 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -73,3 +73,7 @@ pinctrl-0 = <&uart0_rx_default &uart0_tx_default>; pinctrl-names = "default"; }; + +&aes { + status = "okay"; +}; From 0e205aafcff5d15a7aa8a6492ae5afb73cc849f5 Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 19 Feb 2025 17:09:42 +0100 Subject: [PATCH 4/4] samples: drivers: crypto: Add support for cc23x0 For the CCM mode, increase slightly the output buffer size because the cc23x0 directly fills this buffer with 16-byte blocks. This prevents from doing unnecessary memcpy that would have an impact on the driver's performance. Signed-off-by: Julien Panis --- samples/drivers/crypto/src/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/drivers/crypto/src/main.c b/samples/drivers/crypto/src/main.c index d4609fc2d10c..a5a2fe01fabd 100644 --- a/samples/drivers/crypto/src/main.c +++ b/samples/drivers/crypto/src/main.c @@ -31,6 +31,8 @@ LOG_MODULE_REGISTER(main); #define CRYPTO_DEV_COMPAT nordic_nrf_ecb #elif DT_HAS_COMPAT_STATUS_OKAY(renesas_smartbond_crypto) #define CRYPTO_DEV_COMPAT renesas_smartbond_crypto +#elif DT_HAS_COMPAT_STATUS_OKAY(ti_cc23x0_aes) +#define CRYPTO_DEV_COMPAT ti_cc23x0_aes #elif CONFIG_CRYPTO_SI32 #define CRYPTO_DEV_COMPAT silabs_si32_aes #else @@ -396,7 +398,7 @@ static const uint8_t ccm_expected[31] = {0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x6 void ccm_mode(const struct device *dev) { uint8_t encrypted[50] __aligned(IO_ALIGNMENT_BYTES); - uint8_t decrypted[25] __aligned(IO_ALIGNMENT_BYTES); + uint8_t decrypted[32] __aligned(IO_ALIGNMENT_BYTES); struct cipher_ctx ini = { .keylen = sizeof(ccm_key), .key.bit_stream = ccm_key,