feat(mbedtls/aes): Add config to support AES block and DMA modes during runtime

- Dynamically switch the AES operation modes based on the buffer operating length
- Shorter AES and SHA operations can now run faster and concurrently as well

Closes https://github.com/espressif/esp-idf/issues/15914
This commit is contained in:
harshal.patil
2025-07-27 16:49:09 +05:30
parent ac89a6f896
commit 8992f08bef
13 changed files with 779 additions and 1118 deletions

View File

@@ -210,14 +210,6 @@ if(CONFIG_SOC_SHA_SUPPORTED)
endif() endif()
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") if(SHA_PERIPHERAL_TYPE STREQUAL "core")
target_include_directories(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/sha/core/include") 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}") target_sources(mbedcrypto PRIVATE "${SHA_CORE_SRCS}")
endif() endif()
if(AES_PERIPHERAL_TYPE STREQUAL "dma") if(CONFIG_SOC_AES_SUPPORT_DMA)
if(NOT CONFIG_SOC_AES_GDMA) if(NOT CONFIG_SOC_AES_GDMA)
set(AES_DMA_SRCS "${COMPONENT_DIR}/port/aes/dma/esp_aes_crypto_dma_impl.c") set(AES_DMA_SRCS "${COMPONENT_DIR}/port/aes/dma/esp_aes_crypto_dma_impl.c")
else() else()
@@ -242,7 +234,7 @@ if(AES_PERIPHERAL_TYPE STREQUAL "dma")
target_sources(mbedcrypto PRIVATE "${AES_DMA_SRCS}") target_sources(mbedcrypto PRIVATE "${AES_DMA_SRCS}")
endif() 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) target_link_libraries(mbedcrypto PRIVATE idf::esp_mm)
if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA) if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA)
if(CONFIG_SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT) 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_include_directories(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/include")
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_xts.c" target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_xts.c"
"${COMPONENT_DIR}/port/aes/esp_aes_common.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() endif()

View File

@@ -1647,6 +1647,21 @@ menu "mbedTLS"
priority level and any level from 1 to 3 can be selected (based on the availability). priority level and any level from 1 to 3 can be selected (based on the availability).
Note: Higher value indicates high interrupt priority. 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 config MBEDTLS_PK_RSA_ALT_SUPPORT
bool "Enable RSA alt support" bool "Enable RSA alt support"
default y default y

View File

@@ -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") target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/esp_tee/esp_tee_crypto_shared_gdma.c")
# AES implementation # 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") "${COMPONENT_DIR}/port/aes/dma/esp_aes_dma_core.c")
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_common.c" target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_common.c"

View File

@@ -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 <string.h>
#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 <sys/lock.h>
#include "hal/aes_hal.h"
#include "hal/aes_ll.h"
#include "esp_aes_internal.h"
#include <freertos/FreeRTOS.h>
#include <stdio.h>
#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 );
}

View File

@@ -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 <string.h>
#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 */

View File

@@ -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 <string.h>
#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 <freertos/FreeRTOS.h>
/* 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;
}

View File

@@ -345,7 +345,6 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16
/** XTS-AES buffer encryption/decryption */ /** 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 ); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -34,6 +34,7 @@
#include "esp_sha_internal.h" #include "esp_sha_internal.h"
#include "sha/sha_core.h" #include "sha/sha_core.h"
#include "esp_compiler.h"
/* Implementation that should never be optimized out by the compiler */ /* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize(void *v, size_t n) 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); esp_internal_sha_update_state(ctx);
#if SOC_SHA_SUPPORT_DMA #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); int ret = esp_sha_dma(SHA1, data, 64, NULL, 0, ctx->first_block);
if (ret != 0) { if (ret != 0) {
esp_sha_release_hardware(); esp_sha_release_hardware();

View File

@@ -34,6 +34,7 @@
#include "esp_sha_internal.h" #include "esp_sha_internal.h"
#include "sha/sha_core.h" #include "sha/sha_core.h"
#include "esp_compiler.h"
/* Implementation that should never be optimized out by the compiler */ /* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize(void *v, size_t n) 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); esp_internal_sha_update_state(ctx);
#if SOC_SHA_SUPPORT_DMA #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); int ret = esp_sha_dma(ctx->mode, data, 64, NULL, 0, ctx->first_block);
if (ret != 0) { if (ret != 0) {
esp_sha_release_hardware(); esp_sha_release_hardware();

View File

@@ -40,6 +40,7 @@
#include "esp_sha_internal.h" #include "esp_sha_internal.h"
#include "sha/sha_core.h" #include "sha/sha_core.h"
#include "esp_compiler.h"
/* Implementation that should never be optimized out by the compiler */ /* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize(void *v, size_t n) 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 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); ret = esp_sha_dma(ctx->mode, data, 128, NULL, 0, ctx->first_block);
if (ret != 0) { if (ret != 0) {
esp_sha_release_hardware(); esp_sha_release_hardware();

View File

@@ -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 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`. - 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. :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. The help text for each option has some more information for reference.

View File

@@ -223,6 +223,7 @@ MbedTLS 功能
- 可以考虑禁用在 ``TLS Key Exchange Methods`` 子菜单中列出的一些密码套件(例如 :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`),以减小代码大小。 - 可以考虑禁用在 ``TLS Key Exchange Methods`` 子菜单中列出的一些密码套件(例如 :ref:`CONFIG_MBEDTLS_KEY_EXCHANGE_RSA`),以减小代码大小。
- 如果应用程序已经通过使用 :cpp:func:`mbedtls_strerror` 拉取 mbedTLS 错误字符串,则可以考虑禁用 :ref:`CONFIG_MBEDTLS_ERROR_STRINGS` - 如果应用程序已经通过使用 :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 签名的软件防护措施。 :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`。
每个选项的帮助文本中都有更多信息可供参考。 每个选项的帮助文本中都有更多信息可供参考。

View File

@@ -470,8 +470,6 @@ components/lwip/apps/ping/ping.c
components/lwip/include/apps/esp_ping.h components/lwip/include/apps/esp_ping.h
components/lwip/include/apps/ping/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/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/aes/esp_aes_xts.c
components/mbedtls/port/include/aes/esp_aes.h components/mbedtls/port/include/aes/esp_aes.h
components/mbedtls/port/include/aes_alt.h components/mbedtls/port/include/aes_alt.h