diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index b3aed5dd4a..b8f3f1d41d 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -210,14 +210,6 @@ if(CONFIG_SOC_SHA_SUPPORTED) endif() endif() -if(CONFIG_SOC_AES_SUPPORTED) - if(CONFIG_SOC_AES_SUPPORT_DMA) - set(AES_PERIPHERAL_TYPE "dma") - else() - set(AES_PERIPHERAL_TYPE "block") - endif() -endif() - if(SHA_PERIPHERAL_TYPE STREQUAL "core") target_include_directories(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/sha/core/include") @@ -229,7 +221,7 @@ if(SHA_PERIPHERAL_TYPE STREQUAL "core") target_sources(mbedcrypto PRIVATE "${SHA_CORE_SRCS}") endif() -if(AES_PERIPHERAL_TYPE STREQUAL "dma") +if(CONFIG_SOC_AES_SUPPORT_DMA) if(NOT CONFIG_SOC_AES_GDMA) set(AES_DMA_SRCS "${COMPONENT_DIR}/port/aes/dma/esp_aes_crypto_dma_impl.c") else() @@ -242,7 +234,7 @@ if(AES_PERIPHERAL_TYPE STREQUAL "dma") target_sources(mbedcrypto PRIVATE "${AES_DMA_SRCS}") endif() -if((SHA_PERIPHERAL_TYPE STREQUAL "core" AND CONFIG_SOC_SHA_SUPPORT_DMA) OR AES_PERIPHERAL_TYPE STREQUAL "dma") +if((SHA_PERIPHERAL_TYPE STREQUAL "core" AND CONFIG_SOC_SHA_SUPPORT_DMA) OR CONFIG_SOC_AES_SUPPORT_DMA) target_link_libraries(mbedcrypto PRIVATE idf::esp_mm) if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA) if(CONFIG_SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT) @@ -263,7 +255,7 @@ if(CONFIG_SOC_AES_SUPPORTED) target_include_directories(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/include") target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_xts.c" "${COMPONENT_DIR}/port/aes/esp_aes_common.c" - "${COMPONENT_DIR}/port/aes/${AES_PERIPHERAL_TYPE}/esp_aes.c" + "${COMPONENT_DIR}/port/aes/esp_aes.c" ) endif() diff --git a/components/mbedtls/Kconfig b/components/mbedtls/Kconfig index 99d6123bca..9aaad9646a 100644 --- a/components/mbedtls/Kconfig +++ b/components/mbedtls/Kconfig @@ -1647,6 +1647,21 @@ menu "mbedTLS" priority level and any level from 1 to 3 can be selected (based on the availability). Note: Higher value indicates high interrupt priority. + config MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + bool "Enable performance optimisation for the small data length hardware AES operations" + depends on MBEDTLS_HARDWARE_AES && SOC_AES_SUPPORT_DMA + default y + help + This option enables dynamically switching between the hardware + AES peripheral's block and DMA modes based on the length of the input data, + thus, significantly speeding up the AES operations with shorter data lengths. + For example, NVS encryption/decryption operations, TLS communication, etc. + with smaller data lengths. + + It is enabled by default due to the significant performance impact but note that + it also increases the binary size by ~1.2 KB as it pulls in the peripheral's block + mode code as well. + config MBEDTLS_PK_RSA_ALT_SUPPORT bool "Enable RSA alt support" default y diff --git a/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake b/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake index d2f10d5215..2beb36233a 100644 --- a/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake +++ b/components/mbedtls/esp_tee/esp_tee_mbedtls.cmake @@ -48,7 +48,7 @@ target_include_directories(mbedcrypto PRIVATE ${crypto_port_inc_dirs}) target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/esp_tee/esp_tee_crypto_shared_gdma.c") # AES implementation -target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/dma/esp_aes.c" +target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes.c" "${COMPONENT_DIR}/port/aes/dma/esp_aes_dma_core.c") target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_common.c" diff --git a/components/mbedtls/port/aes/block/esp_aes.c b/components/mbedtls/port/aes/block/esp_aes.c deleted file mode 100644 index 5089e52edc..0000000000 --- a/components/mbedtls/port/aes/block/esp_aes.c +++ /dev/null @@ -1,579 +0,0 @@ -/** - * \brief AES block cipher, ESP block hardware accelerated version - * Based on mbedTLS FIPS-197 compliant version. - * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Additions Copyright (C) 2016-2017, Espressif Systems (Shanghai) PTE Ltd - * SPDX-License-Identifier: Apache-2.0 - * - * 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. - * - */ -/* - * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. - * - * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf - * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - */ -#include -#include "mbedtls/aes.h" -#include "mbedtls/platform_util.h" -#include "esp_log.h" -#include "aes/esp_aes.h" -#include "soc/hwcrypto_periph.h" -#include "soc/soc_caps.h" -#include -#include "hal/aes_hal.h" -#include "hal/aes_ll.h" -#include "esp_aes_internal.h" - -#include - -#include -#include "esp_private/esp_crypto_lock_internal.h" - - -static const char *TAG = "esp-aes"; -/* AES uses a spinlock mux not a lock as the underlying block operation - only takes 208 cycles (to write key & compute block), +600 cycles - for DPORT protection but +3400 cycles again if you use a full sized lock. - - For CBC, CFB, etc. this may mean that interrupts are disabled for a longer - period of time for bigger lengths. However at the moment this has to happen - anyway due to DPORT protection... -*/ -static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED; - - -void esp_aes_acquire_hardware( void ) -{ - portENTER_CRITICAL(&aes_spinlock); - - /* Enable AES hardware */ - AES_RCC_ATOMIC() { - aes_ll_enable_bus_clock(true); - aes_ll_reset_register(); - } -} - -void esp_aes_release_hardware( void ) -{ - /* Disable AES hardware */ - AES_RCC_ATOMIC() { - aes_ll_enable_bus_clock(false); - } - - portEXIT_CRITICAL(&aes_spinlock); -} - - - -/* Run a single 16 byte block of AES, using the hardware engine. - * - * Call only while holding esp_aes_acquire_hardware(). - * - * The function esp_aes_block zeroises the output buffer in the case of following conditions: - * 1. If key is not written in the hardware - * 2. If the fault injection check failed - */ -static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) -{ - uint32_t i0, i1, i2, i3; - const uint32_t *input_words = (uint32_t *)input; - uint32_t *output_words = (uint32_t *)output; - - /* If no key is written to hardware yet, either the user hasn't called - mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't - know which mode to use - or a fault skipped the - key write to hardware. Treat this as a fatal error and zero the output block. - */ - if (ctx->key_in_hardware != ctx->key_bytes) { - mbedtls_platform_zeroize(output, 16); - return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; - } - i0 = input_words[0]; - i1 = input_words[1]; - i2 = input_words[2]; - i3 = input_words[3]; - -#ifdef CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC - esp_aes_enable_pseudo_rounds(CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC_STRENGTH); -#endif /* CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC */ - - aes_hal_transform_block(input, output); - - /* Physical security check: Verify the AES accelerator actually ran, and wasn't - skipped due to external fault injection while starting the peripheral. - - Note that i0,i1,i2,i3 are copied from input buffer in case input==output. - - Bypassing this check requires at least one additional fault. - */ - if (i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) { - // calling zeroing functions to narrow the - // window for a double-fault of the abort step, here - memset(output, 0, 16); - mbedtls_platform_zeroize(output, 16); - abort(); - } - - return 0; -} - -static int esp_aes_validate_input(esp_aes_context *ctx, const unsigned char *input, - const unsigned char *output ) -{ - if (!ctx) { - ESP_LOGD(TAG, "No AES context supplied"); - return -1; - } - if (!input) { - ESP_LOGD(TAG, "No input supplied"); - return -1; - } - if (!output) { - ESP_LOGD(TAG, "No output supplied"); - return -1; - } - - return 0; -} - - - -/* - * AES-ECB block encryption - */ -int esp_internal_aes_encrypt(esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) -{ - int r = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - r = esp_aes_block(ctx, input, output); - esp_aes_release_hardware(); - return r; -} - - -/* - * AES-ECB block decryption - */ - -int esp_internal_aes_decrypt(esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) -{ - int r = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); - r = esp_aes_block(ctx, input, output); - esp_aes_release_hardware(); - return r; -} - -/* - * AES-ECB block encryption/decryption - */ -int esp_aes_crypt_ecb(esp_aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ) -{ - int r = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - r = esp_aes_block(ctx, input, output); - esp_aes_release_hardware(); - return r; -} - - -/* - * AES-CBC buffer encryption/decryption - */ -int esp_aes_crypt_cbc(esp_aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int ret = -1; - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGD(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - uint32_t *output_words = (uint32_t *)output; - const uint32_t *input_words = (const uint32_t *)input; - uint32_t *iv_words = (uint32_t *)iv; - unsigned char temp[16]; - - if ( length % 16 ) { - return ( ERR_ESP_AES_INVALID_INPUT_LENGTH ); - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - - - if ( mode == ESP_AES_DECRYPT ) { - while ( length > 0 ) { - memcpy(temp, input_words, 16); - ret = esp_aes_block(ctx, input_words, output_words); - if (ret != 0) { - goto cleanup; - } - - output_words[0] = output_words[0] ^ iv_words[0]; - output_words[1] = output_words[1] ^ iv_words[1]; - output_words[2] = output_words[2] ^ iv_words[2]; - output_words[3] = output_words[3] ^ iv_words[3]; - - memcpy( iv_words, temp, 16 ); - - input_words += 4; - output_words += 4; - length -= 16; - } - } else { // ESP_AES_ENCRYPT - while ( length > 0 ) { - - output_words[0] = input_words[0] ^ iv_words[0]; - output_words[1] = input_words[1] ^ iv_words[1]; - output_words[2] = input_words[2] ^ iv_words[2]; - output_words[3] = input_words[3] ^ iv_words[3]; - - ret = esp_aes_block(ctx, output_words, output_words); - if (ret != 0) { - goto cleanup; - } - - memcpy( iv_words, output_words, 16 ); - - input_words += 4; - output_words += 4; - length -= 16; - } - } - ret = 0; - -cleanup: - esp_aes_release_hardware(); - return ret; -} - -/* - * AES-CFB128 buffer encryption/decryption - */ -int esp_aes_crypt_cfb128(esp_aes_context *ctx, - int mode, - size_t length, - size_t *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int ret = -1; - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv_off) { - ESP_LOGE(TAG, "No IV offset supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - int c; - size_t n = *iv_off; - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - - if ( mode == ESP_AES_DECRYPT ) { - while ( length-- ) { - if ( n == 0 ) { - ret = esp_aes_block(ctx, iv, iv); - if (ret != 0) { - goto cleanup; - } - } - - c = *input++; - *output++ = (unsigned char)( c ^ iv[n] ); - iv[n] = (unsigned char) c; - - n = ( n + 1 ) & 0x0F; - } - } else { - while ( length-- ) { - if ( n == 0 ) { - ret = esp_aes_block(ctx, iv, iv); - if (ret != 0) { - goto cleanup; - } - } - - iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); - - n = ( n + 1 ) & 0x0F; - } - } - - *iv_off = n; - ret = 0; - -cleanup: - esp_aes_release_hardware(); - return ret; -} - -/* - * AES-CFB8 buffer encryption/decryption - */ -int esp_aes_crypt_cfb8(esp_aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int ret = -1; - unsigned char c; - unsigned char ov[17]; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - - - while ( length-- ) { - memcpy( ov, iv, 16 ); - ret = esp_aes_block(ctx, iv, iv); - if (ret != 0) { - goto cleanup; - } - - if ( mode == ESP_AES_DECRYPT ) { - ov[16] = *input; - } - - c = *output++ = (unsigned char)( iv[0] ^ *input++ ); - - if ( mode == ESP_AES_ENCRYPT ) { - ov[16] = c; - } - - memcpy( iv, ov + 1, 16 ); - } - ret = 0; - -cleanup: - esp_aes_release_hardware(); - return ret; -} - -/* - * AES-CTR buffer encryption/decryption - */ -int esp_aes_crypt_ctr(esp_aes_context *ctx, - size_t length, - size_t *nc_off, - unsigned char nonce_counter[16], - unsigned char stream_block[16], - const unsigned char *input, - unsigned char *output ) -{ - int c, i, ret = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!stream_block) { - ESP_LOGE(TAG, "No stream supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!nonce_counter) { - ESP_LOGE(TAG, "No nonce supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!nc_off) { - ESP_LOGE(TAG, "No nonce offset supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - size_t n = *nc_off; - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - - - while ( length-- ) { - if ( n == 0 ) { - ret = esp_aes_block(ctx, nonce_counter, stream_block); - if (ret != 0) { - goto cleanup; - } - - for ( i = 16; i > 0; i-- ) { - if ( ++nonce_counter[i - 1] != 0 ) { - break; - } - } - } - c = *input++; - *output++ = (unsigned char)( c ^ stream_block[n] ); - - n = ( n + 1 ) & 0x0F; - } - - *nc_off = n; - ret = 0; - -cleanup: - esp_aes_release_hardware(); - return ret; -} - -/* - * AES-OFB (Output Feedback Mode) buffer encryption/decryption - */ -int esp_aes_crypt_ofb(esp_aes_context *ctx, - size_t length, - size_t *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int ret = -1; - size_t n; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv_off) { - ESP_LOGE(TAG, "No IV offset supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - n = *iv_off; - - if (n > 15) { - return (MBEDTLS_ERR_AES_BAD_INPUT_DATA); - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - - - while (length--) { - if ( n == 0 ) { - ret = esp_aes_block(ctx, iv, iv); - if (ret != 0) { - goto cleanup; - } - } - *output++ = *input++ ^ iv[n]; - - n = ( n + 1 ) & 0x0F; - } - - *iv_off = n; - ret = 0; - -cleanup: - esp_aes_release_hardware(); - - return ( ret ); -} diff --git a/components/mbedtls/port/aes/dma/esp_aes.c b/components/mbedtls/port/aes/dma/esp_aes.c deleted file mode 100644 index a9abeda599..0000000000 --- a/components/mbedtls/port/aes/dma/esp_aes.c +++ /dev/null @@ -1,521 +0,0 @@ -/** - * \brief AES block cipher, ESP DMA hardware accelerated version - * Based on mbedTLS FIPS-197 compliant version. - * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd - * SPDX-License-Identifier: Apache-2.0 - * - * 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. - * - */ -/* - * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. - * - * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf - * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - */ - -#include -#include "mbedtls/aes.h" -#include "esp_log.h" -#include "esp_crypto_lock.h" -#include "hal/aes_hal.h" -#include "esp_aes_internal.h" -#include "esp_crypto_periph_clk.h" - -#if SOC_AES_GDMA -#define AES_LOCK() esp_crypto_sha_aes_lock_acquire() -#define AES_RELEASE() esp_crypto_sha_aes_lock_release() -#elif SOC_AES_CRYPTO_DMA -#define AES_LOCK() esp_crypto_dma_lock_acquire() -#define AES_RELEASE() esp_crypto_dma_lock_release() -#include "hal/crypto_dma_ll.h" -#endif - -static const char *TAG = "esp-aes"; - -void esp_aes_acquire_hardware( void ) -{ - /* Released by esp_aes_release_hardware()*/ - AES_LOCK(); - esp_crypto_aes_enable_periph_clk(true); -} - -/* Function to disable AES and Crypto DMA clocks and release locks */ -void esp_aes_release_hardware( void ) -{ - esp_crypto_aes_enable_periph_clk(false); - AES_RELEASE(); -} - -static int esp_aes_validate_input(esp_aes_context *ctx, const unsigned char *input, - unsigned char *output ) -{ - if (!ctx) { - ESP_LOGE(TAG, "No AES context supplied"); - return -1; - } - if (!input) { - ESP_LOGE(TAG, "No input supplied"); - return -1; - } - if (!output) { - ESP_LOGE(TAG, "No output supplied"); - return -1; - } - - return 0; -} - - -/* - * AES-ECB single block encryption - */ -int esp_internal_aes_encrypt(esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) -{ - int r = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_ECB); - r = esp_aes_process_dma(ctx, input, output, AES_BLOCK_BYTES, NULL); - esp_aes_release_hardware(); - - return r; -} - - -/* - * AES-ECB single block decryption - */ -int esp_internal_aes_decrypt(esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) -{ - int r = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_ECB); - r = esp_aes_process_dma(ctx, input, output, AES_BLOCK_BYTES, NULL); - esp_aes_release_hardware(); - - return r; -} - - - -/* - * AES-ECB block encryption/decryption - */ -int esp_aes_crypt_ecb(esp_aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ) -{ - int r = -1; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_ECB); - r = esp_aes_process_dma(ctx, input, output, AES_BLOCK_BYTES, NULL); - esp_aes_release_hardware(); - - return r; -} - -/* - * AES-CBC buffer encryption/decryption - */ -int esp_aes_crypt_cbc(esp_aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int r = -1; - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - /* For CBC input length should be multiple of - * AES BLOCK BYTES - * */ - if ( (length % AES_BLOCK_BYTES) || (length == 0) ) { - return ERR_ESP_AES_INVALID_INPUT_LENGTH; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_CBC); - aes_hal_set_iv(iv); - - r = esp_aes_process_dma(ctx, input, output, length, NULL); - if (r != 0) { - goto cleanup; - } - - aes_hal_read_iv(iv); - -cleanup: - esp_aes_release_hardware(); - return r; -} - -/* - * AES-CFB8 buffer encryption/decryption - */ -int esp_aes_crypt_cfb8(esp_aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int r = -1; - unsigned char c; - unsigned char ov[17]; - size_t block_bytes = length - (length % AES_BLOCK_BYTES); - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - /* The DMA engine will only output correct IV if it runs - full blocks of input in CFB8 mode - */ - esp_aes_acquire_hardware(); - - if (block_bytes > 0) { - - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_CFB8); - aes_hal_set_iv(iv); - r = esp_aes_process_dma(ctx, input, output, block_bytes, NULL); - if (r != 0) { - goto cleanup; - } - - aes_hal_read_iv(iv); - - length -= block_bytes; - input += block_bytes; - output += block_bytes; - } - - // Process remaining bytes block-at-a-time in ECB mode - if (length > 0) { - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, MBEDTLS_AES_ENCRYPT); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_ECB); - - while ( length-- ) { - memcpy( ov, iv, 16 ); - - r = esp_aes_process_dma(ctx, iv, iv, AES_BLOCK_BYTES, NULL); - if (r != 0) { - goto cleanup; - } - - if ( mode == MBEDTLS_AES_DECRYPT ) { - ov[16] = *input; - } - - c = *output++ = ( iv[0] ^ *input++ ); - - if ( mode == MBEDTLS_AES_ENCRYPT ) { - ov[16] = c; - } - memcpy( iv, ov + 1, 16 ); - } - - } - r = 0; - -cleanup: - esp_aes_release_hardware(); - return r; -} - -/* - * AES-CFB128 buffer encryption/decryption - */ -int esp_aes_crypt_cfb128(esp_aes_context *ctx, - int mode, - size_t length, - size_t *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) - -{ - uint8_t c; - size_t stream_bytes = 0; - size_t n; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv_off) { - ESP_LOGE(TAG, "No IV offset supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - n = *iv_off; - - /* First process the *iv_off bytes - * which are pending from the previous call to this API - */ - while (n > 0 && length > 0) { - if (mode == MBEDTLS_AES_ENCRYPT) { - iv[n] = *output++ = *input++ ^ iv[n]; - } else { - c = *input++; - *output++ = c ^ iv[n]; - iv[n] = c; - } - n = (n + 1) % AES_BLOCK_BYTES; - length--; - } - - - if (length > 0) { - stream_bytes = length % AES_BLOCK_BYTES; - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_CFB128); - aes_hal_set_iv(iv); - - int r = esp_aes_process_dma(ctx, input, output, length, iv); - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - if (stream_bytes == 0) { - // if we didn't need the partial 'stream block' then the new IV is in the IV register - aes_hal_read_iv(iv); - } else { - // if we did process a final partial block the new IV is already processed via DMA (and has some bytes of output in it), - // In decrypt mode any partial bytes are output plaintext (iv ^ c) and need to be swapped back to ciphertext (as the next - // block uses ciphertext as its IV input) - // - // Note: It may be more efficient to not process the partial block via DMA in this case. - if (mode == MBEDTLS_AES_DECRYPT) { - memcpy(iv, input + length - stream_bytes, stream_bytes); - } - } - esp_aes_release_hardware(); - } - - *iv_off = n + stream_bytes; - return 0; -} - -/* - * AES-OFB (Output Feedback Mode) buffer encryption/decryption - */ - -int esp_aes_crypt_ofb(esp_aes_context *ctx, - size_t length, - size_t *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - size_t n; - size_t stream_bytes = 0; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!iv_off) { - ESP_LOGE(TAG, "No IV offset supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - n = *iv_off; - - /* If there is an offset then use the output of the previous AES block - (the updated IV) to calculate the new output */ - while (n > 0 && length > 0) { - *output++ = (*input++ ^ iv[n]); - n = (n + 1) & 0xF; - length--; - } - if (length > 0) { - stream_bytes = (length % AES_BLOCK_BYTES); - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); - aes_hal_mode_init(ESP_AES_BLOCK_MODE_OFB); - aes_hal_set_iv(iv); - - int r = esp_aes_process_dma(ctx, input, output, length, iv); - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - aes_hal_read_iv(iv); - esp_aes_release_hardware(); - } - - *iv_off = n + stream_bytes; - - return 0; -} - -#ifdef CONFIG_MBEDTLS_CIPHER_MODE_CTR -/* - * AES-CTR buffer encryption/decryption - */ -int esp_aes_crypt_ctr(esp_aes_context *ctx, - size_t length, - size_t *nc_off, - unsigned char nonce_counter[16], - unsigned char stream_block[16], - const unsigned char *input, - unsigned char *output ) -{ - size_t n; - - if (esp_aes_validate_input(ctx, input, output)) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!stream_block) { - ESP_LOGE(TAG, "No stream supplied"); - return -1; - } - - if (!nonce_counter) { - ESP_LOGE(TAG, "No nonce supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - if (!nc_off) { - ESP_LOGE(TAG, "No nonce offset supplied"); - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; - } - - n = *nc_off; - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - /* Process any unprocessed bytes left in stream block from - last operation */ - while (n > 0 && length > 0) { - *output++ = (unsigned char)(*input++ ^ stream_block[n]); - n = (n + 1) & 0xF; - length--; - } - - if (length > 0) { - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); - - aes_hal_mode_init(ESP_AES_BLOCK_MODE_CTR); - aes_hal_set_iv(nonce_counter); - - int r = esp_aes_process_dma(ctx, input, output, length, stream_block); - - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - aes_hal_read_iv(nonce_counter); - - esp_aes_release_hardware(); - - } - *nc_off = n + (length % AES_BLOCK_BYTES); - - return 0; -} -#endif /* CONFIG_MBEDTLS_CIPHER_MODE_CTR */ diff --git a/components/mbedtls/port/aes/esp_aes.c b/components/mbedtls/port/aes/esp_aes.c new file mode 100644 index 0000000000..e874102a52 --- /dev/null +++ b/components/mbedtls/port/aes/esp_aes.c @@ -0,0 +1,749 @@ +/* + * \brief AES block and DMA hardware accelerated version + * Based on mbedTLS FIPS-197 compliant version. + * + * SPDX-FileCopyrightText: The Mbed TLS Contributors + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#include +#include "mbedtls/aes.h" +#include "esp_log.h" +#include "esp_crypto_lock.h" +#include "hal/aes_hal.h" +#include "esp_aes_internal.h" +#include "esp_crypto_periph_clk.h" +#include "soc/soc_caps.h" +#include "sdkconfig.h" + +#if SOC_AES_GDMA +#define AES_LOCK() esp_crypto_sha_aes_lock_acquire() +#define AES_RELEASE() esp_crypto_sha_aes_lock_release() +#elif SOC_AES_CRYPTO_DMA +#define AES_LOCK() esp_crypto_dma_lock_acquire() +#define AES_RELEASE() esp_crypto_dma_lock_release() +#include "hal/crypto_dma_ll.h" +#endif + +static const char *TAG = "esp-aes"; + +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM +#if CONFIG_IDF_TARGET_ESP32P4 +#define AES_DMA_MODE_THRESHOLD 512 +#else +#define AES_DMA_MODE_THRESHOLD 128 +#endif +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + +#if !SOC_AES_SUPPORT_DMA +#include + +/* AES uses a spinlock mux not a lock as the underlying block operation + only takes 208 cycles (to write key & compute block), +600 cycles + for DPORT protection but +3400 cycles again if you use a full sized lock. + + For CBC, CFB, etc. this may mean that interrupts are disabled for a longer + period of time for bigger lengths. However at the moment this has to happen + anyway due to DPORT protection... +*/ +static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED; +#endif + +void esp_aes_acquire_hardware( void ) +{ + /* Released by esp_aes_release_hardware()*/ +#if SOC_AES_SUPPORT_DMA + AES_LOCK(); +#else + portENTER_CRITICAL(&aes_spinlock); +#endif + esp_crypto_aes_enable_periph_clk(true); +} + +/* Function to disable AES and Crypto DMA clocks and release locks */ +void esp_aes_release_hardware( void ) +{ + esp_crypto_aes_enable_periph_clk(false); +#if SOC_AES_SUPPORT_DMA + AES_RELEASE(); +#else + portEXIT_CRITICAL(&aes_spinlock); +#endif +} + +static int esp_aes_validate_input(esp_aes_context *ctx, const unsigned char *input, + unsigned char *output, unsigned char *iv, bool validate_iv) +{ + if (!ctx) { + ESP_LOGE(TAG, "No AES context supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + if (!input) { + ESP_LOGE(TAG, "No input supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + if (!output) { + ESP_LOGE(TAG, "No output supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + if (!valid_key_length(ctx)) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + if (validate_iv && !iv) { + ESP_LOGE(TAG, "No IV supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + return 0; +} + +#if !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM +/* Run a single 16 byte block of AES, using the hardware engine. + * + * Call only while holding esp_aes_acquire_hardware(). + * + * The function esp_aes_block zeroises the output buffer in the case of following conditions: + * 1. If key is not written in the hardware + * 2. If the fault injection check failed + */ +static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) +{ + uint32_t i0, i1, i2, i3; + const uint32_t *input_words = (uint32_t *)input; + uint32_t *output_words = (uint32_t *)output; + + /* If no key is written to hardware yet, either the user hasn't called + mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't + know which mode to use - or a fault skipped the + key write to hardware. Treat this as a fatal error and zero the output block. + */ + if (ctx->key_in_hardware != ctx->key_bytes) { + mbedtls_platform_zeroize(output, 16); + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + i0 = input_words[0]; + i1 = input_words[1]; + i2 = input_words[2]; + i3 = input_words[3]; + +#ifdef CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC + esp_aes_enable_pseudo_rounds(CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC_STRENGTH); +#endif /* CONFIG_MBEDTLS_AES_USE_PSEUDO_ROUND_FUNC */ + + aes_hal_transform_block(input, output); + + /* Physical security check: Verify the AES accelerator actually ran, and wasn't + skipped due to external fault injection while starting the peripheral. + + Note that i0,i1,i2,i3 are copied from input buffer in case input==output. + + Bypassing this check requires at least one additional fault. + */ + if (i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) { + // calling zeroing functions to narrow the + // window for a double-fault of the abort step, here + memset(output, 0, 16); + mbedtls_platform_zeroize(output, 16); + abort(); + } + + return 0; +} +#endif /* !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + +/* + * AES-ECB single block encryption + */ +int esp_internal_aes_encrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + return esp_aes_crypt_ecb(ctx, ESP_AES_ENCRYPT, input, output); +} + +/* + * AES-ECB single block decryption + */ +int esp_internal_aes_decrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + return esp_aes_crypt_ecb(ctx, ESP_AES_DECRYPT, input, output); +} + +/* + * AES-ECB block encryption/decryption + */ +int esp_aes_crypt_ecb(esp_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + // Use helper for validation + int ret = esp_aes_validate_input(ctx, input, output, NULL, false); + if (ret != 0) { + return ret; + } + + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); + +#if SOC_AES_SUPPORT_DMA && !CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + aes_hal_mode_init(ESP_AES_BLOCK_MODE_ECB); + ret = esp_aes_process_dma(ctx, input, output, AES_BLOCK_BYTES, NULL); +#else + ret = esp_aes_block(ctx, input, output); +#endif + + esp_aes_release_hardware(); + return ret; +} + +/* + * AES-CBC buffer encryption/decryption + */ +int esp_aes_crypt_cbc(esp_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + // Use helpers for validation + int ret = esp_aes_validate_input(ctx, input, output, iv, true); + if (ret != 0) { + return ret; + } + + /* For CBC input length should be multiple of AES BLOCK BYTES */ + if ( (length % AES_BLOCK_BYTES) || (length == 0) ) { + return ERR_ESP_AES_INVALID_INPUT_LENGTH; + } + + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + +#if SOC_AES_SUPPORT_DMA +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + if (length > AES_DMA_MODE_THRESHOLD) { +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_CBC); + aes_hal_set_iv(iv); + + ret = esp_aes_process_dma(ctx, input, output, length, NULL); + if (ret != 0) { + goto cleanup; + } + + aes_hal_read_iv(iv); +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + } else +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ +#endif /* SOC_AES_SUPPORT_DMA */ +#if !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + { + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); + + uint32_t *output_words = (uint32_t *)output; + const uint32_t *input_words = (const uint32_t *)input; + uint32_t *iv_words = (uint32_t *)iv; + unsigned char temp[16]; + + if (mode == ESP_AES_DECRYPT) { + while (length > 0) { + memcpy(temp, input_words, 16); + ret = esp_aes_block(ctx, input_words, output_words); + if (ret != 0) { + goto cleanup; + } + + output_words[0] = output_words[0] ^ iv_words[0]; + output_words[1] = output_words[1] ^ iv_words[1]; + output_words[2] = output_words[2] ^ iv_words[2]; + output_words[3] = output_words[3] ^ iv_words[3]; + + memcpy( iv_words, temp, 16 ); + + input_words += 4; + output_words += 4; + length -= 16; + } + } else { // ESP_AES_ENCRYPT + while (length > 0) { + + output_words[0] = input_words[0] ^ iv_words[0]; + output_words[1] = input_words[1] ^ iv_words[1]; + output_words[2] = input_words[2] ^ iv_words[2]; + output_words[3] = input_words[3] ^ iv_words[3]; + + ret = esp_aes_block(ctx, output_words, output_words); + if (ret != 0) { + goto cleanup; + } + + memcpy(iv_words, output_words, 16); + + input_words += 4; + output_words += 4; + length -= 16; + } + } + ret = 0; + } +#endif /* !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + +cleanup: + esp_aes_release_hardware(); + return ret; +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int esp_aes_crypt_cfb8(esp_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + // Use helpers for validation + int ret = esp_aes_validate_input(ctx, input, output, iv, true); + if (ret != 0) { + return ret; + } + + esp_aes_acquire_hardware(); + +#if SOC_AES_SUPPORT_DMA +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + if (length > AES_DMA_MODE_THRESHOLD) { +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + size_t block_bytes = length - (length % AES_BLOCK_BYTES); + + /* The DMA engine will only output correct IV if it runs + full blocks of input in CFB8 mode + */ + if (block_bytes > 0) { + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_CFB8); + aes_hal_set_iv(iv); + + ret = esp_aes_process_dma(ctx, input, output, block_bytes, NULL); + if (ret != 0) { + goto cleanup; + } + + aes_hal_read_iv(iv); + + length -= block_bytes; + input += block_bytes; + output += block_bytes; + } + + // Process remaining bytes block-at-a-time in ECB mode + if (length > 0) { + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_ECB); + + while ( length-- ) { + memcpy( ov, iv, 16 ); + + ret = esp_aes_process_dma(ctx, iv, iv, AES_BLOCK_BYTES, NULL); + if (ret != 0) { + goto cleanup; + } + + if ( mode == ESP_AES_DECRYPT ) { + ov[16] = *input; + } + + c = *output++ = ( iv[0] ^ *input++ ); + + if ( mode == ESP_AES_ENCRYPT ) { + ov[16] = c; + } + memcpy( iv, ov + 1, 16 ); + } + } + ret = 0; +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + } else +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ +#endif /* SOC_AES_SUPPORT_DMA */ +#if !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + { + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); + + while (length--) { + memcpy( ov, iv, 16 ); + ret = esp_aes_block(ctx, iv, iv); + if (ret != 0) { + goto cleanup; + } + + if (mode == ESP_AES_DECRYPT) { + ov[16] = *input; + } + + c = *output++ = (unsigned char)(iv[0] ^ *input++); + + if (mode == ESP_AES_ENCRYPT) { + ov[16] = c; + } + + memcpy( iv, ov + 1, 16 ); + } + ret = 0; + } +#endif /* !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ +cleanup: + esp_aes_release_hardware(); + return ret; +} + +/* + * AES-CFB128 buffer encryption/decryption + */ +int esp_aes_crypt_cfb128(esp_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) + +{ + uint8_t c; + size_t n; + + // Use helpers for validation + int ret = esp_aes_validate_input(ctx, input, output, iv, true); + if (ret != 0) { + return ret; + } + + if (!iv_off) { + ESP_LOGE(TAG, "No IV offset supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + n = *iv_off; + +#if SOC_AES_SUPPORT_DMA +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + if (length > AES_DMA_MODE_THRESHOLD) { +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + size_t stream_bytes = 0; + + /* First process the *iv_off bytes + * which are pending from the previous call to this API + */ + while (n > 0 && length > 0) { + if (mode == ESP_AES_ENCRYPT) { + iv[n] = *output++ = *input++ ^ iv[n]; + } else { + c = *input++; + *output++ = c ^ iv[n]; + iv[n] = c; + } + n = (n + 1) % AES_BLOCK_BYTES; + length--; + } + + if (length > 0) { + stream_bytes = length % AES_BLOCK_BYTES; + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_CFB128); + aes_hal_set_iv(iv); + + ret = esp_aes_process_dma(ctx, input, output, length, iv); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + + if (stream_bytes == 0) { + // if we didn't need the partial 'stream block' then the new IV is in the IV register + aes_hal_read_iv(iv); + } else { + // if we did process a final partial block the new IV is already processed via DMA (and has some bytes of output in it), + // In decrypt mode any partial bytes are output plaintext (iv ^ c) and need to be swapped back to ciphertext (as the next + // block uses ciphertext as its IV input) + // + // Note: It may be more efficient to not process the partial block via DMA in this case. + if (mode == ESP_AES_DECRYPT) { + memcpy(iv, input + length - stream_bytes, stream_bytes); + } + } + esp_aes_release_hardware(); + } + + *iv_off = n + stream_bytes; +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + } else +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ +#endif /* SOC_AES_SUPPORT_DMA */ +#if !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + { + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); + + if (mode == ESP_AES_DECRYPT) { + while (length--) { + if (n == 0) { + ret = esp_aes_block(ctx, iv, iv); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + } + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + n = (n + 1) & 0x0F; + } + } else { + while (length--) { + if ( n == 0 ) { + ret = esp_aes_block(ctx, iv, iv); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + } + + iv[n] = *output++ = (unsigned char)(iv[n] ^ *input++); + n = ( n + 1 ) & 0x0F; + } + } + + esp_aes_release_hardware(); + *iv_off = n; + } +#endif /* !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + return 0; +} + +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ + +int esp_aes_crypt_ofb(esp_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + size_t n; + + // Use helpers for validation + int ret = esp_aes_validate_input(ctx, input, output, iv, true); + if (ret != 0) { + return ret; + } + + if (!iv_off) { + ESP_LOGE(TAG, "No IV offset supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + n = *iv_off; + +#if SOC_AES_SUPPORT_DMA +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + if (length > AES_DMA_MODE_THRESHOLD) { +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + size_t stream_bytes = 0; + + /* If there is an offset then use the output of the previous AES block + (the updated IV) to calculate the new output */ + while (n > 0 && length > 0) { + *output++ = (*input++ ^ iv[n]); + n = (n + 1) & 0xF; + length--; + } + + if (length > 0) { + stream_bytes = (length % AES_BLOCK_BYTES); + + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_OFB); + aes_hal_set_iv(iv); + + ret = esp_aes_process_dma(ctx, input, output, length, iv); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + + aes_hal_read_iv(iv); + esp_aes_release_hardware(); + } + + *iv_off = n + stream_bytes; +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + } else +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ +#endif /* SOC_AES_SUPPORT_DMA */ +#if !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + { + // TODO: Check if this is necessary as the DMA version does not have this check + if (n > 15) { + return (MBEDTLS_ERR_AES_BAD_INPUT_DATA); + } + + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); + + while (length--) { + if (n == 0) { + ret = esp_aes_block(ctx, iv, iv); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + } + *output++ = *input++ ^ iv[n]; + n = (n + 1) & 0x0F; + } + + esp_aes_release_hardware(); + *iv_off = n; + } +#endif /* !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + return 0; +} + +/* + * AES-CTR buffer encryption/decryption + */ +int esp_aes_crypt_ctr(esp_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + size_t n; + + // Use helper for validation + int ret = esp_aes_validate_input(ctx, input, output, NULL, false); + if (ret != 0) { + return ret; + } + + if (!stream_block) { + ESP_LOGE(TAG, "No stream supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + if (!nonce_counter) { + ESP_LOGE(TAG, "No nonce supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + if (!nc_off) { + ESP_LOGE(TAG, "No nonce offset supplied"); + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + } + + n = *nc_off; + +#if SOC_AES_SUPPORT_DMA +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + if (length > AES_DMA_MODE_THRESHOLD) { +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + /* Process any unprocessed bytes left in stream block from + last operation */ + while (n > 0 && length > 0) { + *output++ = (unsigned char)(*input++ ^ stream_block[n]); + n = (n + 1) & 0xF; + length--; + } + + if (length > 0) { + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); + + aes_hal_mode_init(ESP_AES_BLOCK_MODE_CTR); + aes_hal_set_iv(nonce_counter); + + ret = esp_aes_process_dma(ctx, input, output, length, stream_block); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + + aes_hal_read_iv(nonce_counter); + esp_aes_release_hardware(); + } + + *nc_off = n + (length % AES_BLOCK_BYTES); +#if CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + } else +#endif /* CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ +#endif /* SOC_AES_SUPPORT_DMA */ +#if !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM + { + esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); + + int c, i; + while (length--) { + if (n == 0) { + ret = esp_aes_block(ctx, nonce_counter, stream_block); + if (ret != 0) { + esp_aes_release_hardware(); + return ret; + } + + for (i = 16; i > 0; i--) { + if (++nonce_counter[i - 1] != 0) { + break; + } + } + } + c = *input++; + *output++ = (unsigned char)(c ^ stream_block[n]); + n = (n + 1) & 0x0F; + } + + esp_aes_release_hardware(); + *nc_off = n; + } +#endif /* !SOC_AES_SUPPORT_DMA || CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM */ + return 0; +} diff --git a/components/mbedtls/port/include/aes/esp_aes.h b/components/mbedtls/port/include/aes/esp_aes.h index db3018fa96..38f5513f45 100644 --- a/components/mbedtls/port/include/aes/esp_aes.h +++ b/components/mbedtls/port/include/aes/esp_aes.h @@ -345,7 +345,6 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16 /** XTS-AES buffer encryption/decryption */ int esp_aes_crypt_xts( esp_aes_xts_context *ctx, int mode, size_t length, const unsigned char data_unit[16], const unsigned char *input, unsigned char *output ); - #ifdef __cplusplus } #endif diff --git a/components/mbedtls/port/sha/core/esp_sha1.c b/components/mbedtls/port/sha/core/esp_sha1.c index 515bd1c838..1359dc94b9 100644 --- a/components/mbedtls/port/sha/core/esp_sha1.c +++ b/components/mbedtls/port/sha/core/esp_sha1.c @@ -34,6 +34,7 @@ #include "esp_sha_internal.h" #include "sha/sha_core.h" +#include "esp_compiler.h" /* Implementation that should never be optimized out by the compiler */ static void mbedtls_zeroize(void *v, size_t n) @@ -119,7 +120,8 @@ int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char esp_internal_sha_update_state(ctx); #if SOC_SHA_SUPPORT_DMA - if (sha_operation_mode(64) == SHA_DMA_MODE) { + // Unlikely to use DMA because data size is 64 bytes which is smaller than the DMA threshold + if (unlikely(sha_operation_mode(64) == SHA_DMA_MODE)) { int ret = esp_sha_dma(SHA1, data, 64, NULL, 0, ctx->first_block); if (ret != 0) { esp_sha_release_hardware(); diff --git a/components/mbedtls/port/sha/core/esp_sha256.c b/components/mbedtls/port/sha/core/esp_sha256.c index cc717f8202..dad3c571e8 100644 --- a/components/mbedtls/port/sha/core/esp_sha256.c +++ b/components/mbedtls/port/sha/core/esp_sha256.c @@ -34,6 +34,7 @@ #include "esp_sha_internal.h" #include "sha/sha_core.h" +#include "esp_compiler.h" /* Implementation that should never be optimized out by the compiler */ static void mbedtls_zeroize(void *v, size_t n) @@ -132,7 +133,8 @@ int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned esp_internal_sha_update_state(ctx); #if SOC_SHA_SUPPORT_DMA - if (sha_operation_mode(64) == SHA_DMA_MODE) { + // Unlikely to use DMA because data size is 64 bytes which is smaller than the DMA threshold + if (unlikely(sha_operation_mode(64) == SHA_DMA_MODE)) { int ret = esp_sha_dma(ctx->mode, data, 64, NULL, 0, ctx->first_block); if (ret != 0) { esp_sha_release_hardware(); diff --git a/components/mbedtls/port/sha/core/esp_sha512.c b/components/mbedtls/port/sha/core/esp_sha512.c index 1750095009..0c9e6607de 100644 --- a/components/mbedtls/port/sha/core/esp_sha512.c +++ b/components/mbedtls/port/sha/core/esp_sha512.c @@ -40,6 +40,7 @@ #include "esp_sha_internal.h" #include "sha/sha_core.h" +#include "esp_compiler.h" /* Implementation that should never be optimized out by the compiler */ static void mbedtls_zeroize(void *v, size_t n) @@ -169,7 +170,8 @@ int mbedtls_internal_sha512_process(mbedtls_sha512_context *ctx, const unsigned } #if SOC_SHA_SUPPORT_DMA - if (sha_operation_mode(128) == SHA_DMA_MODE) { + // Likely to use DMA because data size is 128 bytes which is larger or equal to the DMA threshold + if (likely(sha_operation_mode(128) == SHA_DMA_MODE)) { ret = esp_sha_dma(ctx->mode, data, 128, NULL, 0, ctx->first_block); if (ret != 0) { esp_sha_release_hardware(); diff --git a/docs/en/api-guides/performance/size.rst b/docs/en/api-guides/performance/size.rst index 45e4004bc4..3ac68e8867 100644 --- a/docs/en/api-guides/performance/size.rst +++ b/docs/en/api-guides/performance/size.rst @@ -223,6 +223,7 @@ These include: - Consider disabling some cipher suites listed in the ``TLS Key Exchange Methods`` sub-menu (i.e., :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`). - Consider disabling :ref:`CONFIG_MBEDTLS_ERROR_STRINGS` if the application is already pulling in mbedTLS error strings through using :cpp:func:`mbedtls_strerror`. :esp32h2: - For {IDF_TARGET_NAME} v1.2 and above, consider disabling :ref:`CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_MASKING_CM` and :ref:`CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_CONSTANT_TIME_CM` as the software countermeasures for the ECDSA sign operation are not required. + :SOC_AES_SUPPORT_DMA: - Consider disabling :ref:CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM if the application does not involve or require performance optimization for operations that involve small data lengths, such as NVS encryption/decryption or TLS communication when performed on small data segments. The help text for each option has some more information for reference. diff --git a/docs/zh_CN/api-guides/performance/size.rst b/docs/zh_CN/api-guides/performance/size.rst index f7696d0792..3e19337145 100644 --- a/docs/zh_CN/api-guides/performance/size.rst +++ b/docs/zh_CN/api-guides/performance/size.rst @@ -223,6 +223,7 @@ MbedTLS 功能 - 可以考虑禁用在 ``TLS Key Exchange Methods`` 子菜单中列出的一些密码套件(例如 :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`),以减小代码大小。 - 如果应用程序已经通过使用 :cpp:func:`mbedtls_strerror` 拉取 mbedTLS 错误字符串,则可以考虑禁用 :ref:`CONFIG_MBEDTLS_ERROR_STRINGS`。 :esp32h2: - 对于 {IDF_TARGET_NAME} v1.2 及以上版本,可以考虑禁用 :ref:`CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_MASKING_CM` 和 :ref:`CONFIG_MBEDTLS_HARDWARE_ECDSA_SIGN_CONSTANT_TIME_CM`,因为无需再使用 ECDSA 签名的软件防护措施。 + :SOC_AES_SUPPORT_DMA: - 如果应用程序不涉及或不需要针对小数据长度操作进行性能优化,例如在处理小数据段时进行的 NVS 加密/解密操作、TLS 通信等,可以考虑禁用 :ref:`CONFIG_MBEDTLS_AES_HW_SMALL_DATA_LEN_OPTIM`。 每个选项的帮助文本中都有更多信息可供参考。 diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 7973872efa..70351688f8 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -470,8 +470,6 @@ components/lwip/apps/ping/ping.c components/lwip/include/apps/esp_ping.h components/lwip/include/apps/ping/ping.h components/mbedtls/esp_crt_bundle/test_gen_crt_bundle/test_gen_crt_bundle.py -components/mbedtls/port/aes/block/esp_aes.c -components/mbedtls/port/aes/dma/esp_aes.c components/mbedtls/port/aes/esp_aes_xts.c components/mbedtls/port/include/aes/esp_aes.h components/mbedtls/port/include/aes_alt.h