From 457ce080aec9811faee26a1ea5293fff17049fee Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 12 Nov 2020 15:11:38 +0800 Subject: [PATCH] AES: refactor and add HAL layer Refactor the AES driver and add HAL, LL and caps. Add better support for running AES-GCM fully in hardware. --- components/esp32/test/test_aes_sha_rsa.c | 2 +- components/esp_rom/include/esp32/rom/aes.h | 2 +- components/hal/CMakeLists.txt | 1 + components/hal/aes_hal.c | 227 +++ components/hal/esp32/include/hal/aes_ll.h | 137 ++ components/hal/esp32c3/include/hal/aes_ll.h | 235 +++ components/hal/esp32s2/include/hal/aes_ll.h | 317 ++++ .../hal/esp32s2/include/hal/crypto_dma_ll.h | 38 +- components/hal/esp32s3/include/hal/aes_ll.h | 235 +++ components/hal/esp32s3/include/hal/gdma_ll.h | 17 +- components/hal/include/hal/aes_hal.h | 162 ++ components/hal/include/hal/aes_types.h | 48 + components/hal/sha_hal.c | 5 +- .../include/esp32/idf_performance_target.h | 1 - .../include/esp32s2/idf_performance_target.h | 3 +- components/mbedtls/CMakeLists.txt | 10 +- components/mbedtls/component.mk | 2 +- .../port/{esp32/aes.c => aes/block/esp_aes.c} | 237 +-- .../port/{esp32s3/aes.c => aes/dma/esp_aes.c} | 573 +++---- components/mbedtls/port/aes/esp_aes_common.c | 83 + components/mbedtls/port/aes/esp_aes_gcm.c | 695 ++++++++ .../mbedtls/port/{ => aes}/esp_aes_xts.c | 14 +- components/mbedtls/port/esp32s2/aes.c | 1524 ----------------- .../include/{esp32s3/aes.h => aes/esp_aes.h} | 75 +- .../{esp32s3/gcm.h => aes/esp_aes_gcm.h} | 25 +- .../crypto_dma.h => aes/esp_aes_internal.h} | 32 +- components/mbedtls/port/include/aes_alt.h | 10 +- components/mbedtls/port/include/esp32/aes.h | 326 +--- components/mbedtls/port/include/esp32s2/aes.h | 340 +--- components/mbedtls/port/include/esp32s2/gcm.h | 218 +-- components/mbedtls/port/include/gcm_alt.h | 29 +- components/mbedtls/test/test_aes.c | 225 +-- components/mbedtls/test/test_aes_gcm.c | 494 ++++++ components/mbedtls/test/test_aes_perf.c | 74 +- components/mbedtls/test/test_esp_crt_bundle.c | 37 +- components/mbedtls/test/test_sha_perf.c | 2 +- components/soc/esp32/include/soc/soc_caps.h | 5 + components/soc/esp32c3/include/soc/soc_caps.h | 9 + components/soc/esp32s2/include/soc/soc_caps.h | 12 + components/soc/esp32s3/include/soc/soc.h | 6 +- components/soc/esp32s3/include/soc/soc_caps.h | 10 + .../soc/include/soc/soc_memory_layout.h | 2 +- 42 files changed, 3202 insertions(+), 3297 deletions(-) create mode 100644 components/hal/aes_hal.c create mode 100644 components/hal/esp32/include/hal/aes_ll.h create mode 100644 components/hal/esp32c3/include/hal/aes_ll.h create mode 100644 components/hal/esp32s2/include/hal/aes_ll.h create mode 100644 components/hal/esp32s3/include/hal/aes_ll.h create mode 100644 components/hal/include/hal/aes_hal.h create mode 100644 components/hal/include/hal/aes_types.h rename components/mbedtls/port/{esp32/aes.c => aes/block/esp_aes.c} (63%) rename components/mbedtls/port/{esp32s3/aes.c => aes/dma/esp_aes.c} (65%) create mode 100644 components/mbedtls/port/aes/esp_aes_common.c create mode 100644 components/mbedtls/port/aes/esp_aes_gcm.c rename components/mbedtls/port/{ => aes}/esp_aes_xts.c (97%) delete mode 100644 components/mbedtls/port/esp32s2/aes.c rename components/mbedtls/port/include/{esp32s3/aes.h => aes/esp_aes.h} (90%) rename components/mbedtls/port/include/{esp32s3/gcm.h => aes/esp_aes_gcm.h} (95%) rename components/mbedtls/port/include/{esp32s3/crypto_dma.h => aes/esp_aes_internal.h} (51%) create mode 100644 components/mbedtls/test/test_aes_gcm.c diff --git a/components/esp32/test/test_aes_sha_rsa.c b/components/esp32/test/test_aes_sha_rsa.c index c18850a190..b5b977421f 100644 --- a/components/esp32/test/test_aes_sha_rsa.c +++ b/components/esp32/test/test_aes_sha_rsa.c @@ -17,7 +17,7 @@ #include "esp_log.h" #include "mbedtls/sha256.h" #include "sha/sha_parallel_engine.h" -#include "esp32/aes.h" +#include "aes/esp_aes.h" #include "mbedtls/rsa.h" static const char *TAG = "test"; diff --git a/components/esp_rom/include/esp32/rom/aes.h b/components/esp_rom/include/esp32/rom/aes.h index bbe13d22e4..4657d5223e 100644 --- a/components/esp_rom/include/esp32/rom/aes.h +++ b/components/esp_rom/include/esp32/rom/aes.h @@ -2,7 +2,7 @@ ROM functions for hardware AES support. It is not recommended to use these functions directly, - use the wrapper functions in esp32/aes.h instead. + use the wrapper functions in aes/esp_aes.h instead. */ // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 85bc1170bc..2814e70494 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -28,6 +28,7 @@ if(NOT BOOTLOADER_BUILD) "soc_hal.c" "interrupt_controller_hal.c" "sha_hal.c" + "aes_hal.c" "twai_hal.c" "twai_hal_iram.c" "${target}/interrupt_descriptor_table.c") diff --git a/components/hal/aes_hal.c b/components/hal/aes_hal.c new file mode 100644 index 0000000000..8f697bcd41 --- /dev/null +++ b/components/hal/aes_hal.c @@ -0,0 +1,227 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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 HAL layer for AES + +#include "hal/aes_hal.h" +#include "hal/aes_ll.h" +#include +#include +#include "soc/soc_caps.h" + +#if SOC_AES_CRYPTO_DMA +#include "soc/crypto_dma_reg.h" +#include "hal/crypto_dma_ll.h" +#elif SOC_AES_GENERAL_DMA +#include "hal/gdma_ll.h" +#endif + +uint8_t aes_hal_setkey(const uint8_t *key, size_t key_bytes, int mode) +{ + aes_ll_set_mode(mode, key_bytes); + + uint8_t key_bytes_in_hardware = aes_ll_write_key(key, key_bytes / 4); + /* Used for fault injection check: all words of key data should have been written to hardware */ + return key_bytes_in_hardware; +} + +/** + * @brief Busy wait until the AES accelerator is idle + * + */ +static inline void aes_hal_wait_idle(void) +{ + while (aes_ll_get_state() != ESP_AES_STATE_IDLE) { + } +} + +void aes_hal_transform_block(const void *input_block, void *output_block) +{ + aes_ll_write_block(input_block); + aes_ll_start_transform(); + aes_hal_wait_idle(); + aes_ll_read_block(output_block); +} + +#if SOC_AES_SUPPORT_DMA + +#if SOC_AES_GENERAL_DMA +/** + * @brief Initialize the DMA + * + * @param input AES input descriptor (outlink) + * @param output AES output descriptor (inlink) + */ +static inline void aes_hal_dma_init(const lldesc_t *input, const lldesc_t *output) +{ + /* Update driver when centralized DMA interface implemented, IDF-2192 */ + gdma_ll_tx_enable_descriptor_burst(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, false); + gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, false); + gdma_ll_rx_enable_descriptor_burst(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, false); + gdma_ll_rx_enable_data_burst(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, false); + + gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, GDMA_LL_PERIPH_ID_AES); + gdma_ll_rx_connect_to_periph(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, GDMA_LL_PERIPH_ID_AES); + + /* An L2 FIFO bigger than 40 bytes is need when accessing external ram */ + gdma_ll_tx_extend_fifo_size_to(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, 40); + gdma_ll_rx_extend_l2_fifo_size_to(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, 40); + gdma_ll_tx_set_block_size_psram(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, GDMA_OUT_EXT_MEM_BK_SIZE_16B); + gdma_ll_rx_set_block_size_psram(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, GDMA_OUT_EXT_MEM_BK_SIZE_16B); + + /* Set descriptors */ + gdma_ll_tx_set_desc_addr(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, (uint32_t)input); + gdma_ll_rx_set_desc_addr(&GDMA, SOC_GDMA_AES_DMA_CHANNEL, (uint32_t)output); + + gdma_ll_rx_reset_channel(&GDMA, SOC_GDMA_AES_DMA_CHANNEL); + gdma_ll_tx_reset_channel(&GDMA, SOC_GDMA_AES_DMA_CHANNEL); + + /* Start transfer */ + gdma_ll_tx_start(&GDMA, SOC_GDMA_AES_DMA_CHANNEL); + gdma_ll_rx_start(&GDMA, SOC_GDMA_AES_DMA_CHANNEL); +} + +static inline bool aes_hal_dma_done(const lldesc_t *output) +{ + return (gdma_ll_rx_is_fsm_idle(&GDMA, SOC_GDMA_AES_DMA_CHANNEL) && (output->owner == 0)); +} +#endif //SOC_AES_GENERAL_DMA + + + +#if SOC_AES_CRYPTO_DMA +/** + * @brief Initialize the DMA + * + * @param input AES input descriptor (outlink) + * @param output AES output descriptor (inlink) + */ +static inline void aes_hal_dma_init(const lldesc_t *input, const lldesc_t *output) +{ + crypto_dma_ll_reset(); + crypto_dma_ll_set_mode(CRYPTO_DMA_AES); + + /* Set descriptors, input to AES comes from outlink DMA and viceversa */ + crypto_dma_ll_outlink_set((uint32_t)input); + crypto_dma_ll_inlink_set((uint32_t)output); + + /* Start transfer */ + crypto_dma_ll_outlink_start(); + crypto_dma_ll_inlink_start(); +} + +static inline bool aes_hal_dma_done(lldesc_t *output) +{ + return (crypto_dma_ll_inlink_is_eof() && (output->owner == 0)); +} +#endif //SOC_AES_CRYPTO_DMA + +void aes_hal_transform_dma_start(const lldesc_t *input, const lldesc_t *output, size_t num_blocks) +{ + aes_ll_dma_enable(true); + aes_hal_dma_init(input, output); + + /* Write the number of blocks */ + aes_ll_set_num_blocks(num_blocks); + + /* Start encrypting/decrypting */ + aes_ll_start_transform(); +} + +void aes_hal_transform_dma_finish(void) +{ + aes_ll_dma_exit(); + aes_ll_dma_enable(false); +} + +void aes_hal_mode_init(esp_aes_mode_t mode) +{ + /* Set the algorith mode CBC, CFB ... */ + aes_ll_set_block_mode(mode); + /* Presently hard-coding the INC function to 32 bit */ + if (mode == ESP_AES_BLOCK_MODE_CTR) { + aes_ll_set_inc(); + } +} + +void aes_hal_set_iv(const uint8_t *iv) +{ + aes_ll_set_iv(iv); +} + +void aes_hal_read_iv(uint8_t *iv) +{ + aes_ll_read_iv(iv); +} + +static inline void aes_hal_wait_done(void) +{ + while (aes_ll_get_state() != ESP_AES_STATE_DONE) {} +} + +void aes_hal_wait_dma_done(lldesc_t *output) +{ + /* Checking this if interrupt is used also, to avoid + issues with AES fault injection + */ + aes_hal_wait_done(); + + /* Wait for DMA write operation to complete */ + while (1) { + if ( aes_hal_dma_done(output) ) { + break; + } + } +} + +#endif //SOC_AES_SUPPORT_DMA + +#if SOC_AES_SUPPORT_GCM + +void aes_hal_gcm_calc_hash(uint8_t *gcm_hash) +{ + aes_ll_dma_enable(true); + aes_ll_start_transform(); + + aes_hal_wait_idle(); + + aes_ll_gcm_read_hash(gcm_hash); +} + +void aes_hal_transform_dma_gcm_start(const lldesc_t *input, const lldesc_t *output, size_t num_blocks) +{ + aes_hal_dma_init(input, output); + + /* Write the number of blocks */ + aes_ll_set_num_blocks(num_blocks); + + /* Start encrypting/decrypting */ + aes_ll_cont_transform(); +} + +void aes_hal_gcm_init(size_t aad_num_blocks, size_t num_valid_bit) +{ + aes_ll_gcm_set_aad_num_blocks(aad_num_blocks); + aes_ll_gcm_set_num_valid_bit(num_valid_bit); +} + +void aes_hal_gcm_read_tag(uint8_t *tag, size_t tag_len) +{ + uint8_t tag_res[TAG_BYTES]; + aes_ll_gcm_read_tag(tag_res); + memcpy(tag, tag_res, tag_len); +} + + +#endif //SOC_AES_SUPPORT_GCM diff --git a/components/hal/esp32/include/hal/aes_ll.h b/components/hal/esp32/include/hal/aes_ll.h new file mode 100644 index 0000000000..8283397dde --- /dev/null +++ b/components/hal/esp32/include/hal/aes_ll.h @@ -0,0 +1,137 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include "soc/hwcrypto_reg.h" +#include "soc/dport_access.h" +#include "hal/aes_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief State of AES accelerator, busy or idle + * + */ +typedef enum { + ESP_AES_STATE_BUSY = 0, /* Transform in progress */ + ESP_AES_STATE_IDLE, /* AES accelerator is idle */ +} esp_aes_state_t; + + +/** + * @brief Write the encryption/decryption key to hardware + * + * @param key Key to be written to the AES hardware + * @param key_word_len Number of words in the key + * + * @return Number of bytes written to hardware, used for fault injection check, + * if a write was skipped then this sum is likely to be wrong + */ +static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len) +{ + /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ + volatile uint8_t key_bytes_in_hardware = 0; + uint32_t *key_words = (uint32_t *)key; + + for (int i = 0; i < key_word_len; i++) { + DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(key_words + i)); + key_bytes_in_hardware += 4; + } + return key_bytes_in_hardware; +} + +/** + * @brief Sets the mode + * + * @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0 + * @param key_bytes Number of bytes in the key + */ +static inline void aes_ll_set_mode(int mode, uint8_t key_bytes) +{ + const uint32_t MODE_DECRYPT_BIT = 4; + unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + + /* See TRM for the mapping between keylength and mode bit */ + DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2)); +} + +/** + * @brief Writes message block to AES hardware + * + * @param input Block to be written + */ +static inline void aes_ll_write_block(const uint8_t *input) +{ + const uint32_t *input_words = (const uint32_t *)input; + uint32_t i0; + uint32_t i1; + uint32_t i2; + uint32_t i3; + + /* Storing i0,i1,i2,i3 in registers not an array + helps a lot with optimisations at -Os level */ + i0 = input_words[0]; + DPORT_REG_WRITE(AES_TEXT_BASE, i0); + + i1 = input_words[1]; + DPORT_REG_WRITE(AES_TEXT_BASE + 4, i1); + + i2 = input_words[2]; + DPORT_REG_WRITE(AES_TEXT_BASE + 8, i2); + + i3 = input_words[3]; + DPORT_REG_WRITE(AES_TEXT_BASE + 12, i3); +} + +/** + * @brief Read the AES block + * + * @note If a transform was ran then this is the output + * + * @param output the output of the transform, length = AES_BLOCK_BYTES + */ +static inline void aes_ll_read_block(void *output) +{ + uint32_t *output_words = (uint32_t *)output; + esp_dport_access_read_buffer(output_words, AES_TEXT_BASE, AES_BLOCK_WORDS); +} + + +/** + * @brief Starts block transform + * + */ +static inline void aes_ll_start_transform(void) +{ + DPORT_REG_WRITE(AES_START_REG, 1); +} + + +/** + * @brief Read state of AES accelerator + * + * @return esp_aes_state_t + */ +static inline esp_aes_state_t aes_ll_get_state(void) +{ + return DPORT_REG_READ(AES_IDLE_REG); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32c3/include/hal/aes_ll.h b/components/hal/esp32c3/include/hal/aes_ll.h new file mode 100644 index 0000000000..0eb7fabc64 --- /dev/null +++ b/components/hal/esp32c3/include/hal/aes_ll.h @@ -0,0 +1,235 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include +#include "soc/hwcrypto_reg.h" +#include "hal/aes_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief State of AES accelerator, busy, idle or done + * + */ +typedef enum { + ESP_AES_STATE_IDLE = 0, /* AES accelerator is idle */ + ESP_AES_STATE_BUSY, /* Transform in progress */ + ESP_AES_STATE_DONE, /* Transform completed */ +} esp_aes_state_t; + + +/** + * @brief Write the encryption/decryption key to hardware + * + * @param key Key to be written to the AES hardware + * @param key_word_len Number of words in the key + * + * @return volatile number of bytes written to hardware, used for fault injection check + */ +static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len) +{ + /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ + volatile uint8_t key_in_hardware = 0; + uint32_t *key_words = (uint32_t *)key; + + for (int i = 0; i < key_word_len; i++) { + REG_WRITE(AES_KEY_BASE + i * 4, *(key_words + i)); + key_in_hardware += 4; + } + return key_in_hardware; +} + +/** + * @brief Sets the mode + * + * @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0 + * @param key_bytes Number of bytes in the key + */ +static inline void aes_ll_set_mode(int mode, uint8_t key_bytes) +{ + const uint32_t MODE_DECRYPT_BIT = 4; + unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + + /* See TRM for the mapping between keylength and mode bit */ + REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2)); +} + +/** + * @brief Writes message block to AES hardware + * + * @param input Block to be written + */ +static inline void aes_ll_write_block(const void *input) +{ + const uint32_t *input_words = (const uint32_t *)input; + uint32_t i0, i1, i2, i3; + + /* Storing i0,i1,i2,i3 in registers, not in an array + helps a lot with optimisations at -Os level */ + i0 = input_words[0]; + REG_WRITE(AES_TEXT_IN_BASE, i0); + + i1 = input_words[1]; + REG_WRITE(AES_TEXT_IN_BASE + 4, i1); + + i2 = input_words[2]; + REG_WRITE(AES_TEXT_IN_BASE + 8, i2); + + i3 = input_words[3]; + REG_WRITE(AES_TEXT_IN_BASE + 12, i3); +} + +/** + * @brief Read the AES block + * + * @param output the output of the transform, length = AES_BLOCK_BYTES + */ +static inline void aes_ll_read_block(void *output) +{ + uint32_t *output_words = (uint32_t *)output; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < AES_BLOCK_WORDS; i++) { + output_words[i] = REG_READ(AES_TEXT_OUT_BASE + (i * REG_WIDTH)); + } +} + +/** + * @brief Starts block transform + * + */ +static inline void aes_ll_start_transform(void) +{ + REG_WRITE(AES_TRIGGER_REG, 1); +} + + +/** + * @brief Read state of AES accelerator + * + * @return esp_aes_state_t + */ +static inline esp_aes_state_t aes_ll_get_state(void) +{ + return REG_READ(AES_STATE_REG); +} + + +/** + * @brief Set mode of operation + * + * @note Only used for DMA transforms + * + * @param mode + */ +static inline void aes_ll_set_block_mode(esp_aes_mode_t mode) +{ + REG_WRITE(AES_BLOCK_MODE_REG, mode); +} + +/** + * @brief Set AES-CTR counter to INC32 + * + * @note Only affects AES-CTR mode + * + */ +static inline void aes_ll_set_inc(void) +{ + REG_WRITE(AES_INC_SEL_REG, 0); +} + +/** + * @brief Release the DMA + * + */ +static inline void aes_ll_dma_exit(void) +{ + REG_WRITE(AES_DMA_EXIT_REG, 0); +} + +/** + * @brief Sets the number of blocks to be transformed + * + * @note Only used for DMA transforms + * + * @param num_blocks Number of blocks to transform + */ +static inline void aes_ll_set_num_blocks(size_t num_blocks) +{ + REG_WRITE(AES_BLOCK_NUM_REG, num_blocks); +} + +/* + * Write IV to hardware iv registers + */ +static inline void aes_ll_set_iv(const uint8_t *iv) +{ + uint32_t *iv_words = (uint32_t *)iv; + uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE); + + for (int i = 0; i < IV_WORDS; i++ ) { + REG_WRITE(®_addr_buf[i], iv_words[i]); + } +} + +/* + * Read IV from hardware iv registers + */ +static inline void aes_ll_read_iv(uint8_t *iv) +{ + uint32_t *iv_words = (uint32_t *)iv; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < IV_WORDS; i++) { + iv_words[i] = REG_READ(AES_IV_BASE + (i * REG_WIDTH)); + } +} + +/** + * @brief Enable or disable DMA mode + * + * @param enable true to enable, false to disable. + */ +static inline void aes_ll_dma_enable(bool enable) +{ + REG_WRITE(AES_DMA_ENABLE_REG, enable); +} + +/** + * @brief Enable or disable transform completed interrupt + * + * @param enable true to enable, false to disable. + */ +static inline void aes_ll_interrupt_enable(bool enable) +{ + REG_WRITE(AES_INT_ENA_REG, enable); +} + +/** + * @brief Clears the interrupt + * + */ +static inline void aes_ll_interrupt_clear(void) +{ + REG_WRITE(AES_INT_CLR_REG, 1); +} + + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/aes_ll.h b/components/hal/esp32s2/include/hal/aes_ll.h new file mode 100644 index 0000000000..9056216517 --- /dev/null +++ b/components/hal/esp32s2/include/hal/aes_ll.h @@ -0,0 +1,317 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include +#include "soc/hwcrypto_reg.h" +#include "hal/aes_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief State of AES accelerator, busy, idle or done + * + */ +typedef enum { + ESP_AES_STATE_IDLE = 0, /* AES accelerator is idle */ + ESP_AES_STATE_BUSY, /* Transform in progress */ + ESP_AES_STATE_DONE, /* Transform completed */ +} esp_aes_state_t; + + +/** + * @brief Write the encryption/decryption key to hardware + * + * @param key Key to be written to the AES hardware + * @param key_word_len Number of words in the key + * + * @return Number of bytes written to hardware, used for fault injection check + */ +static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len) +{ + /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ + volatile uint8_t key_in_hardware = 0; + uint32_t *key_words = (uint32_t *)key; + + for (int i = 0; i < key_word_len; i++) { + REG_WRITE(AES_KEY_BASE + i * 4, *(key_words + i)); + key_in_hardware += 4; + } + return key_in_hardware; +} + +/** + * @brief Sets the mode + * + * @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0 + * @param key_bytes Number of bytes in the key + */ +static inline void aes_ll_set_mode(int mode, uint8_t key_bytes) +{ + const uint32_t MODE_DECRYPT_BIT = 4; + unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + + /* See TRM for the mapping between keylength and mode bit */ + REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2)); +} + +/** + * @brief Writes message block to AES hardware + * + * @param input Block to be written + */ +static inline void aes_ll_write_block(const void *input) +{ + const uint32_t *input_words = (const uint32_t *)input; + uint32_t i0, i1, i2, i3; + + /* Storing i0,i1,i2,i3 in registers not an array + helps a lot with optimisations at -Os level */ + i0 = input_words[0]; + REG_WRITE(AES_TEXT_IN_BASE, i0); + + i1 = input_words[1]; + REG_WRITE(AES_TEXT_IN_BASE + 4, i1); + + i2 = input_words[2]; + REG_WRITE(AES_TEXT_IN_BASE + 8, i2); + + i3 = input_words[3]; + REG_WRITE(AES_TEXT_IN_BASE + 12, i3); +} + +/** + * @brief Read the AES block + * + * @param output the output of the transform, length = AES_BLOCK_BYTES + */ +static inline void aes_ll_read_block(void *output) +{ + uint32_t *output_words = (uint32_t *)output; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < AES_BLOCK_WORDS; i++) { + output_words[i] = REG_READ(AES_TEXT_OUT_BASE + (i * REG_WIDTH)); + } +} + + +/** + * @brief Starts block transform + * + */ +static inline void aes_ll_start_transform(void) +{ + REG_WRITE(AES_TRIGGER_REG, 1); +} + +/** + * @brief Continue a previous started transform + * + * @note Only used when doing GCM + */ +static inline void aes_ll_cont_transform(void) +{ + REG_WRITE(AES_CONTINUE_REG, 1); +} + +/** + * @brief Read state of AES accelerator + * + * @return esp_aes_state_t + */ +static inline esp_aes_state_t aes_ll_get_state(void) +{ + return REG_READ(AES_STATE_REG); +} + + +/** + * @brief Set mode of operation + * + * @note Only used for DMA transforms + * + * @param mode + */ +static inline void aes_ll_set_block_mode(esp_aes_mode_t mode) +{ + REG_WRITE(AES_BLOCK_MODE_REG, mode); +} + +/** + * @brief Set AES-CTR counter to INC32 + * + * @note Only affects AES-CTR mode + * + */ +static inline void aes_ll_set_inc(void) +{ + REG_WRITE(AES_INC_SEL_REG, 0); +} + +/** + * @brief Release the DMA + * + */ +static inline void aes_ll_dma_exit(void) +{ + REG_WRITE(AES_DMA_EXIT_REG, 0); +} + +/** + * @brief Sets the number of blocks to be transformed + * + * @note Only used for DMA transforms + * + * @param num_blocks Number of blocks to transform + */ +static inline void aes_ll_set_num_blocks(size_t num_blocks) +{ + REG_WRITE(AES_BLOCK_NUM_REG, num_blocks); +} + +/* + * Write IV to hardware iv registers + */ +static inline void aes_ll_set_iv(const uint8_t *iv) +{ + uint32_t *iv_words = (uint32_t *)iv; + uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE); + + for (int i = 0; i < IV_WORDS; i++ ) { + REG_WRITE(®_addr_buf[i], iv_words[i]); + } +} + +/* + * Read IV from hardware iv registers + */ +static inline void aes_ll_read_iv(uint8_t *iv) +{ + uint32_t *iv_words = (uint32_t *)iv; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < IV_WORDS; i++) { + iv_words[i] = REG_READ(AES_IV_BASE + (i * REG_WIDTH)); + } +} + +/** + * @brief Enable or disable DMA mode + * + * @param enable true to enable, false to disable. + */ +static inline void aes_ll_dma_enable(bool enable) +{ + REG_WRITE(AES_DMA_ENABLE_REG, enable); +} + +/** + * @brief Enable or disable transform completed interrupt + * + * @param enable true to enable, false to disable. + */ +static inline void aes_ll_interrupt_enable(bool enable) +{ + REG_WRITE(AES_INT_ENA_REG, enable); +} + +/** + * @brief Clears the interrupt + * + */ +static inline void aes_ll_interrupt_clear(void) +{ + REG_WRITE(AES_INT_CLR_REG, 1); +} + +/** + * @brief Reads the AES-GCM hash sub-key H + * + * @param gcm_hash hash value + */ +static inline void aes_ll_gcm_read_hash(uint8_t *gcm_hash) +{ + uint32_t *hash_words = (uint32_t *)gcm_hash; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < AES_BLOCK_WORDS; i++) { + hash_words[i] = REG_READ(AES_H_BASE + (i * REG_WIDTH)); + } + +} + +/** + * @brief Sets the number of Additional Authenticated Data (AAD) blocks + * + * @note Only affects AES-GCM + * + * @param aad_num_blocks the number of Additional Authenticated Data (AAD) blocks + */ +static inline void aes_ll_gcm_set_aad_num_blocks(size_t aad_num_blocks) +{ + REG_WRITE(AES_AAD_BLOCK_NUM_REG, aad_num_blocks); +} + +/** + * @brief Sets the J0 value, for more information see the GCM subchapter in the TRM + * + * @note Only affects AES-GCM + * + * @param j0 J0 value + */ +static inline void aes_ll_gcm_set_j0(const uint8_t *j0) +{ + uint32_t *j0_words = (uint32_t *)j0; + uint32_t *reg_addr_buf = (uint32_t *)(AES_J_BASE); + + for (int i = 0; i < AES_BLOCK_WORDS; i++ ) { + REG_WRITE(®_addr_buf[i], j0_words[i]); + } +} + +/** + * @brief Sets the number of effective bits of incomplete blocks in plaintext/cipertext. + * + * @note Only affects AES-GCM + * + * @param num_valid_bits the number of effective bits of incomplete blocks in plaintext/cipertext. + */ +static inline void aes_ll_gcm_set_num_valid_bit(size_t num_valid_bits) +{ + REG_WRITE(AES_BIT_VALID_NUM_REG, num_valid_bits); +} + +/** + * @brief Read the tag after a AES-GCM transform + * + * @param tag Pointer to where to store the result with length TAG_WORDS + */ +static inline void aes_ll_gcm_read_tag(uint8_t *tag) +{ + uint32_t *tag_words = (uint32_t *)tag; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < TAG_WORDS; i++) { + tag_words[i] = REG_READ(AES_T_BASE + (i * REG_WIDTH)); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s2/include/hal/crypto_dma_ll.h b/components/hal/esp32s2/include/hal/crypto_dma_ll.h index e78c78fabe..5c65c9249a 100644 --- a/components/hal/esp32s2/include/hal/crypto_dma_ll.h +++ b/components/hal/esp32s2/include/hal/crypto_dma_ll.h @@ -19,29 +19,28 @@ ******************************************************************************/ #pragma once -#include "soc/hwcrypto_reg.h" -#include "soc/dport_reg.h" - #ifdef __cplusplus extern "C" { #endif +#include "soc/hwcrypto_reg.h" +#include "soc/dport_reg.h" + typedef enum { - CRYPTO_DMA_AES = 0, + CRYPTO_DMA_AES= 0, CRYPTO_DMA_SHA, } crypto_dma_mode_t; /** - * @brief Resets set the outlink + * @brief Resets the DMA * */ -static inline void crypto_dma_ll_outlink_reset(void) +static inline void crypto_dma_ll_reset(void) { SET_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); CLEAR_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); } - /** * @brief Selects the crypto DMA mode * @@ -63,6 +62,17 @@ static inline void crypto_dma_ll_outlink_set(uint32_t outlink_addr) SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, outlink_addr & OUT_LINK_REG_OUTLINK_ADDR); } +/** + * @brief Sets up the inlink for a transfer + * + * @param inlink_addr Address of the inlink buffer + */ +static inline void crypto_dma_ll_inlink_set(uint32_t inlink_addr) +{ + CLEAR_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, IN_LINK_REG_INLINK_ADDR); + SET_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, inlink_addr & IN_LINK_REG_INLINK_ADDR); +} + /** * @brief Starts the outlink * @@ -72,6 +82,20 @@ static inline void crypto_dma_ll_outlink_start(void) SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_START); } +/** + * @brief Starts the inlink + * + */ +static inline void crypto_dma_ll_inlink_start(void) +{ + SET_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, IN_LINK_REG_INLINK_START); +} + +static inline bool crypto_dma_ll_inlink_is_eof(void) +{ + return ((REG_READ(CRYPTO_DMA_INT_RAW_REG) & INT_RAW_IN_SUC_EOF) == INT_RAW_IN_SUC_EOF); +} + #ifdef __cplusplus } diff --git a/components/hal/esp32s3/include/hal/aes_ll.h b/components/hal/esp32s3/include/hal/aes_ll.h new file mode 100644 index 0000000000..dbc831f038 --- /dev/null +++ b/components/hal/esp32s3/include/hal/aes_ll.h @@ -0,0 +1,235 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include +#include "soc/hwcrypto_reg.h" +#include "hal/aes_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief State of AES accelerator, busy, idle or done + * + */ +typedef enum { + ESP_AES_STATE_IDLE = 0, /* AES accelerator is idle */ + ESP_AES_STATE_BUSY, /* Transform in progress */ + ESP_AES_STATE_DONE, /* Transform completed */ +} esp_aes_state_t; + + +/** + * @brief Write the encryption/decryption key to hardware + * + * @param key Key to be written to the AES hardware + * @param key_word_len Number of words in the key + * + * @return volatile number of bytes written to hardware, used for fault injection check + */ +static inline uint8_t aes_ll_write_key(const uint8_t *key, size_t key_word_len) +{ + /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ + volatile uint8_t key_in_hardware = 0; + uint32_t *key_words = (uint32_t *)key; + + for (int i = 0; i < key_word_len; i++) { + REG_WRITE(AES_KEY_BASE + i * 4, *(key_words + i)); + key_in_hardware += 4; + } + return key_in_hardware; +} + +/** + * @brief Sets the mode + * + * @param mode ESP_AES_ENCRYPT = 1, or ESP_AES_DECRYPT = 0 + * @param key_bytes Number of bytes in the key + */ +static inline void aes_ll_set_mode(int mode, uint8_t key_bytes) +{ + const uint32_t MODE_DECRYPT_BIT = 4; + unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + + /* See TRM for the mapping between keylength and mode bit */ + REG_WRITE(AES_MODE_REG, mode_reg_base + ((key_bytes / 8) - 2)); +} + +/** + * @brief Writes message block to AES hardware + * + * @param input Block to be written + */ +static inline void aes_ll_write_block(const void *input) +{ + const uint32_t *input_words = (const uint32_t *)input; + uint32_t i0, i1, i2, i3; + + /* Storing i0,i1,i2,i3 in registers not an array + helps a lot with optimisations at -Os level */ + i0 = input_words[0]; + REG_WRITE(AES_TEXT_IN_BASE, i0); + + i1 = input_words[1]; + REG_WRITE(AES_TEXT_IN_BASE + 4, i1); + + i2 = input_words[2]; + REG_WRITE(AES_TEXT_IN_BASE + 8, i2); + + i3 = input_words[3]; + REG_WRITE(AES_TEXT_IN_BASE + 12, i3); +} + +/** + * @brief Read the AES block + * + * @param output the output of the transform, length = AES_BLOCK_BYTES + */ +static inline void aes_ll_read_block(void *output) +{ + uint32_t *output_words = (uint32_t *)output; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < AES_BLOCK_WORDS; i++) { + output_words[i] = REG_READ(AES_TEXT_OUT_BASE + (i * REG_WIDTH)); + } +} + +/** + * @brief Starts block transform + * + */ +static inline void aes_ll_start_transform(void) +{ + REG_WRITE(AES_TRIGGER_REG, 1); +} + + +/** + * @brief Read state of AES accelerator + * + * @return esp_aes_state_t + */ +static inline esp_aes_state_t aes_ll_get_state(void) +{ + return REG_READ(AES_STATE_REG); +} + + +/** + * @brief Set mode of operation + * + * @note Only used for DMA transforms + * + * @param mode + */ +static inline void aes_ll_set_block_mode(esp_aes_mode_t mode) +{ + REG_WRITE(AES_BLOCK_MODE_REG, mode); +} + +/** + * @brief Set AES-CTR counter to INC32 + * + * @note Only affects AES-CTR mode + * + */ +static inline void aes_ll_set_inc(void) +{ + REG_WRITE(AES_INC_SEL_REG, 0); +} + +/** + * @brief Release the DMA + * + */ +static inline void aes_ll_dma_exit(void) +{ + REG_WRITE(AES_DMA_EXIT_REG, 0); +} + +/** + * @brief Sets the number of blocks to be transformed + * + * @note Only used for DMA transforms + * + * @param num_blocks Number of blocks to transform + */ +static inline void aes_ll_set_num_blocks(size_t num_blocks) +{ + REG_WRITE(AES_BLOCK_NUM_REG, num_blocks); +} + +/* + * Write IV to hardware iv registers + */ +static inline void aes_ll_set_iv(const uint8_t *iv) +{ + uint32_t *iv_words = (uint32_t *)iv; + uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE); + + for (int i = 0; i < IV_WORDS; i++ ) { + REG_WRITE(®_addr_buf[i], iv_words[i]); + } +} + +/* + * Read IV from hardware iv registers + */ +static inline void aes_ll_read_iv(uint8_t *iv) +{ + uint32_t *iv_words = (uint32_t *)iv; + const size_t REG_WIDTH = sizeof(uint32_t); + + for (size_t i = 0; i < IV_WORDS; i++) { + iv_words[i] = REG_READ(AES_IV_BASE + (i * REG_WIDTH)); + } +} + +/** + * @brief Enable or disable DMA mode + * + * @param enable true to enable, false to disable. + */ +static inline void aes_ll_dma_enable(bool enable) +{ + REG_WRITE(AES_DMA_ENABLE_REG, enable); +} + +/** + * @brief Enable or disable transform completed interrupt + * + * @param enable true to enable, false to disable. + */ +static inline void aes_ll_interrupt_enable(bool enable) +{ + REG_WRITE(AES_INT_ENA_REG, enable); +} + +/** + * @brief Clears the interrupt + * + */ +static inline void aes_ll_interrupt_clear(void) +{ + REG_WRITE(AES_INT_CLR_REG, 1); +} + + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32s3/include/hal/gdma_ll.h b/components/hal/esp32s3/include/hal/gdma_ll.h index d85e447d95..8903c58ea7 100644 --- a/components/hal/esp32s3/include/hal/gdma_ll.h +++ b/components/hal/esp32s3/include/hal/gdma_ll.h @@ -52,6 +52,19 @@ extern "C" { #define GDMA_LL_TRIG_SRC_SHA (7) #define GDMA_LL_TRIG_SRC_ADC_DAC (8) +typedef enum { + GDMA_LL_PERIPH_ID_SPI2 = 0, + GDMA_LL_PERIPH_ID_SPI3, + GDMA_LL_PERIPH_ID_UART, + GDMA_LL_PERIPH_ID_I2S0, + GDMA_LL_PERIPH_ID_I2S1, + GDMA_LL_PERIPH_ID_LCD_CAM, + GDMA_LL_PERIPH_ID_AES, + GDMA_LL_PERIPH_ID_SHA, + GDMA_LL_PERIPH_ID_ADC_DAC, +} gdma_ll_periph_id_t; + + ///////////////////////////////////// Common ///////////////////////////////////////// /** * @brief Enable DMA channel M2M mode (TX channel n forward data to RX channel n), disabled by default @@ -287,7 +300,7 @@ static inline void gdma_ll_rx_set_priority(gdma_dev_t *dev, uint32_t channel, ui /** * @brief Connect DMA RX channel to a given peripheral */ -static inline void gdma_ll_rx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, uint32_t periph_id) +static inline void gdma_ll_rx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, gdma_ll_periph_id_t periph_id) { dev->peri_sel[channel].peri_in_sel = periph_id; } @@ -482,7 +495,7 @@ static inline void gdma_ll_tx_set_priority(gdma_dev_t *dev, uint32_t channel, ui /** * @brief Connect DMA TX channel to a given peripheral */ -static inline void gdma_ll_tx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, uint32_t periph_id) +static inline void gdma_ll_tx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, gdma_ll_periph_id_t periph_id) { dev->peri_sel[channel].peri_out_sel = periph_id; } diff --git a/components/hal/include/hal/aes_hal.h b/components/hal/include/hal/aes_hal.h new file mode 100644 index 0000000000..08502df93f --- /dev/null +++ b/components/hal/include/hal/aes_hal.h @@ -0,0 +1,162 @@ +// Copyright 2020 Espressif Systems (shanghai) PTE LTD +// +// 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. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +#pragma once + +#include +#include +#include "soc/lldesc.h" +#include "soc/soc_caps.h" +#include "hal/aes_types.h" +#include "hal/aes_ll.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief Sets the key used for AES encryption/decryption + * + * @param key pointer to the key + * @param key_bytes number of bytes in key + * @param mode key mode, 0 : decrypt, 1: encrypt + * + * @return uint8_t number of key bytes written to hardware, used for fault injection check + */ +uint8_t aes_hal_setkey(const uint8_t *key, size_t key_bytes, int mode); + +/** + * @brief encrypts/decrypts a single block + * + * @param input_block input block, size of AES_BLOCK_BYTES + * @param output_block output block, size of AES_BLOCK_BYTES + */ +void aes_hal_transform_block(const void *input_block, void *output_block); + +#if SOC_AES_SUPPORT_DMA +/** + * @brief Inits the AES mode of operation + * + * @param mode mode of operation, e.g. CTR or CBC + */ +void aes_hal_mode_init(esp_aes_mode_t mode); + +/** + * @brief Sets the initialization vector for the transform + * + * @note The same IV must never be reused with the same key + * + * @param iv the initialization vector, length = IV_BYTES (16 bytes) + */ +void aes_hal_set_iv(const uint8_t *iv); + +/** + * @brief Reads the initialization vector + * + * @param iv initialization vector read from HW, length = IV_BYTES (16 bytes) + */ +void aes_hal_read_iv(uint8_t *iv); + +/** + * @brief Busy waits until the DMA operation is done (descriptor owner is CPU) + * + * @param output pointer to inlink descriptor + */ +void aes_hal_wait_dma_done(lldesc_t *output); + +/** + * @brief Starts an already configured AES DMA transform + * + * @param input outlink descriptor for data to be written to the peripheral + * @param output inlink descriptor for data to be read from the peripheral + * @param num_blocks Number of blocks to transform + */ +void aes_hal_transform_dma_start(const lldesc_t *input, const lldesc_t *output, size_t num_blocks); + +/** + * @brief Finish up a AES DMA conversion, release DMA + * + */ +void aes_hal_transform_dma_finish(void); + +/** + * @brief Enable or disable transform completed interrupt + * + * @param enable true to enable, false to disable. + */ +#define aes_hal_interrupt_enable(enable) aes_ll_interrupt_enable(enable) + +/** + * @brief Clears the interrupt + * + */ +#define aes_hal_interrupt_clear() aes_ll_interrupt_clear() + +#if SOC_AES_SUPPORT_GCM +/** + * @brief Calculates the Hash sub-key H0 needed to start AES-GCM + * + * @param gcm_hash the Hash sub-key H0 output + */ +void aes_hal_gcm_calc_hash(uint8_t *gcm_hash); + +/** + * @brief Initializes the AES hardware for AES-GCM + * + * @param aad_num_blocks the number of Additional Authenticated Data (AAD) blocks + * @param num_valid_bit the number of effective bits of incomplete blocks in plaintext/cipertext + */ +void aes_hal_gcm_init(size_t aad_num_blocks, size_t num_valid_bit); + +/** + * @brief Starts a AES-GCM transform + * + * @param input outlink descriptor for data to be written to the peripheral + * @param output inlink descriptor for data to be read from the perihperal + * @param num_blocks Number of blocks to transform + */ +void aes_hal_transform_dma_gcm_start(const lldesc_t *input, const lldesc_t *output, size_t num_blocks); + +/** + * @brief Sets the J0 value, for more information see the GCM subchapter in the TRM + * + * @note Only affects AES-GCM + * + * @param j0 J0 value + */ +#define aes_hal_gcm_set_j0(j0) aes_ll_gcm_set_j0(j0) + +/** + * @brief Read the tag after a AES-GCM transform + * + * @param tag Pointer to where to store the result + * @param tag_length number of bytes to read into tag + */ +void aes_hal_gcm_read_tag(uint8_t *tag, size_t tag_len); + +#endif //SOC_AES_SUPPORT_GCM + +#endif //SOC_AES_SUPPORT_DMA + + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/aes_types.h b/components/hal/include/hal/aes_types.h new file mode 100644 index 0000000000..e12d510c6e --- /dev/null +++ b/components/hal/include/hal/aes_types.h @@ -0,0 +1,48 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// 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. +#pragma once + +/* padlock.c and aesni.c rely on these values! */ +#define ESP_AES_ENCRYPT 1 +#define ESP_AES_DECRYPT 0 + + +/* DMA AES working modes*/ +typedef enum { + ESP_AES_BLOCK_MODE_ECB = 0, + ESP_AES_BLOCK_MODE_CBC, + ESP_AES_BLOCK_MODE_OFB, + ESP_AES_BLOCK_MODE_CTR, + ESP_AES_BLOCK_MODE_CFB8, + ESP_AES_BLOCK_MODE_CFB128, + ESP_AES_BLOCK_MODE_GCM, + ESP_AES_BLOCK_MODE_MAX, +} esp_aes_mode_t; + +/* Number of bytes in an AES block */ +#define AES_BLOCK_BYTES (16) +/* Number of words in an AES block */ +#define AES_BLOCK_WORDS (4) +/* Number of bytes in an IV */ +#define IV_BYTES (16) +/* Number of words in an IV */ +#define IV_WORDS (4) +/* Number of bytes in a GCM tag block */ +#define TAG_BYTES (16) +/* Number of words in a GCM tag block */ +#define TAG_WORDS (4) + +#define AES_128_KEY_BYTES (128/8) +#define AES_192_KEY_BYTES (192/8) +#define AES_256_KEY_BYTES (256/8) diff --git a/components/hal/sha_hal.c b/components/hal/sha_hal.c index 48b5262365..ac9323be8b 100644 --- a/components/hal/sha_hal.c +++ b/components/hal/sha_hal.c @@ -26,7 +26,6 @@ #include "hal/crypto_dma_ll.h" #elif SOC_SHA_GENERAL_DMA #include "hal/gdma_ll.h" -#define DMA_PERIPH_SHA 7 #endif #define SHA1_STATE_LEN_WORDS (160 / 32) @@ -99,7 +98,7 @@ static inline void sha_hal_dma_init(lldesc_t *input) gdma_ll_tx_enable_data_burst(&GDMA, SOC_GDMA_SHA_DMA_CHANNEL, false); gdma_ll_tx_enable_auto_write_back(&GDMA, SOC_GDMA_SHA_DMA_CHANNEL, false); - gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SHA_DMA_CHANNEL, DMA_PERIPH_SHA); + gdma_ll_tx_connect_to_periph(&GDMA, SOC_GDMA_SHA_DMA_CHANNEL, GDMA_LL_PERIPH_ID_SHA); #if SOC_GDMA_SUPPORT_EXTMEM /* Atleast 40 bytes when accessing external RAM */ @@ -124,7 +123,7 @@ static inline void sha_hal_dma_init(lldesc_t *input) static inline void sha_hal_dma_init(lldesc_t *input) { crypto_dma_ll_set_mode(CRYPTO_DMA_SHA); - crypto_dma_ll_outlink_reset(); + crypto_dma_ll_reset(); crypto_dma_ll_outlink_set((uint32_t)input); crypto_dma_ll_outlink_start(); diff --git a/components/idf_test/include/esp32/idf_performance_target.h b/components/idf_test/include/esp32/idf_performance_target.h index c31e26061b..92c157e721 100644 --- a/components/idf_test/include/esp32/idf_performance_target.h +++ b/components/idf_test/include/esp32/idf_performance_target.h @@ -2,7 +2,6 @@ // AES-CBC hardware throughput (accounts for worst-case performance with PSRAM workaround) #define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.2 -#define IDF_PERFORMANCE_MIN_AES_GCM_THROUGHPUT_MBSEC 0.5 // SHA256 hardware throughput at 240MHz, threshold set lower than worst case #define IDF_PERFORMANCE_MIN_SHA256_THROUGHPUT_MBSEC 8.0 diff --git a/components/idf_test/include/esp32s2/idf_performance_target.h b/components/idf_test/include/esp32s2/idf_performance_target.h index f098f17279..90c0f7428c 100644 --- a/components/idf_test/include/esp32s2/idf_performance_target.h +++ b/components/idf_test/include/esp32s2/idf_performance_target.h @@ -1,7 +1,8 @@ #pragma once #define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 43.0 -#define IDF_PERFORMANCE_MIN_AES_GCM_THROUGHPUT_MBSEC 2.1 +#define IDF_PERFORMANCE_MIN_AES_GCM_CRYPT_TAG_THROUGHPUT_MBSEC 30.0 +#define IDF_PERFORMANCE_MIN_AES_GCM_UPDATE_THROUGHPUT_MBSEC 2.1 // SHA256 hardware throughput at 240MHz, threshold set lower than worst case #define IDF_PERFORMANCE_MIN_SHA256_THROUGHPUT_MBSEC 90.0 diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index cefca19aa4..75702bb9de 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -84,16 +84,19 @@ target_sources(mbedtls PRIVATE ${mbedtls_target_sources}) # Choose perihperal type if(CONFIG_IDF_TARGET_ESP32) set(SHA_PERIPHERAL_TYPE "parallel_engine") + set(AES_PERIPHERAL_TYPE "block") else() set(SHA_PERIPHERAL_TYPE "dma") + set(AES_PERIPHERAL_TYPE "dma") endif() target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c" "${COMPONENT_DIR}/port/esp_mem.c" "${COMPONENT_DIR}/port/esp_timing.c" "${COMPONENT_DIR}/port/sha/esp_sha.c" - "${COMPONENT_DIR}/port/esp_aes_xts.c" - "${COMPONENT_DIR}/port/${idf_target}/aes.c" + "${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/sha/${SHA_PERIPHERAL_TYPE}/sha.c" ) @@ -121,6 +124,9 @@ if(CONFIG_MBEDTLS_HARDWARE_SHA) ) endif() +if(CONFIG_MBEDTLS_HARDWARE_GCM) + target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_gcm.c") +endif() foreach(target ${mbedtls_targets}) target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h") diff --git a/components/mbedtls/component.mk b/components/mbedtls/component.mk index 7bd137a5b4..d160d9effa 100644 --- a/components/mbedtls/component.mk +++ b/components/mbedtls/component.mk @@ -5,7 +5,7 @@ COMPONENT_ADD_INCLUDEDIRS := port/include mbedtls/include esp_crt_bundle/include -COMPONENT_SRCDIRS := mbedtls/library port port/$(IDF_TARGET) port/sha port/sha/parallel_engine esp_crt_bundle +COMPONENT_SRCDIRS := mbedtls/library port port/$(IDF_TARGET) port/sha port/sha/parallel_engine port/aes port/aes/block esp_crt_bundle COMPONENT_OBJEXCLUDE := mbedtls/library/net_sockets.o diff --git a/components/mbedtls/port/esp32/aes.c b/components/mbedtls/port/aes/block/esp_aes.c similarity index 63% rename from components/mbedtls/port/esp32/aes.c rename to components/mbedtls/port/aes/block/esp_aes.c index 39d05e6c29..083d17a5d8 100644 --- a/components/mbedtls/port/esp32/aes.c +++ b/components/mbedtls/port/aes/block/esp_aes.c @@ -1,5 +1,5 @@ /** - * \brief AES block cipher, ESP32 hardware accelerated version + * \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 @@ -28,9 +28,11 @@ #include #include "mbedtls/aes.h" #include "mbedtls/platform_util.h" -#include "esp32/aes.h" +#include "aes/esp_aes.h" #include "soc/hwcrypto_periph.h" #include +#include "hal/aes_hal.h" +#include "aes/esp_aes_internal.h" #include @@ -49,10 +51,6 @@ */ static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED; -static inline bool valid_key_length(const esp_aes_context *ctx) -{ - return ctx->key_bytes == 128/8 || ctx->key_bytes == 192/8 || ctx->key_bytes == 256/8; -} void esp_aes_acquire_hardware( void ) { @@ -70,64 +68,7 @@ void esp_aes_release_hardware( void ) portEXIT_CRITICAL(&aes_spinlock); } -void esp_aes_init( esp_aes_context *ctx ) -{ - bzero( ctx, sizeof( esp_aes_context ) ); -} -void esp_aes_free( esp_aes_context *ctx ) -{ - if ( ctx == NULL ) { - return; - } - - bzero( ctx, sizeof( esp_aes_context ) ); -} - - - -/* - * AES key schedule (same for encryption or decryption, as hardware handles schedule) - * - */ -int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, - unsigned int keybits ) -{ - if (keybits != 128 && keybits != 192 && keybits != 256) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - ctx->key_bytes = keybits / 8; - memcpy(ctx->key, key, ctx->key_bytes); - ctx->key_in_hardware = 0; - return 0; -} - -/* - * Helper function to copy key from esp_aes_context buffer - * to hardware key registers. - * - * Call only while holding esp_aes_acquire_hardware(). - */ -static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode) -{ - const uint32_t MODE_DECRYPT_BIT = 4; - unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; - - ctx->key_in_hardware = 0; - - for (int i = 0; i < ctx->key_bytes/4; ++i) { - DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i)); - ctx->key_in_hardware += 4; - } - - DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2)); - - /* Fault injection check: all words of key data should have been written to hardware */ - if (ctx->key_in_hardware < 16 - || ctx->key_in_hardware != ctx->key_bytes) { - abort(); - } -} /* Run a single 16 byte block of AES, using the hardware engine. * @@ -135,8 +76,8 @@ static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode) */ static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) { - const uint32_t *input_words = (const uint32_t *)input; 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 @@ -148,26 +89,12 @@ static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) bzero(output, 16); return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; } - - /* Storing i0,i1,i2,i3 in registers not an array - helps a lot with optimisations at -Os level */ i0 = input_words[0]; - DPORT_REG_WRITE(AES_TEXT_BASE, i0); - i1 = input_words[1]; - DPORT_REG_WRITE(AES_TEXT_BASE + 4, i1); - i2 = input_words[2]; - DPORT_REG_WRITE(AES_TEXT_BASE + 8, i2); - i3 = input_words[3]; - DPORT_REG_WRITE(AES_TEXT_BASE + 12, i3); - DPORT_REG_WRITE(AES_START_REG, 1); - - while (DPORT_REG_READ(AES_IDLE_REG) != 1) { } - - esp_dport_access_read_buffer(output_words, AES_TEXT_BASE, 4); + 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. @@ -176,7 +103,7 @@ static int esp_aes_block(esp_aes_context *ctx, const void *input, void *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]) { + 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); @@ -187,12 +114,19 @@ static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output) return 0; } +void esp_aes_encrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + esp_internal_aes_encrypt(ctx, input, output); +} + /* * AES-ECB block encryption */ -int esp_internal_aes_encrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) +int esp_internal_aes_encrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) { int r; @@ -202,19 +136,26 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + 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; } +void esp_aes_decrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + esp_internal_aes_decrypt(ctx, input, output); +} + /* * AES-ECB block decryption */ -int esp_internal_aes_decrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) +int esp_internal_aes_decrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) { int r; @@ -224,7 +165,7 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); + 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; @@ -233,10 +174,10 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, /* * 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 esp_aes_crypt_ecb(esp_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) { int r; @@ -246,7 +187,7 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, mode); + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); r = esp_aes_block(ctx, input, output); esp_aes_release_hardware(); @@ -257,14 +198,13 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx, /* * 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 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 i; uint32_t *output_words = (uint32_t *)output; const uint32_t *input_words = (const uint32_t *)input; uint32_t *iv_words = (uint32_t *)iv; @@ -280,17 +220,18 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, mode); - esp_aes_setkey_hardware(ctx, mode); if ( mode == ESP_AES_DECRYPT ) { while ( length > 0 ) { memcpy(temp, input_words, 16); esp_aes_block(ctx, input_words, output_words); - for ( i = 0; i < 4; i++ ) { - output_words[i] = output_words[i] ^ iv_words[i]; - } + 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 ); @@ -301,9 +242,10 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, } else { // ESP_AES_ENCRYPT while ( length > 0 ) { - for ( i = 0; i < 4; i++ ) { - output_words[i] = input_words[i] ^ iv_words[i]; - } + 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]; esp_aes_block(ctx, output_words, output_words); memcpy( iv_words, output_words, 16 ); @@ -322,13 +264,13 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, /* * 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 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 c; size_t n = *iv_off; @@ -339,8 +281,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); if ( mode == ESP_AES_DECRYPT ) { while ( length-- ) { @@ -376,12 +317,12 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, /* * 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 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]; @@ -392,8 +333,8 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while ( length-- ) { memcpy( ov, iv, 16 ); @@ -420,13 +361,13 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, /* * 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 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; size_t n = *nc_off; @@ -437,17 +378,18 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); while ( length-- ) { if ( n == 0 ) { esp_aes_block(ctx, nonce_counter, stream_block); - for ( i = 16; i > 0; i-- ) + for ( i = 16; i > 0; i-- ) { if ( ++nonce_counter[i - 1] != 0 ) { break; } + } } c = *input++; *output++ = (unsigned char)( c ^ stream_block[n] ); @@ -465,25 +407,25 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, /* * 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 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 = 0; size_t n; - if ( ctx == NULL || iv_off == NULL || iv == NULL || - input == NULL || output == NULL ) { - return MBEDTLS_ERR_AES_BAD_INPUT_DATA; + if (ctx == NULL || iv_off == NULL || iv == NULL || + input == NULL || output == NULL ) { + return MBEDTLS_ERR_AES_BAD_INPUT_DATA; } n = *iv_off; - if( n > 15 ) { - return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + if (n > 15) { + return (MBEDTLS_ERR_AES_BAD_INPUT_DATA); } if (!valid_key_length(ctx)) { @@ -491,11 +433,12 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, } esp_aes_acquire_hardware(); + ctx->key_in_hardware = 0; + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_ENCRYPT); - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); - while( length-- ) { - if( n == 0 ) { + while (length--) { + if ( n == 0 ) { esp_aes_block(ctx, iv, iv); } *output++ = *input++ ^ iv[n]; @@ -507,5 +450,5 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, esp_aes_release_hardware(); - return( ret ); + return ( ret ); } diff --git a/components/mbedtls/port/esp32s3/aes.c b/components/mbedtls/port/aes/dma/esp_aes.c similarity index 65% rename from components/mbedtls/port/esp32s3/aes.c rename to components/mbedtls/port/aes/dma/esp_aes.c index f092b6a3df..1c78c30d4f 100644 --- a/components/mbedtls/port/esp32s3/aes.c +++ b/components/mbedtls/port/aes/dma/esp_aes.c @@ -1,5 +1,5 @@ /** - * \brief AES block cipher, ESP32-S2 hardware accelerated version + * \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 @@ -26,17 +26,8 @@ * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf */ -#include #include -#include #include "mbedtls/aes.h" -#include "esp32s3/aes.h" -#include "soc/cpu.h" -#include "soc/dport_reg.h" -#include "soc/hwcrypto_reg.h" -#include "soc/periph_defs.h" -#include "esp32s3/rom/lldesc.h" -#include "esp32s3/rom/cache.h" #include "esp_intr_alloc.h" #include "driver/periph_ctrl.h" #include "esp_log.h" @@ -44,18 +35,31 @@ #include "esp_heap_caps.h" #include "sys/param.h" #include "esp_pm.h" -#include "soc/soc_memory_layout.h" -#include "soc/gdma_reg.h" -#include "soc/gdma_struct.h" -#include "soc/extmem_reg.h" +#include "esp_crypto_lock.h" +#include "hal/aes_hal.h" +#include "aes/esp_aes_internal.h" + +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/cache.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/cache.h" +#endif + #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" -#define AES_BLOCK_BYTES 16 -#define IV_WORDS 4 +#if SOC_AES_SUPPORT_GCM +#include "aes/esp_aes_gcm.h" +#endif + +#if SOC_AES_GENERAL_DMA +#define AES_LOCK() esp_crypto_aes_lock_acquire() +#define AES_RELEASE() esp_crypto_aes_lock_release() +#elif SOC_AES_CRYPTO_DMA +#define AES_LOCK() esp_crypto_dma_lock_acquire() +#define AES_RELEASE() esp_crypto_dma_lock_release() +#endif -#define DMA_PERIPH_AES 6 /* DMA peripheral indexes */ -#define DMA_PERIPH_SHA 7 /* Max size of each chunk to process when output buffer is in unaligned external ram must be a multiple of block size */ @@ -65,22 +69,6 @@ busy-waiting, 30000 bytes is approx 0.5 ms */ #define AES_DMA_INTR_TRIG_LEN 2000 -#define ESP_PUT_BE64(a, val) \ - do { \ - *(uint64_t*)(a) = __builtin_bswap64( (uint64_t)(val) ); \ - } while (0) - - -/* DMA AES working modes*/ -typedef enum { - ESP_AES_BLOCK_MODE_ECB = 0, - ESP_AES_BLOCK_MODE_CBC, - ESP_AES_BLOCK_MODE_OFB, - ESP_AES_BLOCK_MODE_CTR, - ESP_AES_BLOCK_MODE_CFB8, - ESP_AES_BLOCK_MODE_CFB128, -} esp_aes_mode_t; - #if defined(CONFIG_MBEDTLS_AES_USE_INTERRUPT) static SemaphoreHandle_t op_complete_sem; @@ -92,143 +80,50 @@ static esp_pm_lock_handle_t s_pm_sleep_lock; static const char *TAG = "esp-aes"; -static _lock_t s_aes_lock; - -static inline bool valid_key_length(const esp_aes_context *ctx) +/* Append a descriptor to the chain, set head if chain empty */ +static inline void lldesc_append(lldesc_t **head, lldesc_t *item) { - return ctx->key_bytes == 128 / 8 || ctx->key_bytes == 256 / 8; -} + lldesc_t *it; + if (*head == NULL) { + *head = item; + return; + } + it = *head; + + while (it->empty != 0) { + it = (lldesc_t *)it->empty; + } + it->eof = 0; + it->empty = (uint32_t)item; +} void esp_aes_acquire_hardware( void ) { - _lock_acquire(&s_aes_lock); + /* Released by esp_aes_release_hardware()*/ + AES_LOCK(); - /* Enable AES hardware */ - //periph_module_enable(PERIPH_AES_DMA_MODULE); - /* Enable AES hardware */ - REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_CRYPTO_AES_CLK_EN | SYSTEM_DMA_CLK_EN); - /* Clear reset on digital signature unit, - otherwise AES unit is held in reset also. */ - REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, - SYSTEM_CRYPTO_AES_RST | SYSTEM_DMA_RST | SYSTEM_CRYPTO_DS_RST); + /* Enable AES and DMA hardware */ +#if SOC_AES_CRYPTO_DMA + periph_module_enable(PERIPH_AES_DMA_MODULE); +#elif SOC_AES_GENERAL_DMA + periph_module_enable(PERIPH_AES_MODULE); + periph_module_enable(PERIPH_GDMA_MODULE); +#endif } /* Function to disable AES and Crypto DMA clocks and release locks */ void esp_aes_release_hardware( void ) { - /* Disable AES hardware */ - //periph_module_disable(PERIPH_AES_DMA_MODULE); - /* Disable AES hardware */ - REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_CRYPTO_AES_RST | SYSTEM_DMA_RST); - /* Don't return other units to reset, as this pulls - reset on RSA & SHA units, respectively. */ - REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_CRYPTO_AES_CLK_EN | SYSTEM_DMA_CLK_EN); + /* Disable AES and DMA hardware */ +#if SOC_AES_CRYPTO_DMA + periph_module_disable(PERIPH_AES_DMA_MODULE); +#elif SOC_AES_GENERAL_DMA + periph_module_disable(PERIPH_AES_MODULE); + periph_module_disable(PERIPH_GDMA_MODULE); +#endif - _lock_release(&s_aes_lock); -} - - -/* Function to init AES context to zero */ -void esp_aes_init( esp_aes_context *ctx ) -{ - if ( ctx == NULL ) { - return; - } - - bzero( ctx, sizeof( esp_aes_context ) ); -} - -/* Function to clear AES context */ -void esp_aes_free( esp_aes_context *ctx ) -{ - if ( ctx == NULL ) { - return; - } - - bzero( ctx, sizeof( esp_aes_context ) ); -} - -/* - * AES key schedule (same for encryption or decryption, as hardware handles schedule) - * - */ -int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, - unsigned int keybits ) -{ - if (keybits == 192) { - return MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE; - } - if (keybits != 128 && keybits != 256) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - ctx->key_bytes = keybits / 8; - memcpy(ctx->key, key, ctx->key_bytes); - ctx->key_in_hardware = 0; - return 0; -} - -/* - * Helper function to copy key from esp_aes_context buffer - * to hardware key registers. - * - * Call only while holding esp_aes_acquire_hardware(). - */ -static void esp_aes_setkey_hardware( esp_aes_context *ctx, int crypt_mode) -{ - const uint32_t MODE_DECRYPT_BIT = 4; - unsigned mode_reg_base = (crypt_mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; - - ctx->key_in_hardware = 0; - - for (int i = 0; i < ctx->key_bytes / 4; ++i) { - REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i)); - ctx->key_in_hardware += 4; - } - - REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2)); - - /* Fault injection check: all words of key data should have been written to hardware */ - if (ctx->key_in_hardware < 16 - || ctx->key_in_hardware != ctx->key_bytes) { - abort(); - } -} - -/* - * Sets the AES DMA block mode (ECB, CBC, CFB, OFB, GCM, CTR) - * and intializes the required registers for that working mode - */ -static inline void esp_aes_mode_init(esp_aes_mode_t mode) -{ - /* Set the algorithm mode CBC, CFB ... */ - REG_WRITE(AES_BLOCK_MODE_REG, mode); - - /* Presently hard-coding the INC function to 32 bit */ - if (mode == ESP_AES_BLOCK_MODE_CTR) { - REG_WRITE(AES_INC_SEL_REG, 0); - } -} - -/* - * Write IV to hardware iv registers - */ -static inline void esp_aes_set_iv(uint8_t *iv) -{ - uint32_t *iv_words = (uint32_t *)iv; - uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE); - - for (int i = 0; i < IV_WORDS; i++ ) { - REG_WRITE(®_addr_buf[i], iv_words[i]); - } -} - -/* - * Read IV from hardware iv registers - */ -static inline void esp_aes_get_iv(uint8_t *iv) -{ - esp_dport_access_read_buffer((uint32_t *)iv, AES_IV_BASE, IV_WORDS); + AES_RELEASE(); } @@ -236,7 +131,7 @@ static inline void esp_aes_get_iv(uint8_t *iv) static IRAM_ATTR void esp_aes_complete_isr(void *arg) { BaseType_t higher_woken; - REG_WRITE(AES_INT_CLR_REG, 1); + aes_hal_interrupt_clear(); xSemaphoreGiveFromISR(op_complete_sem, &higher_woken); if (higher_woken) { portYIELD_FROM_ISR(); @@ -245,8 +140,8 @@ static IRAM_ATTR void esp_aes_complete_isr(void *arg) static esp_err_t esp_aes_isr_initialise( void ) { - REG_WRITE(AES_INT_CLR_REG, 1); - REG_WRITE(AES_INT_ENA_REG, 1); + aes_hal_interrupt_clear(); + aes_hal_interrupt_enable(true); if (op_complete_sem == NULL) { op_complete_sem = xSemaphoreCreateBinary(); @@ -281,8 +176,6 @@ static esp_err_t esp_aes_isr_initialise( void ) /* Wait for AES hardware block operation to complete */ static void esp_aes_dma_wait_complete(bool use_intr, lldesc_t *output_desc) { - __attribute__((unused)) volatile uint32_t dma_done; - #if defined (CONFIG_MBEDTLS_AES_USE_INTERRUPT) if (use_intr) { if (!xSemaphoreTake(op_complete_sem, 2000 / portTICK_PERIOD_MS)) { @@ -297,76 +190,9 @@ static void esp_aes_dma_wait_complete(bool use_intr, lldesc_t *output_desc) } #endif - /* Checking this if interrupt is used also, to avoid - issues with AES fault injection - */ - while (REG_READ(AES_STATE_REG) != AES_STATE_DONE) { - } - - - /* Wait for DMA write operation to complete */ - while (1) { - dma_done = REG_READ(CRYPTO_DMA_INT_RAW_REG); - // Wait for ownership of buffer to be transferred back to CPU - if ( (output_desc->owner == 0) ) { - break; - } - } + aes_hal_wait_dma_done(output_desc); } -/* Init DMA related registers for AES operation */ -static void esp_aes_dma_init(lldesc_t *input, lldesc_t *output) -{ - /* Enable DMA mode */ - REG_WRITE(AES_DMA_ENABLE_REG, 1); - REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN); - REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_DMA_CLK_EN); - REG_SET_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); - REG_CLR_BIT(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST); - - /* Initialize DMA registers - this is probably mostly one off initialization - - Note: hardcoded to DMA channel 0 - */ - /* Note: burst mode has alignment requirements that we have not checked here */ - GDMA.conf0[0].outdscr_burst_en = 0; - GDMA.conf0[0].indscr_burst_en = 0; - GDMA.conf0[0].out_data_burst_en = 0; - GDMA.conf0[0].in_data_burst_en = 0; - - GDMA.peri_sel[0].peri_out_sel = DMA_PERIPH_AES; - GDMA.peri_sel[0].peri_in_sel = DMA_PERIPH_AES; - - /* Set descriptor addresses: NOTE BACKWARDS AS DMA IN/OUT is reverse of AES in/out */ - GDMA.out_link[0].addr = (uint32_t)input; - GDMA.in_link[0].addr = (uint32_t)output; - - GDMA.sram_size[0].in_size = 3; /* 40 bytes, also minimum size for EDMA */ - GDMA.sram_size[0].out_size = 3; - GDMA.conf1[0].in_ext_mem_bk_size = 0; // 16 bytes - GDMA.conf1[0].out_ext_mem_bk_size = 0; // 16 bytes - - /* - printf("DESC HEAD pointers IN/outlink %p OUT/inlink / %p\n", in_desc_head, out_desc_head); - - printf("before starting in_desc_head owner %d out_desc_head owner %d INT_RAW 0x%08x\n", - in_desc_head->owner, - out_desc_head->owner, - DMA.int_raw.val); - - */ - - //REG_SET_BIT(EXTMEM_CACHE_MMU_OWNER_REG, 1<<23); //mark PSRAM DCache as belonging to DMA - - GDMA.conf0[0].in_rst = 1; - GDMA.conf0[0].in_rst = 0; - GDMA.conf0[0].out_rst = 1; - GDMA.conf0[0].out_rst = 0; - - /* Start transfer */ - GDMA.out_link[0].start = 1; - GDMA.in_link[0].start = 1; -} static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, uint8_t *stream_out); @@ -450,7 +276,7 @@ cleanup: static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, uint8_t *stream_out) { lldesc_t stream_in_desc, stream_out_desc; - lldesc_t *in_desc_head, *out_desc_head; + lldesc_t *in_desc_head = NULL, *out_desc_head = NULL; lldesc_t *block_desc = NULL, *block_in_desc, *block_out_desc; size_t lldesc_num; uint8_t stream_in[16] = {}; @@ -503,7 +329,6 @@ static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, return esp_aes_process_dma_ext_ram(ctx, input, output, len, stream_out, input_needs_realloc, output_needs_realloc); } - /* Set up dma descriptors for input and output */ lldesc_num = lldesc_get_required_num(block_bytes); @@ -540,11 +365,6 @@ static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, in_desc_head = (block_bytes > 0) ? block_in_desc : &stream_in_desc; out_desc_head = (block_bytes > 0) ? block_out_desc : &stream_out_desc; - esp_aes_dma_init(in_desc_head, out_desc_head); - - /* Write the number of blocks */ - REG_WRITE(AES_BLOCK_NUM_REG, blocks); - #if defined (CONFIG_MBEDTLS_AES_USE_INTERRUPT) /* Only use interrupt for long AES operations */ @@ -557,15 +377,12 @@ static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, } else #endif { - REG_WRITE(AES_INT_ENA_REG, 0); + aes_hal_interrupt_enable(false); } - /* Start AES operation */ - REG_WRITE(AES_TRIGGER_REG, 1); + aes_hal_transform_dma_start(in_desc_head, out_desc_head, blocks); esp_aes_dma_wait_complete(use_intr, out_desc_head); - - #if (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) if (block_bytes > 0) { if (esp_ptr_external_ram(output)) { @@ -574,9 +391,7 @@ static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, } #endif - REG_WRITE(AES_DMA_EXIT_REG, 0); - /* Disable DMA mode */ - REG_WRITE(AES_DMA_ENABLE_REG, 0); + aes_hal_transform_dma_finish(); if (stream_bytes > 0) { memcpy(output + block_bytes, stream_out, stream_bytes); @@ -589,6 +404,118 @@ cleanup: } +#if SOC_AES_SUPPORT_GCM + +/* Encrypt/decrypt with AES-GCM the input using DMA */ +int esp_aes_process_dma_gcm(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, lldesc_t *aad_desc, size_t aad_len) +{ + lldesc_t *in_desc_head = NULL, *out_desc_head = NULL, *len_desc = NULL; + lldesc_t stream_in_desc, stream_out_desc; + lldesc_t *block_desc = NULL, *block_in_desc = NULL, *block_out_desc = NULL; + size_t lldesc_num; + uint32_t len_buf[4] = {}; + uint8_t stream_in[16] = {}; + uint8_t stream_out[16] = {}; + unsigned stream_bytes = len % AES_BLOCK_BYTES; // bytes which aren't in a full block + unsigned block_bytes = len - stream_bytes; // bytes which are in a full block + + unsigned blocks = (block_bytes / AES_BLOCK_BYTES) + ((stream_bytes > 0) ? 1 : 0); + + bool use_intr = false; + int ret = 0; + + /* 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) { + bzero(output, len); + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + } + + /* Set up dma descriptors for input and output */ + lldesc_num = lldesc_get_required_num(block_bytes); + + /* Allocate both in and out descriptors to save a malloc/free per function call, add 1 for length descriptor */ + block_desc = heap_caps_calloc( (lldesc_num * 2) + 1, sizeof(lldesc_t), MALLOC_CAP_DMA); + if (block_desc == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory"); + ret = -1; + goto cleanup; + } + + block_in_desc = block_desc; + len_desc = block_desc + lldesc_num; + block_out_desc = block_desc + lldesc_num + 1; + + if (aad_desc != NULL) { + lldesc_append(&in_desc_head, aad_desc); + } + + if (block_bytes > 0) { + lldesc_setup_link(block_in_desc, input, block_bytes, 0); + lldesc_setup_link(block_out_desc, output, block_bytes, 0); + + lldesc_append(&in_desc_head, block_in_desc); + lldesc_append(&out_desc_head, block_out_desc); + } + + /* Any leftover bytes which are appended as an additional DMA list */ + if (stream_bytes > 0) { + memcpy(stream_in, input + block_bytes, stream_bytes); + + lldesc_setup_link(&stream_in_desc, stream_in, AES_BLOCK_BYTES, 0); + lldesc_setup_link(&stream_out_desc, stream_out, AES_BLOCK_BYTES, 0); + + lldesc_append(&in_desc_head, &stream_in_desc); + lldesc_append(&out_desc_head, &stream_out_desc); + } + + + len_buf[1] = __builtin_bswap32(aad_len * 8); + len_buf[3] = __builtin_bswap32(len * 8); + + len_desc->length = sizeof(len_buf); + len_desc->size = sizeof(len_buf); + len_desc->owner = 1; + len_desc->eof = 1; + len_desc->buf = (uint8_t *)len_buf; + + lldesc_append(&in_desc_head, len_desc); + +#if defined (CONFIG_MBEDTLS_AES_USE_INTERRUPT) + /* Only use interrupt for long AES operations */ + if (len > AES_DMA_INTR_TRIG_LEN) { + use_intr = true; + if (esp_aes_isr_initialise() == ESP_FAIL) { + ret = -1; + goto cleanup; + } + } else +#endif + { + aes_hal_interrupt_enable(false); + } + + /* Start AES operation */ + aes_hal_transform_dma_gcm_start(in_desc_head, out_desc_head, blocks); + + esp_aes_dma_wait_complete(use_intr, out_desc_head); + + aes_hal_transform_dma_finish(); + + if (stream_bytes > 0) { + memcpy(output + block_bytes, stream_out, stream_bytes); + } + +cleanup: + free(block_desc); + return ret; +} + +#endif //SOC_AES_SUPPORT_GCM + static int esp_aes_validate_input(esp_aes_context *ctx, const unsigned char *input, unsigned char *output ) { @@ -612,9 +539,9 @@ static int esp_aes_validate_input(esp_aes_context *ctx, const unsigned char *inp /* * AES-ECB single block encryption */ -int esp_internal_aes_encrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) +int esp_internal_aes_encrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) { int r; @@ -628,17 +555,17 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_ECB); + 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; } -void esp_aes_encrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) +void esp_aes_encrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) { esp_internal_aes_encrypt(ctx, input, output); } @@ -646,9 +573,9 @@ void esp_aes_encrypt( esp_aes_context *ctx, /* * AES-ECB single block decryption */ -int esp_internal_aes_decrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) +int esp_internal_aes_decrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) { int r; @@ -662,17 +589,17 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_ECB); + 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; } -void esp_aes_decrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) +void esp_aes_decrypt(esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) { esp_internal_aes_decrypt(ctx, input, output); } @@ -681,10 +608,10 @@ void esp_aes_decrypt( esp_aes_context *ctx, /* * 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 esp_aes_crypt_ecb(esp_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) { int r; @@ -698,8 +625,8 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_ECB); + 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(); @@ -709,12 +636,12 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx, /* * 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 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 = 0; if (esp_aes_validate_input(ctx, input, output)) { @@ -739,9 +666,9 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CBC); - esp_aes_set_iv(iv); + 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) { @@ -749,7 +676,7 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, return r; } - esp_aes_get_iv(iv); + aes_hal_read_iv(iv); esp_aes_release_hardware(); return r; @@ -758,12 +685,12 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx, /* * 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 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]; @@ -792,11 +719,11 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, if (block_bytes > 0) { ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CFB8); - esp_aes_set_iv(iv); + 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); - esp_aes_get_iv(iv); + aes_hal_read_iv(iv); if (r != 0) { esp_aes_release_hardware(); @@ -811,8 +738,8 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, // Process remaining bytes block-at-a-time in ECB mode if (length > 0) { ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, MBEDTLS_AES_ENCRYPT); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_ECB); + 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 ); @@ -844,13 +771,13 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx, /* * 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 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; @@ -898,9 +825,9 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, stream_bytes = length % AES_BLOCK_BYTES; esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CFB128); - esp_aes_set_iv(iv); + 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); r = esp_aes_process_dma(ctx, input, output, length, iv); if (r != 0) { @@ -910,7 +837,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, if (stream_bytes == 0) { // if we didn't need the partial 'stream block' then the new IV is in the IV register - esp_aes_get_iv(iv); + 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 @@ -932,12 +859,12 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx, * 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 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 r = 0; size_t n; @@ -971,9 +898,9 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_OFB); - esp_aes_set_iv(iv); + 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); r = esp_aes_process_dma(ctx, input, output, length, iv); if (r != 0) { @@ -981,7 +908,7 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, return r; } - esp_aes_get_iv(iv); + aes_hal_read_iv(iv); esp_aes_release_hardware(); } @@ -993,13 +920,13 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, /* * 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 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 r = 0; size_t n; @@ -1036,10 +963,10 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, esp_aes_acquire_hardware(); ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); + ctx->key_in_hardware = aes_hal_setkey(ctx->key, ctx->key_bytes, ESP_AES_DECRYPT); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CTR); - esp_aes_set_iv(nonce_counter); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_CTR); + aes_hal_set_iv(nonce_counter); r = esp_aes_process_dma(ctx, input, output, length, stream_block); @@ -1048,7 +975,7 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx, return r; } - esp_aes_get_iv(nonce_counter); + aes_hal_read_iv(nonce_counter); esp_aes_release_hardware(); diff --git a/components/mbedtls/port/aes/esp_aes_common.c b/components/mbedtls/port/aes/esp_aes_common.c new file mode 100644 index 0000000000..c196fa81d6 --- /dev/null +++ b/components/mbedtls/port/aes/esp_aes_common.c @@ -0,0 +1,83 @@ +/** + * \brief AES block cipher, ESP hardware accelerated version, common + * 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 "aes/esp_aes_internal.h" +#include "mbedtls/aes.h" +#include "hal/aes_hal.h" +#include "hal/aes_types.h" +#include "soc/soc_caps.h" + +#include +#include "mbedtls/platform.h" + +bool valid_key_length(const esp_aes_context *ctx) +{ + bool valid_len = (ctx->key_bytes == AES_128_KEY_BYTES) || (ctx->key_bytes == AES_256_KEY_BYTES); + +#if SOC_AES_SUPPORT_AES_192 + valid_len |= ctx->key_bytes == AES_192_KEY_BYTES; +#endif + + return valid_len; +} + + +void esp_aes_init( esp_aes_context *ctx ) +{ + bzero( ctx, sizeof( esp_aes_context ) ); +} + +void esp_aes_free( esp_aes_context *ctx ) +{ + if ( ctx == NULL ) { + return; + } + + bzero( ctx, sizeof( esp_aes_context ) ); +} + +/* + * AES key schedule (same for encryption or decryption, as hardware handles schedule) + * + */ +int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ +#if !SOC_AES_SUPPORT_AES_192 + if (keybits == 192) { + return MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED; + } +#endif + if (keybits != 128 && keybits != 192 && keybits != 256) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + ctx->key_bytes = keybits / 8; + memcpy(ctx->key, key, ctx->key_bytes); + ctx->key_in_hardware = 0; + return 0; +} diff --git a/components/mbedtls/port/aes/esp_aes_gcm.c b/components/mbedtls/port/aes/esp_aes_gcm.c new file mode 100644 index 0000000000..b8cb59f229 --- /dev/null +++ b/components/mbedtls/port/aes/esp_aes_gcm.c @@ -0,0 +1,695 @@ +/** + * \brief GCM 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 "soc/soc_caps.h" + +#if SOC_AES_SUPPORT_GCM + +#include "aes/esp_aes.h" +#include "aes/esp_aes_gcm.h" +#include "aes/esp_aes_internal.h" +#include "hal/aes_hal.h" + +#include "esp_log.h" +#include "mbedtls/aes.h" +#include "esp_heap_caps.h" +#include "soc/soc_memory_layout.h" + +#include + +#define ESP_PUT_BE64(a, val) \ + do { \ + *(uint64_t*)(a) = __builtin_bswap64( (uint64_t)(val) ); \ + } while (0) + +/* For simplicity limit the maxium amount of aad bytes to a single DMA descriptor + This should cover all normal, e.g. mbedtls, use cases */ +#define ESP_AES_GCM_AAD_MAX_BYTES 4080 + +static const char *TAG = "esp-aes-gcm"; + +static void esp_gcm_ghash(esp_gcm_context *ctx, const unsigned char *x, size_t x_len, uint8_t *z); + +/* + * Calculates the Initial Counter Block, J0 + * and copies to to the esp_gcm_context + */ +static void esp_gcm_derive_J0(esp_gcm_context *ctx) +{ + uint8_t len_buf[16]; + + memset(ctx->J0, 0, AES_BLOCK_BYTES); + memset(len_buf, 0, AES_BLOCK_BYTES); + + /* If IV is 96 bits J0 = ( IV || 0^31 || 1 ) */ + if (ctx->iv_len == 12) { + memcpy(ctx->J0, ctx->iv, ctx->iv_len); + ctx->J0[AES_BLOCK_BYTES - 1] |= 1; + } else { + /* For IV != 96 bit, J0 = GHASH(IV || 0[s+64] || [len(IV)]64) */ + /* First calculate GHASH on IV */ + esp_gcm_ghash(ctx, ctx->iv, ctx->iv_len, ctx->J0); + /* Next create 128 bit block which is equal to + 64 bit 0 + iv length truncated to 64 bits */ + ESP_PUT_BE64(len_buf + 8, ctx->iv_len * 8); + /* Calculate GHASH on last block */ + esp_gcm_ghash(ctx, len_buf, 16, ctx->J0); + + + } +} + + +/* + * Increment J0 as per GCM spec, by applying the Standard Incrementing + Function INC_32 to it. + * j is the counter which needs to be incremented which is + * copied to ctx->J0 after incrementing + */ +static void increment32_j0(esp_gcm_context *ctx, uint8_t *j) +{ + uint8_t j_len = AES_BLOCK_BYTES; + memcpy(j, ctx->J0, AES_BLOCK_BYTES); + if (j) { + for (uint32_t i = j_len; i > (j_len - 4); i--) { + if (++j[i - 1] != 0) { + break; + } + } + memcpy(ctx->J0, j, AES_BLOCK_BYTES); + } +} + +/* Function to xor two data blocks */ +static void xor_data(uint8_t *d, const uint8_t *s) +{ + uint32_t *dst = (uint32_t *) d; + uint32_t *src = (uint32_t *) s; + *dst++ ^= *src++; + *dst++ ^= *src++; + *dst++ ^= *src++; + *dst++ ^= *src++; +} + + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* Based on MbedTLS's implemenation + * + * Precompute small multiples of H, that is set + * HH[i] || HL[i] = H times i, + * where i is seen as a field element as in [MGV], ie high-order bits + * correspond to low powers of P. The result is stored in the same way, that + * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL + * corresponds to P^127. + */ +static int gcm_gen_table( esp_gcm_context *ctx ) +{ + int i, j; + uint64_t hi, lo; + uint64_t vl, vh; + unsigned char *h; + + h = ctx->H; + + /* pack h as two 64-bits ints, big-endian */ + GET_UINT32_BE( hi, h, 0 ); + GET_UINT32_BE( lo, h, 4 ); + vh = (uint64_t) hi << 32 | lo; + + GET_UINT32_BE( hi, h, 8 ); + GET_UINT32_BE( lo, h, 12 ); + vl = (uint64_t) hi << 32 | lo; + + /* 8 = 1000 corresponds to 1 in GF(2^128) */ + ctx->HL[8] = vl; + ctx->HH[8] = vh; + + /* 0 corresponds to 0 in GF(2^128) */ + ctx->HH[0] = 0; + ctx->HL[0] = 0; + + for ( i = 4; i > 0; i >>= 1 ) { + uint32_t T = ( vl & 1 ) * 0xe1000000U; + vl = ( vh << 63 ) | ( vl >> 1 ); + vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); + + ctx->HL[i] = vl; + ctx->HH[i] = vh; + } + + for ( i = 2; i <= 8; i *= 2 ) { + uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; + vh = *HiH; + vl = *HiL; + for ( j = 1; j < i; j++ ) { + HiH[j] = vh ^ ctx->HH[j]; + HiL[j] = vl ^ ctx->HL[j]; + } + } + + return ( 0 ); +} +/* + * Shoup's method for multiplication use this table with + * last4[x] = x times P^128 + * where x and last4[x] are seen as elements of GF(2^128) as in [MGV] + */ +static const uint64_t last4[16] = { + 0x0000, 0x1c20, 0x3840, 0x2460, + 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, + 0x9180, 0x8da0, 0xa9c0, 0xb5e0 +}; +/* Based on MbedTLS's implemenation + * + * Sets output to x times H using the precomputed tables. + * x and output are seen as elements of GF(2^128) as in [MGV]. + */ +static void gcm_mult( esp_gcm_context *ctx, const unsigned char x[16], + unsigned char output[16] ) +{ + int i = 0; + unsigned char lo, hi, rem; + uint64_t zh, zl; + + lo = x[15] & 0xf; + + zh = ctx->HH[lo]; + zl = ctx->HL[lo]; + + for ( i = 15; i >= 0; i-- ) { + lo = x[i] & 0xf; + hi = x[i] >> 4; + + if ( i != 15 ) { + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[lo]; + zl ^= ctx->HL[lo]; + + } + + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[hi]; + zl ^= ctx->HL[hi]; + } + + PUT_UINT32_BE( zh >> 32, output, 0 ); + PUT_UINT32_BE( zh, output, 4 ); + PUT_UINT32_BE( zl >> 32, output, 8 ); + PUT_UINT32_BE( zl, output, 12 ); +} + + + +/* Update the key value in gcm context */ +int esp_aes_gcm_setkey( esp_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + if (keybits != 128 && keybits != 192 && keybits != 256) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + + + ctx->aes_ctx.key_bytes = keybits / 8; + + memcpy(ctx->aes_ctx.key, key, ctx->aes_ctx.key_bytes); + + return ( 0 ); +} + + +/* AES-GCM GHASH calculation z = GHASH(x) using h0 hash key +*/ +static void esp_gcm_ghash(esp_gcm_context *ctx, const unsigned char *x, size_t x_len, uint8_t *z) +{ + + uint8_t tmp[AES_BLOCK_BYTES]; + + memset(tmp, 0, AES_BLOCK_BYTES); + /* GHASH(X) is calculated on input string which is multiple of 128 bits + * If input string bit length is not multiple of 128 bits it needs to + * be padded by 0 + * + * Steps: + * 1. Let X1, X2, ... , Xm-1, Xm denote the unique sequence of blocks such + * that X = X1 || X2 || ... || Xm-1 || Xm. + * 2. Let Y0 be the “zero block,” 0128. + * 3. Fori=1,...,m,letYi =(Yi-1 ^ Xi)•H. + * 4. Return Ym + */ + + /* If input bit string is >= 128 bits, process full 128 bit blocks */ + while (x_len >= AES_BLOCK_BYTES) { + + xor_data(z, x); + gcm_mult(ctx, z, z); + + x += AES_BLOCK_BYTES; + x_len -= AES_BLOCK_BYTES; + } + + /* If input bit string is not multiple of 128 create last 128 bit + * block by padding necessary 0s + */ + if (x_len) { + memcpy(tmp, x, x_len); + xor_data(z, tmp); + gcm_mult(ctx, z, z); + } +} + + +/* Function to init AES GCM context to zero */ +void esp_aes_gcm_init( esp_gcm_context *ctx) +{ + if (ctx == NULL) { + return; + } + + bzero(ctx, sizeof(esp_gcm_context)); + + ctx->gcm_state = ESP_AES_GCM_STATE_INIT; +} + +/* Function to clear AES-GCM context */ +void esp_aes_gcm_free( esp_gcm_context *ctx) +{ + if (ctx == NULL) { + return; + } + bzero(ctx, sizeof(esp_gcm_context)); +} + +/* Setup AES-GCM */ +int esp_aes_gcm_starts( esp_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *aad, + size_t aad_len ) +{ + /* IV and AD are limited to 2^32 bits, so 2^29 bytes */ + /* IV is not allowed to be zero length */ + if ( iv_len == 0 || + ( (uint32_t) iv_len ) >> 29 != 0 || + ( (uint32_t) aad_len ) >> 29 != 0 ) { + return ( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + if (!ctx) { + ESP_LOGE(TAG, "No AES context supplied"); + return -1; + } + + if (!iv) { + ESP_LOGE(TAG, "No IV supplied"); + return -1; + } + + if ( (aad_len > 0) && !aad) { + ESP_LOGE(TAG, "No aad supplied"); + return -1; + } + + /* Initialize AES-GCM context */ + memset(ctx->ghash, 0, sizeof(ctx->ghash)); + ctx->data_len = 0; + + ctx->iv = iv; + ctx->iv_len = iv_len; + ctx->aad = aad; + ctx->aad_len = aad_len; + ctx->mode = mode; + + /* H and the lookup table are only generated once per ctx */ + if (ctx->gcm_state == ESP_AES_GCM_STATE_INIT) { + /* Lock the AES engine to calculate ghash key H in hardware */ + esp_aes_acquire_hardware(); + ctx->aes_ctx.key_in_hardware = aes_hal_setkey(ctx->aes_ctx.key, ctx->aes_ctx.key_bytes, mode); + aes_hal_mode_init(ESP_AES_BLOCK_MODE_GCM); + + aes_hal_gcm_calc_hash(ctx->H); + + esp_aes_release_hardware(); + + gcm_gen_table(ctx); + } + + ctx->gcm_state = ESP_AES_GCM_STATE_START; + + /* Once H is obtained we need to derive J0 (Initial Counter Block) */ + esp_gcm_derive_J0(ctx); + + /* The initial counter block keeps updating during the esp_gcm_update call + * however to calculate final authentication tag T we need original J0 + * so we make a copy here + */ + memcpy(ctx->ori_j0, ctx->J0, 16); + + esp_gcm_ghash(ctx, ctx->aad, ctx->aad_len, ctx->ghash); + + return ( 0 ); +} + +/* Perform AES-GCM operation */ +int esp_aes_gcm_update( esp_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ) +{ + size_t nc_off = 0; + uint8_t nonce_counter[AES_BLOCK_BYTES] = {0}; + uint8_t stream[AES_BLOCK_BYTES] = {0}; + + if (!ctx) { + ESP_LOGE(TAG, "No GCM context supplied"); + return -1; + } + if (!input) { + ESP_LOGE(TAG, "No input supplied"); + return -1; + } + if (!output) { + ESP_LOGE(TAG, "No output supplied"); + return -1; + } + + if ( output > input && (size_t) ( output - input ) < length ) { + return ( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + /* If this is the first time esp_gcm_update is getting called + * calculate GHASH on aad and preincrement the ICB + */ + if (ctx->gcm_state == ESP_AES_GCM_STATE_START) { + /* Jo needs to be incremented first time, later the CTR + * operation will auto update it + */ + increment32_j0(ctx, nonce_counter); + ctx->gcm_state = ESP_AES_GCM_STATE_UPDATE; + } else if (ctx->gcm_state == ESP_AES_GCM_STATE_UPDATE) { + memcpy(nonce_counter, ctx->J0, AES_BLOCK_BYTES); + } + + /* Perform intermediate GHASH on "encrypted" data during decryption */ + if (ctx->mode == ESP_AES_DECRYPT) { + esp_gcm_ghash(ctx, input, length, ctx->ghash); + } + + /* Output = GCTR(J0, Input): Encrypt/Decrypt the input */ + esp_aes_crypt_ctr(&ctx->aes_ctx, length, &nc_off, nonce_counter, stream, input, output); + + /* ICB gets auto incremented after GCTR operation here so update the context */ + memcpy(ctx->J0, nonce_counter, AES_BLOCK_BYTES); + + /* Keep updating the length counter for final tag calculation */ + ctx->data_len += length; + + /* Perform intermediate GHASH on "encrypted" data during encryption*/ + if (ctx->mode == ESP_AES_ENCRYPT) { + esp_gcm_ghash(ctx, output, length, ctx->ghash); + } + + return 0; +} + +/* Function to read the tag value */ +int esp_aes_gcm_finish( esp_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ) +{ + size_t nc_off = 0; + uint8_t len_block[AES_BLOCK_BYTES] = {0}; + + if ( tag_len > 16 || tag_len < 4 ) { + return ( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + /* Calculate final GHASH on aad_len, data length */ + ESP_PUT_BE64(len_block, ctx->aad_len * 8); + ESP_PUT_BE64(len_block + 8, ctx->data_len * 8); + esp_gcm_ghash(ctx, len_block, AES_BLOCK_BYTES, ctx->ghash); + + /* Tag T = GCTR(J0, ) where T is truncated to tag_len */ + esp_aes_crypt_ctr(&ctx->aes_ctx, tag_len, &nc_off, ctx->ori_j0, 0, ctx->ghash, tag); + + return 0; +} + +/* Due to restrictions in the hardware (e.g. need to do the whole conversion in one go), + some combinations of inputs are not supported */ +static bool esp_aes_gcm_input_support_hw_accel(size_t length, const unsigned char *aad, size_t aad_len, + const unsigned char *input, unsigned char *output) +{ + bool support_hw_accel = true; + + if (aad_len > ESP_AES_GCM_AAD_MAX_BYTES) { + support_hw_accel = false; + } else if (!esp_ptr_dma_capable(aad) && aad_len > 0) { + /* aad in non internal DMA memory */ + support_hw_accel = false; + } else if (!esp_ptr_dma_capable(input) && length > 0) { + /* input in non internal DMA memory */ + support_hw_accel = false; + } else if (!esp_ptr_dma_capable(output) && length > 0) { + /* output in non internal DMA memory */ + support_hw_accel = false; + } else if (length == 0) { + support_hw_accel = false; + } + + return support_hw_accel; +} + +static int esp_aes_gcm_crypt_and_tag_partial_hw( esp_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + int ret = 0; + + if ( ( ret = esp_aes_gcm_starts( ctx, mode, iv, iv_len, aad, aad_len ) ) != 0 ) { + return ( ret ); + } + + if ( ( ret = esp_aes_gcm_update( ctx, length, input, output ) ) != 0 ) { + return ( ret ); + } + + if ( ( ret = esp_aes_gcm_finish( ctx, tag, tag_len ) ) != 0 ) { + return ( ret ); + } + + return ret; +} + +int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + int ret; + lldesc_t aad_desc[2] = {}; + lldesc_t *aad_head_desc = NULL; + size_t remainder_bit; + uint8_t stream_in[AES_BLOCK_BYTES] = {}; + unsigned stream_bytes = aad_len % AES_BLOCK_BYTES; // bytes which aren't in a full block + unsigned block_bytes = aad_len - stream_bytes; // bytes which are in a full block + + /* Due to hardware limition only certain cases are fully supported in HW */ + if (!esp_aes_gcm_input_support_hw_accel(length, aad, aad_len, input, output)) { + return esp_aes_gcm_crypt_and_tag_partial_hw(ctx, mode, length, iv, iv_len, aad, aad_len, input, output, tag_len, tag); + } + + /* Limit aad len to a single DMA descriptor to simplify DMA handling + In practice, e.g. with mbedtls the length of aad will always be short + */ + if (aad_len > LLDESC_MAX_NUM_PER_DESC) { + return -1; + } + /* IV and AD are limited to 2^32 bits, so 2^29 bytes */ + /* IV is not allowed to be zero length */ + if ( iv_len == 0 || + ( (uint32_t) iv_len ) >> 29 != 0 || + ( (uint32_t) aad_len ) >> 29 != 0 ) { + return ( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + if (!ctx) { + ESP_LOGE(TAG, "No AES context supplied"); + return -1; + } + + if (!iv) { + ESP_LOGE(TAG, "No IV supplied"); + return -1; + } + + if ( (aad_len > 0) && !aad) { + ESP_LOGE(TAG, "No aad supplied"); + return -1; + } + + /* Initialize AES-GCM context */ + memset(ctx->ghash, 0, sizeof(ctx->ghash)); + ctx->data_len = 0; + + ctx->iv = iv; + ctx->iv_len = iv_len; + ctx->aad = aad; + ctx->aad_len = aad_len; + ctx->mode = mode; + + esp_aes_acquire_hardware(); + ctx->aes_ctx.key_in_hardware = 0; + ctx->aes_ctx.key_in_hardware = aes_hal_setkey(ctx->aes_ctx.key, ctx->aes_ctx.key_bytes, mode); + + if (block_bytes > 0) { + aad_desc[0].length = block_bytes; + aad_desc[0].size = block_bytes; + aad_desc[0].owner = 1; + aad_desc[0].buf = aad; + } + + if (stream_bytes > 0) { + memcpy(stream_in, aad + block_bytes, stream_bytes); + + aad_desc[0].empty = (uint32_t)&aad_desc[1]; + aad_desc[1].length = AES_BLOCK_BYTES; + aad_desc[1].size = AES_BLOCK_BYTES; + aad_desc[1].owner = 1; + aad_desc[1].buf = stream_in; + } + + if (block_bytes > 0) { + aad_head_desc = &aad_desc[0]; + } else if (stream_bytes > 0) { + aad_head_desc = &aad_desc[1]; + } + + aes_hal_mode_init(ESP_AES_BLOCK_MODE_GCM); + + /* See TRM GCM chapter for description of this calculation */ + remainder_bit = (8 * length) % 128; + aes_hal_gcm_init( (aad_len + AES_BLOCK_BYTES - 1) / AES_BLOCK_BYTES, remainder_bit); + aes_hal_gcm_calc_hash(ctx->H); + + gcm_gen_table(ctx); + esp_gcm_derive_J0(ctx); + + aes_hal_gcm_set_j0(ctx->J0); + + ret = esp_aes_process_dma_gcm(&ctx->aes_ctx, input, output, length, aad_head_desc, aad_len); + + aes_hal_gcm_read_tag(tag, tag_len); + + esp_aes_release_hardware(); + + return ( ret ); +} + + +int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *aad, + size_t aad_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + + if ( ( ret = esp_aes_gcm_crypt_and_tag( ctx, ESP_AES_DECRYPT, length, + iv, iv_len, aad, aad_len, + input, output, tag_len, check_tag ) ) != 0 ) { + return ( ret ); + } + + /* Check tag in "constant-time" */ + for ( diff = 0, i = 0; i < tag_len; i++ ) { + diff |= tag[i] ^ check_tag[i]; + } + + if ( diff != 0 ) { + bzero( output, length ); + return ( MBEDTLS_ERR_GCM_AUTH_FAILED ); + } + + return ( 0 ); +} + +#endif //SOC_AES_SUPPORT_GCM diff --git a/components/mbedtls/port/esp_aes_xts.c b/components/mbedtls/port/aes/esp_aes_xts.c similarity index 97% rename from components/mbedtls/port/esp_aes_xts.c rename to components/mbedtls/port/aes/esp_aes_xts.c index c2f5226421..d91f17e4ee 100644 --- a/components/mbedtls/port/esp_aes_xts.c +++ b/components/mbedtls/port/aes/esp_aes_xts.c @@ -38,19 +38,7 @@ #include #include "mbedtls/aes.h" -#if CONFIG_IDF_TARGET_ESP32 -#include "esp32/aes.h" -#endif - -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/aes.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/aes.h" -#endif - -#if CONFIG_IDF_TARGET_ESP32S3 -#include "esp32s3/aes.h" -#endif +#include "aes/esp_aes.h" void esp_aes_xts_init( esp_aes_xts_context *ctx ) { diff --git a/components/mbedtls/port/esp32s2/aes.c b/components/mbedtls/port/esp32s2/aes.c deleted file mode 100644 index 6ac113c88e..0000000000 --- a/components/mbedtls/port/esp32s2/aes.c +++ /dev/null @@ -1,1524 +0,0 @@ -/** - * \brief AES block cipher, ESP32-S2 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 -#include -#include "mbedtls/aes.h" -#include "esp32s2/aes.h" -#include "esp32s2/gcm.h" -#include "soc/cpu.h" -#include "soc/dport_reg.h" -#include "soc/hwcrypto_reg.h" -#include "soc/crypto_dma_reg.h" -#include "soc/periph_defs.h" -#include "esp32s2/rom/lldesc.h" -#include "esp32s2/rom/cache.h" -#include "esp_intr_alloc.h" -#include "driver/periph_ctrl.h" -#include "esp_log.h" -#include "soc/lldesc.h" -#include "esp_heap_caps.h" -#include "sys/param.h" -#include "esp_pm.h" -#include "esp_crypto_lock.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" - -#define AES_BLOCK_BYTES 16 -#define IV_WORDS 4 - -/* Max size of each chunk to process when output buffer is in unaligned external ram - must be a multiple of block size -*/ -#define AES_MAX_CHUNK_WRITE_SIZE 1600 - -/* Input over this length will yield and wait for interrupt instead of - busy-waiting, 30000 bytes is approx 0.5 ms */ -#define AES_DMA_INTR_TRIG_LEN 2000 - -#define ESP_PUT_BE64(a, val) \ - do { \ - *(uint64_t*)(a) = __builtin_bswap64( (uint64_t)(val) ); \ - } while (0) - - -/* DMA AES working modes*/ -typedef enum { - ESP_AES_BLOCK_MODE_ECB = 0, - ESP_AES_BLOCK_MODE_CBC, - ESP_AES_BLOCK_MODE_OFB, - ESP_AES_BLOCK_MODE_CTR, - ESP_AES_BLOCK_MODE_CFB8, - ESP_AES_BLOCK_MODE_CFB128, - ESP_AES_BLOCK_MODE_GCM, -} esp_aes_mode_t; - - -#if defined(CONFIG_MBEDTLS_AES_USE_INTERRUPT) -static SemaphoreHandle_t op_complete_sem; -#if defined(CONFIG_PM_ENABLE) -static esp_pm_lock_handle_t s_pm_cpu_lock; -static esp_pm_lock_handle_t s_pm_sleep_lock; -#endif -#endif - -static const char *TAG = "esp-aes"; - -static inline bool valid_key_length(const esp_aes_context *ctx) -{ - return ctx->key_bytes == 128 / 8 || ctx->key_bytes == 192 / 8 || ctx->key_bytes == 256 / 8; -} - - -void esp_aes_acquire_hardware( void ) -{ - /* Need to lock DMA since it is shared with SHA block */ - esp_crypto_dma_lock_acquire(); - - /* Enable AES hardware */ - periph_module_enable(PERIPH_AES_DMA_MODULE); -} - -/* Function to disable AES and Crypto DMA clocks and release locks */ -void esp_aes_release_hardware( void ) -{ - /* Disable AES hardware */ - periph_module_disable(PERIPH_AES_DMA_MODULE); - - esp_crypto_dma_lock_release(); -} - - -/* Function to init AES context to zero */ -void esp_aes_init( esp_aes_context *ctx ) -{ - if ( ctx == NULL ) { - return; - } - - bzero( ctx, sizeof( esp_aes_context ) ); -} - -/* Function to clear AES context */ -void esp_aes_free( esp_aes_context *ctx ) -{ - if ( ctx == NULL ) { - return; - } - - bzero( ctx, sizeof( esp_aes_context ) ); -} - -/* - * AES key schedule (same for encryption or decryption, as hardware handles schedule) - * - */ -int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, - unsigned int keybits ) -{ - if (keybits != 128 && keybits != 192 && keybits != 256) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - ctx->key_bytes = keybits / 8; - memcpy(ctx->key, key, ctx->key_bytes); - ctx->key_in_hardware = 0; - return 0; -} - -/* - * Helper function to copy key from esp_aes_context buffer - * to hardware key registers. - * - * Call only while holding esp_aes_acquire_hardware(). - */ -static void esp_aes_setkey_hardware( esp_aes_context *ctx, int crypt_mode) -{ - const uint32_t MODE_DECRYPT_BIT = 4; - unsigned mode_reg_base = (crypt_mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; - - ctx->key_in_hardware = 0; - - for (int i = 0; i < ctx->key_bytes / 4; ++i) { - REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i)); - ctx->key_in_hardware += 4; - } - - REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2)); - - /* Fault injection check: all words of key data should have been written to hardware */ - if (ctx->key_in_hardware < 16 - || ctx->key_in_hardware != ctx->key_bytes) { - abort(); - } -} - -/* - * Sets the AES DMA block mode (ECB, CBC, CFB, OFB, GCM, CTR) - * and intializes the required registers for that working mode - */ -static inline void esp_aes_mode_init(esp_aes_mode_t mode) -{ - /* Set the algorithm mode CBC, CFB ... */ - REG_WRITE(AES_BLOCK_MODE_REG, mode); - - /* Presently hard-coding the INC function to 32 bit */ - if (mode == ESP_AES_BLOCK_MODE_CTR) { - REG_WRITE(AES_INC_SEL_REG, 0); - } -} - -/* - * Write IV to hardware iv registers - */ -static inline void esp_aes_set_iv(uint8_t *iv) -{ - uint32_t *iv_words = (uint32_t*)iv; - uint32_t *reg_addr_buf = (uint32_t *)(AES_IV_BASE); - - for (int i = 0; iowner == 0) ) { - break; - } - } -} - -/* Init DMA related registers for AES operation */ -static void esp_aes_dma_init(lldesc_t *input, lldesc_t *output) -{ - /* Enable DMA mode */ - REG_WRITE(AES_DMA_ENABLE_REG, 1); - - /* Reset DMA */ - SET_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_IN_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); - CLEAR_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_IN_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST); - - /* Set DMA for AES Use */ - REG_WRITE(CRYPTO_DMA_AES_SHA_SELECT_REG, 0); - - /* Set descriptors */ - CLEAR_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_ADDR); - SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, ((uint32_t)(input))&OUT_LINK_REG_OUTLINK_ADDR); - CLEAR_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, IN_LINK_REG_INLINK_ADDR); - SET_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, ((uint32_t)(output))&IN_LINK_REG_INLINK_ADDR); - - /* Start transfer */ - SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_START); - SET_PERI_REG_MASK(CRYPTO_DMA_IN_LINK_REG, IN_LINK_REG_INLINK_START); -} - -static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, uint8_t *stream_out); - - -/* Output buffers in external ram needs to be 16-byte aligned and DMA cant access input in the iCache mem range, - reallocate them into internal memory and encrypt in chunks to avoid - having to malloc too big of a buffer -*/ - -static int esp_aes_process_dma_ext_ram(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, uint8_t *stream_out, bool realloc_input, bool realloc_output) -{ - size_t chunk_len; - int ret = 0; - int offset = 0; - unsigned char *input_buf = NULL; - unsigned char *output_buf = NULL; - const unsigned char *dma_input; - chunk_len = MIN(AES_MAX_CHUNK_WRITE_SIZE, len); - - if (realloc_input) { - input_buf = heap_caps_malloc(chunk_len, MALLOC_CAP_DMA); - - if (input_buf == NULL) { - ESP_LOGE(TAG, "Failed to allocate memory"); - ret = -1; - goto cleanup; - } - } - - if (realloc_output) { - output_buf = heap_caps_malloc(chunk_len, MALLOC_CAP_DMA); - - if (output_buf == NULL) { - ESP_LOGE(TAG, "Failed to allocate memory"); - ret = -1; - goto cleanup; - } - } else { - output_buf = output; - } - - while (len) { - chunk_len = MIN(AES_MAX_CHUNK_WRITE_SIZE, len); - - /* If input needs realloc then copy it, else use the input with offset*/ - if (realloc_input) { - memcpy(input_buf, input + offset, chunk_len); - dma_input = input_buf; - } else { - dma_input = input + offset; - } - - if (esp_aes_process_dma(ctx, dma_input, output_buf, chunk_len, stream_out) != 0) { - ret = -1; - goto cleanup; - } - - if (realloc_output) { - memcpy(output + offset, output_buf, chunk_len); - } else { - output_buf = output + offset + chunk_len; - } - - len -= chunk_len; - offset += chunk_len; - } - -cleanup: - - if (realloc_input) { - free(input_buf); - } - if (realloc_output) { - free(output_buf); - } - - return ret; -} - -/* Encrypt/decrypt the input using DMA */ -static int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, uint8_t *stream_out) -{ - lldesc_t stream_in_desc, stream_out_desc; - lldesc_t *in_desc_head, *out_desc_head; - lldesc_t *block_desc = NULL, *block_in_desc, *block_out_desc; - size_t lldesc_num; - uint8_t stream_in[16] = {}; - unsigned stream_bytes = len % AES_BLOCK_BYTES; // bytes which aren't in a full block - unsigned block_bytes = len - stream_bytes; // bytes which are in a full block - unsigned char *non_icache_input = NULL; - unsigned blocks = (block_bytes / AES_BLOCK_BYTES) + ((stream_bytes > 0) ? 1 : 0); - bool use_intr = false; - bool input_needs_realloc = false; - bool output_needs_realloc = false; - int ret = 0; - - assert(len > 0); // caller shouldn't ever have len set to zero - assert(stream_bytes == 0 || stream_out != NULL); // stream_out can be NULL if we're processing full block(s) - - /* 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) { - bzero(output, len); - return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; - } - - if (block_bytes > 0) { - /* Flush cache if input in external ram */ -#if (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - if (esp_ptr_external_ram(input)) { - Cache_WriteBack_All(); - } - if (esp_ptr_external_ram(output)) { - if (((intptr_t)(output) & 0xF) != 0) { - // Non aligned ext-mem buffer - output_needs_realloc = true; - } - } -#endif - /* DMA cannot access memory in the iCache range, copy input to internal ram */ - if (!esp_ptr_dma_ext_capable(input) && !esp_ptr_dma_capable(input)) { - input_needs_realloc = true; - } - - if (!esp_ptr_dma_ext_capable(output) && !esp_ptr_dma_capable(output)) { - output_needs_realloc = true; - } - - /* If either input or output is unaccessible to the DMA then they need to be reallocated */ - if (input_needs_realloc || output_needs_realloc) { - return esp_aes_process_dma_ext_ram(ctx, input, output, len, stream_out, input_needs_realloc, output_needs_realloc); - } - - - /* Set up dma descriptors for input and output */ - lldesc_num = lldesc_get_required_num(block_bytes); - - /* Allocate both in and out descriptors to save a malloc/free per function call */ - block_desc = heap_caps_malloc(sizeof(lldesc_t) * lldesc_num * 2, MALLOC_CAP_DMA); - if (block_desc == NULL) { - ESP_LOGE(TAG, "Failed to allocate memory"); - ret = -1; - goto cleanup; - } - - block_in_desc = block_desc; - block_out_desc = block_desc + lldesc_num; - - lldesc_setup_link(block_desc, input, block_bytes, 0); - lldesc_setup_link(block_desc + lldesc_num, output, block_bytes, 0); - } - - /* Any leftover bytes which are appended as an additional DMA list */ - if (stream_bytes > 0) { - memcpy(stream_in, input + block_bytes, stream_bytes); - - lldesc_setup_link(&stream_in_desc, stream_in, AES_BLOCK_BYTES, 0); - lldesc_setup_link(&stream_out_desc, stream_out, AES_BLOCK_BYTES, 0); - - if (block_bytes > 0) { - /* Link with block descriptors*/ - block_in_desc[lldesc_num - 1].empty = (uint32_t)&stream_in_desc; - block_out_desc[lldesc_num - 1].empty = (uint32_t)&stream_out_desc; - } - } - - // block buffers are sent to DMA first, unless there aren't any - in_desc_head = (block_bytes > 0) ? block_in_desc : &stream_in_desc; - out_desc_head = (block_bytes > 0) ? block_out_desc : &stream_out_desc; - - esp_aes_dma_init(in_desc_head, out_desc_head); - - /* Write the number of blocks */ - REG_WRITE(AES_BLOCK_NUM_REG, blocks); - - -#if defined (CONFIG_MBEDTLS_AES_USE_INTERRUPT) - /* Only use interrupt for long AES operations */ - if (len > AES_DMA_INTR_TRIG_LEN) { - use_intr = true; - if (esp_aes_isr_initialise() == ESP_FAIL) { - ret = -1; - goto cleanup; - } - } else -#endif - { - REG_WRITE(AES_INT_ENA_REG, 0); - } - - /* Start AES operation */ - REG_WRITE(AES_TRIGGER_REG, 1); - esp_aes_dma_wait_complete(use_intr, out_desc_head); - - - -#if (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - if (block_bytes > 0) { - if (esp_ptr_external_ram(output)) { - Cache_Invalidate_DCache_All(); - } - } -#endif - - REG_WRITE(AES_DMA_EXIT_REG, 0); - /* Disable DMA mode */ - REG_WRITE(AES_DMA_ENABLE_REG, 0); - - if (stream_bytes > 0) { - memcpy(output + block_bytes, stream_out, stream_bytes); - } - -cleanup: - free(non_icache_input); - free(block_desc); - return ret; -} - - -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; - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); - esp_aes_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; -} - -void esp_aes_encrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) -{ - esp_internal_aes_encrypt(ctx, 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] ) -{ - int r; - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - esp_aes_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; -} - -void esp_aes_decrypt( esp_aes_context *ctx, - const unsigned char input[16], - unsigned char output[16] ) -{ - esp_internal_aes_decrypt(ctx, 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] ) -{ - int r; - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!valid_key_length(ctx)) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - esp_aes_acquire_hardware(); - ctx->key_in_hardware = 0; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_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 = 0; - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return -1; - } - - /* 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; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CBC); - esp_aes_set_iv(iv); - - r = esp_aes_process_dma(ctx, input, output, length, NULL); - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - esp_aes_get_iv(iv); - 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 ) -{ - unsigned char c; - unsigned char ov[17]; - int r = 0; - size_t block_bytes = length - (length % AES_BLOCK_BYTES); - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return -1; - } - - - 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; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CFB8); - esp_aes_set_iv(iv); - r = esp_aes_process_dma(ctx, input, output, block_bytes, NULL); - esp_aes_get_iv(iv); - - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - 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; - esp_aes_setkey_hardware(ctx, MBEDTLS_AES_ENCRYPT); - esp_aes_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) { - esp_aes_release_hardware(); - return r; - } - - 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 ); - } - - } - 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; - int r = 0; - size_t stream_bytes = 0; - size_t n; - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return -1; - } - - if (!iv_off) { - ESP_LOGE(TAG, "No IV offset supplied"); - return -1; - } - - 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; - esp_aes_setkey_hardware(ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CFB128); - esp_aes_set_iv(iv); - - 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 - esp_aes_get_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 r; -} - -/* - * 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 r = 0; - size_t n; - size_t stream_bytes = 0; - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return -1; - } - - if (!iv_off) { - ESP_LOGE(TAG, "No IV offset supplied"); - return -1; - } - - 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; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_OFB); - esp_aes_set_iv(iv); - - r = esp_aes_process_dma(ctx, input, output, length, iv); - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - esp_aes_get_iv(iv); - esp_aes_release_hardware(); - } - - *iv_off = n + stream_bytes; - - return r; -} - -/* - * 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 r = 0; - size_t n; - - if (esp_aes_validate_input(ctx, input, output)) { - return -1; - } - - if (!nonce_counter) { - ESP_LOGE(TAG, "No nonce supplied"); - return -1; - } - - if (!nc_off) { - ESP_LOGE(TAG, "No nonce offset supplied"); - return -1; - } - - 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; - esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); - - esp_aes_mode_init(ESP_AES_BLOCK_MODE_CTR); - esp_aes_set_iv(nonce_counter); - - r = esp_aes_process_dma(ctx, input, output, length, stream_block); - - if (r != 0) { - esp_aes_release_hardware(); - return r; - } - - esp_aes_get_iv(nonce_counter); - - esp_aes_release_hardware(); - - } - *nc_off = n + (length % AES_BLOCK_BYTES); - - return r; -} - -static void esp_gcm_ghash(esp_gcm_context *ctx, const unsigned char *x, size_t x_len, uint8_t *z); - -/* - * Calculates the Initial Counter Block, J0 - * and copies to to the esp_gcm_context - */ -static void esp_gcm_derive_J0(esp_gcm_context *ctx) -{ - uint8_t len_buf[16]; - - memset(ctx->J0, 0, AES_BLOCK_BYTES); - memset(len_buf, 0, AES_BLOCK_BYTES); - - /* If IV is 96 bits J0 = ( IV || 0^31 || 1 ) */ - if (ctx->iv_len == 12) { - memcpy(ctx->J0, ctx->iv, ctx->iv_len); - ctx->J0[AES_BLOCK_BYTES - 1] |= 1; - } else { - /* For IV != 96 bit, J0 = GHASH(IV || 0[s+64] || [len(IV)]64) */ - /* First calculate GHASH on IV */ - esp_gcm_ghash(ctx, ctx->iv, ctx->iv_len, ctx->J0); - /* Next create 128 bit block which is equal to - 64 bit 0 + iv length truncated to 64 bits */ - ESP_PUT_BE64(len_buf + 8, ctx->iv_len * 8); - /* Calculate GHASH on last block */ - esp_gcm_ghash(ctx, len_buf, 16, ctx->J0); - - - } -} - - -/* - * Increment J0 as per GCM spec, by applying the Standard Incrementing - Function INC_32 to it. - * j is the counter which needs to be incremented which is - * copied to ctx->J0 after incrementing - */ -static void increment32_j0(esp_gcm_context *ctx, uint8_t *j) -{ - uint8_t j_len = AES_BLOCK_BYTES; - memcpy(j, ctx->J0, AES_BLOCK_BYTES); - if (j) { - for (uint32_t i = j_len; i > (j_len - 4); i--) { - if (++j[i - 1] != 0) { - break; - } - } - memcpy(ctx->J0, j, AES_BLOCK_BYTES); - } -} - -/* Function to xor two data blocks */ -static void xor_data(uint8_t *d, const uint8_t *s) -{ - uint32_t *dst = (uint32_t *) d; - uint32_t *src = (uint32_t *) s; - *dst++ ^= *src++; - *dst++ ^= *src++; - *dst++ ^= *src++; - *dst++ ^= *src++; -} - - -/* - * 32-bit integer manipulation macros (big endian) - */ -#ifndef GET_UINT32_BE -#define GET_UINT32_BE(n,b,i) \ -{ \ - (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ - | ( (uint32_t) (b)[(i) + 1] << 16 ) \ - | ( (uint32_t) (b)[(i) + 2] << 8 ) \ - | ( (uint32_t) (b)[(i) + 3] ); \ -} -#endif - -#ifndef PUT_UINT32_BE -#define PUT_UINT32_BE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) ); \ -} -#endif - -/* Based on MbedTLS's implemenation - * - * Precompute small multiples of H, that is set - * HH[i] || HL[i] = H times i, - * where i is seen as a field element as in [MGV], ie high-order bits - * correspond to low powers of P. The result is stored in the same way, that - * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL - * corresponds to P^127. - */ -static int gcm_gen_table( esp_gcm_context *ctx ) -{ - int i, j; - uint64_t hi, lo; - uint64_t vl, vh; - unsigned char *h; - - h = ctx->H; - - /* pack h as two 64-bits ints, big-endian */ - GET_UINT32_BE( hi, h, 0 ); - GET_UINT32_BE( lo, h, 4 ); - vh = (uint64_t) hi << 32 | lo; - - GET_UINT32_BE( hi, h, 8 ); - GET_UINT32_BE( lo, h, 12 ); - vl = (uint64_t) hi << 32 | lo; - - /* 8 = 1000 corresponds to 1 in GF(2^128) */ - ctx->HL[8] = vl; - ctx->HH[8] = vh; - - /* 0 corresponds to 0 in GF(2^128) */ - ctx->HH[0] = 0; - ctx->HL[0] = 0; - - for( i = 4; i > 0; i >>= 1 ) - { - uint32_t T = ( vl & 1 ) * 0xe1000000U; - vl = ( vh << 63 ) | ( vl >> 1 ); - vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); - - ctx->HL[i] = vl; - ctx->HH[i] = vh; - } - - for( i = 2; i <= 8; i *= 2 ) - { - uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; - vh = *HiH; - vl = *HiL; - for( j = 1; j < i; j++ ) - { - HiH[j] = vh ^ ctx->HH[j]; - HiL[j] = vl ^ ctx->HL[j]; - } - } - - return( 0 ); -} -/* - * Shoup's method for multiplication use this table with - * last4[x] = x times P^128 - * where x and last4[x] are seen as elements of GF(2^128) as in [MGV] - */ -static const uint64_t last4[16] = -{ - 0x0000, 0x1c20, 0x3840, 0x2460, - 0x7080, 0x6ca0, 0x48c0, 0x54e0, - 0xe100, 0xfd20, 0xd940, 0xc560, - 0x9180, 0x8da0, 0xa9c0, 0xb5e0 -}; -/* Based on MbedTLS's implemenation - * - * Sets output to x times H using the precomputed tables. - * x and output are seen as elements of GF(2^128) as in [MGV]. - */ -static void gcm_mult( esp_gcm_context *ctx, const unsigned char x[16], - unsigned char output[16] ) -{ - int i = 0; - unsigned char lo, hi, rem; - uint64_t zh, zl; - - lo = x[15] & 0xf; - - zh = ctx->HH[lo]; - zl = ctx->HL[lo]; - - for( i = 15; i >= 0; i-- ) - { - lo = x[i] & 0xf; - hi = x[i] >> 4; - - if( i != 15 ) - { - rem = (unsigned char) zl & 0xf; - zl = ( zh << 60 ) | ( zl >> 4 ); - zh = ( zh >> 4 ); - zh ^= (uint64_t) last4[rem] << 48; - zh ^= ctx->HH[lo]; - zl ^= ctx->HL[lo]; - - } - - rem = (unsigned char) zl & 0xf; - zl = ( zh << 60 ) | ( zl >> 4 ); - zh = ( zh >> 4 ); - zh ^= (uint64_t) last4[rem] << 48; - zh ^= ctx->HH[hi]; - zl ^= ctx->HL[hi]; - } - - PUT_UINT32_BE( zh >> 32, output, 0 ); - PUT_UINT32_BE( zh, output, 4 ); - PUT_UINT32_BE( zl >> 32, output, 8 ); - PUT_UINT32_BE( zl, output, 12 ); -} - - - -/* Update the key value in gcm context */ -int esp_aes_gcm_setkey( esp_gcm_context *ctx, - mbedtls_cipher_id_t cipher, - const unsigned char *key, - unsigned int keybits ) -{ - if (keybits != 128 && keybits != 192 && keybits != 256) { - return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; - } - - ctx->aes_ctx.key_bytes = keybits / 8; - - memcpy(ctx->aes_ctx.key, key, ctx->aes_ctx.key_bytes); - - return ( 0 ); -} - - -/* AES-GCM GHASH calculation z = GHASH(x) using h0 hash key -*/ -static void esp_gcm_ghash(esp_gcm_context *ctx, const unsigned char *x, size_t x_len, uint8_t *z) -{ - - uint8_t tmp[AES_BLOCK_BYTES]; - - memset(tmp, 0, AES_BLOCK_BYTES); - /* GHASH(X) is calculated on input string which is multiple of 128 bits - * If input string bit length is not multiple of 128 bits it needs to - * be padded by 0 - * - * Steps: - * 1. Let X1, X2, ... , Xm-1, Xm denote the unique sequence of blocks such - * that X = X1 || X2 || ... || Xm-1 || Xm. - * 2. Let Y0 be the “zero block,” 0128. - * 3. Fori=1,...,m,letYi =(Yi-1 ^ Xi)•H. - * 4. Return Ym - */ - - /* If input bit string is >= 128 bits, process full 128 bit blocks */ - while (x_len >= AES_BLOCK_BYTES) { - - xor_data(z, x); - gcm_mult(ctx, z, z); - - x += AES_BLOCK_BYTES; - x_len -= AES_BLOCK_BYTES; - } - - /* If input bit string is not multiple of 128 create last 128 bit - * block by padding necessary 0s - */ - if (x_len) { - memcpy(tmp, x, x_len); - xor_data(z, tmp); - gcm_mult(ctx, z, z); - } -} - - -/* Function to init AES GCM context to zero */ -void esp_aes_gcm_init( esp_gcm_context *ctx) -{ - if (ctx == NULL) { - return; - } - - bzero(ctx, sizeof(esp_gcm_context)); - - ctx->gcm_state = ESP_AES_GCM_STATE_INIT; -} - -/* Function to clear AES-GCM context */ -void esp_aes_gcm_free( esp_gcm_context *ctx) -{ - if (ctx == NULL) { - return; - } - bzero(ctx, sizeof(esp_gcm_context)); -} - -/* Setup AES-GCM */ -int esp_aes_gcm_starts( esp_gcm_context *ctx, - int mode, - const unsigned char *iv, - size_t iv_len, - const unsigned char *aad, - size_t aad_len ) -{ - /* IV and AD are limited to 2^64 bits, so 2^61 bytes */ - /* IV is not allowed to be zero length */ - if ( iv_len == 0 || - ( (uint64_t) iv_len ) >> 61 != 0 || - ( (uint64_t) aad_len ) >> 61 != 0 ) { - return ( MBEDTLS_ERR_GCM_BAD_INPUT ); - } - - if (!ctx) { - ESP_LOGE(TAG, "No AES context supplied"); - return -1; - } - - if (!iv) { - ESP_LOGE(TAG, "No IV supplied"); - return -1; - } - - if ( (aad_len > 0) && !aad) { - ESP_LOGE(TAG, "No aad supplied"); - return -1; - } - - /* Initialize AES-GCM context */ - memset(ctx->ghash, 0, sizeof(ctx->ghash)); - ctx->data_len = 0; - - ctx->iv = iv; - ctx->iv_len = iv_len; - ctx->aad = aad; - ctx->aad_len = aad_len; - ctx->mode = mode; - - /* H and the lookup table are only generated once per ctx */ - if (ctx->gcm_state == ESP_AES_GCM_STATE_INIT) { - /* Lock the AES engine to calculate ghash key H in hardware */ - esp_aes_acquire_hardware(); - esp_aes_setkey_hardware( &ctx->aes_ctx, mode); - esp_aes_mode_init(ESP_AES_BLOCK_MODE_GCM); - /* Enable DMA mode */ - REG_WRITE(AES_DMA_ENABLE_REG, 1); - REG_WRITE(AES_TRIGGER_REG, 1); - while (REG_READ(AES_STATE_REG) != AES_STATE_IDLE); - - memcpy(ctx->H, (uint8_t *)AES_H_BASE, AES_BLOCK_BYTES); - - esp_aes_release_hardware(); - - gcm_gen_table(ctx); - } - - ctx->gcm_state = ESP_AES_GCM_STATE_START; - - /* Once H is obtained we need to derive J0 (Initial Counter Block) */ - esp_gcm_derive_J0(ctx); - - /* The initial counter block keeps updating during the esp_gcm_update call - * however to calculate final authentication tag T we need original J0 - * so we make a copy here - */ - memcpy(ctx->ori_j0, ctx->J0, 16); - - esp_gcm_ghash(ctx, ctx->aad, ctx->aad_len, ctx->ghash); - - return ( 0 ); -} - -/* Perform AES-GCM operation */ -int esp_aes_gcm_update( esp_gcm_context *ctx, - size_t length, - const unsigned char *input, - unsigned char *output ) -{ - size_t nc_off = 0; - uint8_t nonce_counter[AES_BLOCK_BYTES] = {0}; - uint8_t stream[AES_BLOCK_BYTES] = {0}; - - if (!ctx) { - ESP_LOGE(TAG, "No GCM context supplied"); - return -1; - } - if (!input) { - ESP_LOGE(TAG, "No input supplied"); - return -1; - } - if (!output) { - ESP_LOGE(TAG, "No output supplied"); - return -1; - } - - if ( output > input && (size_t) ( output - input ) < length ) { - return ( MBEDTLS_ERR_GCM_BAD_INPUT ); - } - /* If this is the first time esp_gcm_update is getting called - * calculate GHASH on aad and preincrement the ICB - */ - if (ctx->gcm_state == ESP_AES_GCM_STATE_START) { - /* Jo needs to be incremented first time, later the CTR - * operation will auto update it - */ - increment32_j0(ctx, nonce_counter); - ctx->gcm_state = ESP_AES_GCM_STATE_UPDATE; - } else if (ctx->gcm_state == ESP_AES_GCM_STATE_UPDATE) { - memcpy(nonce_counter, ctx->J0, AES_BLOCK_BYTES); - } - - /* Perform intermediate GHASH on "encrypted" data during decryption */ - if (ctx->mode == ESP_AES_DECRYPT) { - esp_gcm_ghash(ctx, input, length, ctx->ghash); - } - - /* Output = GCTR(J0, Input): Encrypt/Decrypt the input */ - esp_aes_crypt_ctr(&ctx->aes_ctx, length, &nc_off, nonce_counter, stream, input, output); - - /* ICB gets auto incremented after GCTR operation here so update the context */ - memcpy(ctx->J0, nonce_counter, AES_BLOCK_BYTES); - - /* Keep updating the length counter for final tag calculation */ - ctx->data_len += length; - - /* Perform intermediate GHASH on "encrypted" data during encryption*/ - if (ctx->mode == ESP_AES_ENCRYPT) { - esp_gcm_ghash(ctx, output, length, ctx->ghash); - } - - return 0; -} - -/* Function to read the tag value */ -int esp_aes_gcm_finish( esp_gcm_context *ctx, - unsigned char *tag, - size_t tag_len ) -{ - size_t nc_off = 0; - uint8_t len_block[AES_BLOCK_BYTES] = {0}; - - if ( tag_len > 16 || tag_len < 4 ) { - return ( MBEDTLS_ERR_GCM_BAD_INPUT ); - } - - /* Calculate final GHASH on aad_len, data length */ - ESP_PUT_BE64(len_block, ctx->aad_len * 8); - ESP_PUT_BE64(len_block + 8, ctx->data_len * 8); - esp_gcm_ghash(ctx, len_block, AES_BLOCK_BYTES, ctx->ghash); - - /* Tag T = GCTR(J0, ) where T is truncated to tag_len */ - esp_aes_crypt_ctr(&ctx->aes_ctx, tag_len, &nc_off, ctx->ori_j0, 0, ctx->ghash, tag); - - return 0; -} - -int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx, - int mode, - size_t length, - const unsigned char *iv, - size_t iv_len, - const unsigned char *add, - size_t add_len, - const unsigned char *input, - unsigned char *output, - size_t tag_len, - unsigned char *tag ) -{ - int ret; - - - if ( ( ret = esp_aes_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) { - return ( ret ); - } - - if ( ( ret = esp_aes_gcm_update( ctx, length, input, output ) ) != 0 ) { - return ( ret ); - } - - if ( ( ret = esp_aes_gcm_finish( ctx, tag, tag_len ) ) != 0 ) { - return ( ret ); - } - - return ( 0 ); -} - -int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx, - size_t length, - const unsigned char *iv, - size_t iv_len, - const unsigned char *add, - size_t add_len, - const unsigned char *tag, - size_t tag_len, - const unsigned char *input, - unsigned char *output ) -{ - int ret; - unsigned char check_tag[16]; - size_t i; - int diff; - - if ( ( ret = esp_aes_gcm_crypt_and_tag( ctx, ESP_AES_DECRYPT, length, - iv, iv_len, add, add_len, - input, output, tag_len, check_tag ) ) != 0 ) { - return ( ret ); - } - - /* Check tag in "constant-time" */ - for ( diff = 0, i = 0; i < tag_len; i++ ) { - diff |= tag[i] ^ check_tag[i]; - } - - if ( diff != 0 ) { - bzero( output, length ); - return ( MBEDTLS_ERR_GCM_AUTH_FAILED ); - } - - return ( 0 ); -} diff --git a/components/mbedtls/port/include/esp32s3/aes.h b/components/mbedtls/port/include/aes/esp_aes.h similarity index 90% rename from components/mbedtls/port/include/esp32s3/aes.h rename to components/mbedtls/port/include/aes/esp_aes.h index 904a0ecdf5..c9c4316960 100644 --- a/components/mbedtls/port/include/esp32s3/aes.h +++ b/components/mbedtls/port/include/aes/esp_aes.h @@ -1,9 +1,9 @@ /** - * \brief AES block cipher, ESP32 hardware accelerated version + * \brief AES block cipher, ESP 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 + * Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -21,31 +21,23 @@ * */ -#ifndef ESP_AES_H -#define ESP_AES_H +#pragma once #include "esp_types.h" -#include "esp32s3/rom/aes.h" +#include "hal/aes_types.h" #ifdef __cplusplus extern "C" { #endif -/* padlock.c and aesni.c rely on these values! */ -#define ESP_AES_ENCRYPT 1 -#define ESP_AES_DECRYPT 0 + #define ERR_ESP_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ #define ERR_ESP_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ - /** * \brief AES context structure * - * \note buf is able to hold 32 extra bytes, which can be used: - * - for alignment purposes if VIA padlock is used, and/or - * - to simplify key expansion in the 256-bit case by - * generating an extra round key */ typedef struct { uint8_t key_bytes; @@ -53,17 +45,20 @@ typedef struct { uint8_t key[32]; } esp_aes_context; - /** * \brief The AES XTS context-type definition. */ -typedef struct { +typedef struct +{ esp_aes_context crypt; /*!< The AES context to use for AES block encryption or decryption. */ esp_aes_context tweak; /*!< The AES context used for tweak computation. */ } esp_aes_xts_context; + + + /** * \brief Lock access to AES hardware unit * @@ -99,7 +94,7 @@ void esp_aes_init( esp_aes_context *ctx ); */ void esp_aes_free( esp_aes_context *ctx ); -/* +/** * \brief This function initializes the specified AES XTS context. * * It must be the first API called before using @@ -116,16 +111,6 @@ void esp_aes_xts_init( esp_aes_xts_context *ctx ); */ void esp_aes_xts_free( esp_aes_xts_context *ctx ); -/** - * \brief AES set key schedule (encryption or decryption) - * - * \param ctx AES context to be initialized - * \param key encryption key - * \param keybits must be 128, 192 or 256 - * - * \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH - */ - /** * \brief AES set key schedule (encryption or decryption) * @@ -313,21 +298,26 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx, * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. */ int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx, - const unsigned char *key, - unsigned int keybits ); + const unsigned char *key, + unsigned int keybits ); /** - * \brief Internal AES block encryption function - * (Only exposed to allow overriding it, - * see AES_ENCRYPT_ALT) + * \brief This function prepares an XTS context for decryption and + * sets the decryption key. * - * \param ctx AES context - * \param input Plaintext block - * \param output Output (ciphertext) block + * \param ctx The AES XTS context to which the key should be bound. + * \param key The decryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. */ int esp_aes_xts_setkey_dec( esp_aes_xts_context *ctx, - const unsigned char *key, - unsigned int keybits ); + const unsigned char *key, + unsigned int keybits ); /** @@ -341,9 +331,6 @@ int esp_aes_xts_setkey_dec( esp_aes_xts_context *ctx, */ int esp_internal_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); -/** Deprecated, see esp_aes_internal_encrypt */ -void esp_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) __attribute__((deprecated)); - /** * \brief Internal AES block decryption function * (Only exposed to allow overriding it, @@ -355,15 +342,15 @@ void esp_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsig */ int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); -/** Deprecated, see esp_aes_internal_decrypt */ -void esp_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) __attribute__((deprecated)); - /** AES-XTS 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 ); +/** Deprecated, see esp_aes_internal_decrypt */ +void esp_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) __attribute__((deprecated)); + +/** Deprecated, see esp_aes_internal_encrypt */ +void esp_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) __attribute__((deprecated)); #ifdef __cplusplus } #endif - -#endif /* aes.h */ diff --git a/components/mbedtls/port/include/esp32s3/gcm.h b/components/mbedtls/port/include/aes/esp_aes_gcm.h similarity index 95% rename from components/mbedtls/port/include/esp32s3/gcm.h rename to components/mbedtls/port/include/aes/esp_aes_gcm.h index 07c80ad5e6..92c81205f8 100644 --- a/components/mbedtls/port/include/esp32s3/gcm.h +++ b/components/mbedtls/port/include/aes/esp_aes_gcm.h @@ -1,5 +1,5 @@ /** - * \brief AES block cipher, ESP32C hardware accelerated version + * \brief AES GCM block cipher, ESP hardware accelerated version * Based on mbedTLS FIPS-197 compliant version. * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved @@ -21,11 +21,12 @@ * */ -#ifndef ESP_GCM_H -#define ESP_GCM_H +#pragma once -#include "aes.h" +#include "aes/esp_aes.h" #include "mbedtls/cipher.h" +#include "soc/lldesc.h" + #ifdef __cplusplus extern "C" { #endif @@ -36,6 +37,7 @@ extern "C" { typedef enum { ESP_AES_GCM_STATE_INIT, + ESP_AES_GCM_STATE_START, ESP_AES_GCM_STATE_UPDATE, ESP_AES_GCM_STATE_FINISH } esp_aes_gcm_state; @@ -59,6 +61,7 @@ typedef struct { esp_aes_gcm_state gcm_state; } esp_gcm_context; + /** * \brief This function initializes the specified GCM context * @@ -96,8 +99,8 @@ int esp_aes_gcm_setkey( esp_gcm_context *ctx, * \param iv The initialization vector. * \param iv_len The length of the IV. * \param add The buffer holding the additional data, or NULL - * if \p add_len is 0. - * \param add_len The length of the additional data. If 0, + * if \p aad_len is 0. + * \param aad_len The length of the additional data. If 0, * \p add is NULL. * * \return \c 0 on success. @@ -176,7 +179,7 @@ void esp_aes_gcm_free( esp_gcm_context *ctx); * \param iv The initialization vector. * \param iv_len The length of the IV. * \param add The buffer holding the additional data. - * \param add_len The length of the additional data. + * \param aad_len The length of the additional data. * \param input The buffer holding the input data. * \param output The buffer for holding the output data. * \param tag_len The length of the tag to generate. @@ -190,7 +193,7 @@ int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *add, - size_t add_len, + size_t aad_len, const unsigned char *input, unsigned char *output, size_t tag_len, @@ -211,7 +214,7 @@ int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx, * \param iv The initialization vector. * \param iv_len The length of the IV. * \param add The buffer holding the additional data. - * \param add_len The length of the additional data. + * \param aad_len The length of the additional data. * \param tag The buffer holding the tag. * \param tag_len The length of the tag. * \param input The buffer holding the input data. @@ -225,7 +228,7 @@ int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *add, - size_t add_len, + size_t aad_len, const unsigned char *tag, size_t tag_len, const unsigned char *input, @@ -234,5 +237,3 @@ int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx, #ifdef __cplusplus } #endif - -#endif /* gcm.h */ diff --git a/components/mbedtls/port/include/esp32s3/crypto_dma.h b/components/mbedtls/port/include/aes/esp_aes_internal.h similarity index 51% rename from components/mbedtls/port/include/esp32s3/crypto_dma.h rename to components/mbedtls/port/include/aes/esp_aes_internal.h index ce7d67efad..35a7d3935a 100644 --- a/components/mbedtls/port/include/esp32s3/crypto_dma.h +++ b/components/mbedtls/port/include/aes/esp_aes_internal.h @@ -1,4 +1,7 @@ /** + * \brief AES block cipher, ESP-IDF hardware accelerated version + * Based on mbedTLS FIPS-197 compliant version. + * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved * Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd * SPDX-License-Identifier: Apache-2.0 @@ -15,26 +18,37 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * + * Internal API */ -#ifndef ESP_CRYPTO_DMA_H -#define ESP_CRYPTO_DMA_H +#pragma once -#include + +#include "aes/esp_aes.h" +#include "aes/esp_aes_gcm.h" +#include #ifdef __cplusplus extern "C" { #endif +bool valid_key_length(const esp_aes_context *ctx); -/* Since crypto DMA is shared between DMA-AES and SHA blocks - * Needs to be taken by respective blocks before using Crypto DMA + +/** + * @brief Run a AES-GCM conversion using DMA + * + * @param ctx Aes context + * @param input Pointer to input data + * @param output Pointer to output data + * @param len Length of the input data + * @param aad_desc GCM additional data DMA descriptor + * @param aad_len GCM additional data length + * @return int -1 on error */ -extern _lock_t crypto_dma_lock; +int esp_aes_process_dma_gcm(esp_aes_context *ctx, const unsigned char *input, unsigned char *output, size_t len, lldesc_t *aad_desc, size_t aad_len); + #ifdef __cplusplus } #endif - -#endif /* crypto_dma.h */ diff --git a/components/mbedtls/port/include/aes_alt.h b/components/mbedtls/port/include/aes_alt.h index ba63cd9202..2f8e958b27 100644 --- a/components/mbedtls/port/include/aes_alt.h +++ b/components/mbedtls/port/include/aes_alt.h @@ -28,15 +28,7 @@ extern "C" { #endif #if defined(MBEDTLS_AES_ALT) -#if CONFIG_IDF_TARGET_ESP32 -#include "esp32/aes.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/aes.h" -#elif CONFIG_IDF_TARGET_ESP32S3 -#include "esp32s3/aes.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/aes.h" -#endif +#include "aes/esp_aes.h" typedef esp_aes_context mbedtls_aes_context; diff --git a/components/mbedtls/port/include/esp32/aes.h b/components/mbedtls/port/include/esp32/aes.h index f423b8a7ff..3eb87a78c8 100644 --- a/components/mbedtls/port/include/esp32/aes.h +++ b/components/mbedtls/port/include/esp32/aes.h @@ -24,330 +24,8 @@ #ifndef ESP_AES_H #define ESP_AES_H -#include "esp_types.h" -#include "esp32/rom/aes.h" +#warning "esp32/aes.h is deprecated, please use aes/esp_aes.h instead" -#ifdef __cplusplus -extern "C" { -#endif - -/* padlock.c and aesni.c rely on these values! */ -#define ESP_AES_ENCRYPT 1 -#define ESP_AES_DECRYPT 0 - -#define ERR_ESP_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ -#define ERR_ESP_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ - -/** - * \brief AES context structure - * - */ -typedef struct { - uint8_t key_bytes; - volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ - uint8_t key[32]; -} esp_aes_context; - -/** - * \brief The AES XTS context-type definition. - */ -typedef struct -{ - esp_aes_context crypt; /*!< The AES context to use for AES block - encryption or decryption. */ - esp_aes_context tweak; /*!< The AES context used for tweak - computation. */ -} esp_aes_xts_context; - - -/** - * \brief Lock access to AES hardware unit - * - * AES hardware unit can only be used by one - * consumer at a time. - * - * esp_aes_xxx API calls automatically manage locking & unlocking of - * hardware, this function is only needed if you want to call - * ets_aes_xxx functions directly. - */ -void esp_aes_acquire_hardware( void ); - -/** - * \brief Unlock access to AES hardware unit - * - * esp_aes_xxx API calls automatically manage locking & unlocking of - * hardware, this function is only needed if you want to call - * ets_aes_xxx functions directly. - */ -void esp_aes_release_hardware( void ); - -/** - * \brief Initialize AES context - * - * \param ctx AES context to be initialized - */ -void esp_aes_init( esp_aes_context *ctx ); - -/** - * \brief Clear AES context - * - * \param ctx AES context to be cleared - */ -void esp_aes_free( esp_aes_context *ctx ); - -/** - * \brief This function initializes the specified AES XTS context. - * - * It must be the first API called before using - * the context. - * - * \param ctx The AES XTS context to initialize. - */ -void esp_aes_xts_init( esp_aes_xts_context *ctx ); - -/** - * \brief This function releases and clears the specified AES XTS context. - * - * \param ctx The AES XTS context to clear. - */ -void esp_aes_xts_free( esp_aes_xts_context *ctx ); - -/** - * \brief AES set key schedule (encryption or decryption) - * - * \param ctx AES context to be initialized - * \param key encryption key - * \param keybits must be 128, 192 or 256 - * - * \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH - */ -int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, unsigned int keybits ); - -/** - * \brief AES-ECB block encryption/decryption - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param input 16-byte input block - * \param output 16-byte output block - * - * \return 0 if successful - */ -int esp_aes_crypt_ecb( esp_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16] ); - -/** - * \brief AES-CBC buffer encryption/decryption - * Length should be a multiple of the block - * size (16 bytes) - * - * \note Upon exit, the content of the IV is updated so that you can - * call the function same function again on the following - * block(s) of data and get the same result as if it was - * encrypted in one call. This allows a "streaming" usage. - * If on the other hand you need to retain the contents of the - * IV, you should either save it manually or use the cipher - * module instead. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful, or ERR_AES_INVALID_INPUT_LENGTH - */ -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 ); - - -/** - * \brief AES-CFB128 buffer encryption/decryption. - * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * esp_aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \note Upon exit, the content of the IV is updated so that you can - * call the function same function again on the following - * block(s) of data and get the same result as if it was - * encrypted in one call. This allows a "streaming" usage. - * If on the other hand you need to retain the contents of the - * IV, you should either save it manually or use the cipher - * module instead. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv_off offset in IV (updated after use) - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -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 ); - -/** - * \brief AES-CFB8 buffer encryption/decryption. - * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * esp_aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \note Upon exit, the content of the IV is updated so that you can - * call the function same function again on the following - * block(s) of data and get the same result as if it was - * encrypted in one call. This allows a "streaming" usage. - * If on the other hand you need to retain the contents of the - * IV, you should either save it manually or use the cipher - * module instead. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -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 ); - -/** - * \brief AES-CTR buffer encryption/decryption - * - * Warning: You have to keep the maximum use of your counter in mind! - * - * Note: Due to the nature of CTR you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * esp_aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \param ctx AES context - * \param length The length of the data - * \param nc_off The offset in the current stream_block (for resuming - * within current cipher stream). The offset pointer to - * should be 0 at the start of a stream. - * \param nonce_counter The 128-bit nonce and counter. - * \param stream_block The saved stream-block for resuming. Is overwritten - * by the function. - * \param input The input data stream - * \param output The output data stream - * - * \return 0 if successful - */ -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 ); - -/** - * \brief This function prepares an XTS context for encryption and - * sets the encryption key. - * - * \param ctx The AES XTS context to which the key should be bound. - * \param key The encryption key. This is comprised of the XTS key1 - * concatenated with the XTS key2. - * \param keybits The size of \p key passed in bits. Valid options are: - *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • - *
  • 512 bits (each of key1 and key2 is a 256-bit key)
- * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. - */ -int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx, - const unsigned char *key, - unsigned int keybits ); - -/** - * \brief This function performs an AES-OFB (Output Feedback Mode) - * encryption or decryption operation. - * - * \param ctx The AES context to use for encryption or decryption. - * It must be initialized and bound to a key. - * \param length The length of the input data. - * \param iv_off The offset in IV (updated after use). - * It must point to a valid \c size_t. - * \param iv The initialization vector (updated after use). - * It must be a readable and writeable buffer of \c 16 Bytes. - * \param input The buffer holding the input data. - * It must be readable and of size \p length Bytes. - * \param output The buffer holding the output data. - * It must be writeable and of size \p length Bytes. - * - * \return \c 0 on success. - */ -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 ); - -/** - * \brief This function prepares an XTS context for decryption and - * sets the decryption key. - * - * \param ctx The AES XTS context to which the key should be bound. - * \param key The decryption key. This is comprised of the XTS key1 - * concatenated with the XTS key2. - * \param keybits The size of \p key passed in bits. Valid options are: - *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • - *
  • 512 bits (each of key1 and key2 is a 256-bit key)
- * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. - */ -int esp_aes_xts_setkey_dec( esp_aes_xts_context *ctx, - const unsigned char *key, - unsigned int keybits ); - - -/** - * \brief Internal AES block encryption function - * (Only exposed to allow overriding it, - * see AES_ENCRYPT_ALT) - * - * \param ctx AES context - * \param input Plaintext block - * \param output Output (ciphertext) block - */ -int esp_internal_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); - -/** - * \brief Internal AES block decryption function - * (Only exposed to allow overriding it, - * see AES_DECRYPT_ALT) - * - * \param ctx AES context - * \param input Ciphertext block - * \param output Output (plaintext) block - */ -int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); - -/** AES-XTS 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 +#include "aes/esp_aes.h" #endif /* aes.h */ diff --git a/components/mbedtls/port/include/esp32s2/aes.h b/components/mbedtls/port/include/esp32s2/aes.h index 5f55fdce4a..09a3b3d59b 100644 --- a/components/mbedtls/port/include/esp32s2/aes.h +++ b/components/mbedtls/port/include/esp32s2/aes.h @@ -24,346 +24,10 @@ #ifndef ESP_AES_H #define ESP_AES_H -#include "esp_types.h" -#include "esp32s2/rom/aes.h" -#ifdef __cplusplus -extern "C" { -#endif +//#warning "esp32s2/aes.h is deprecated, please use aes/esp_aes.h instead" -/* padlock.c and aesni.c rely on these values! */ -#define ESP_AES_ENCRYPT 1 -#define ESP_AES_DECRYPT 0 +#include "aes/esp_aes.h" -#define ERR_ESP_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ -#define ERR_ESP_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ - - -/** - * \brief AES context structure - * - * \note buf is able to hold 32 extra bytes, which can be used: - * - for alignment purposes if VIA padlock is used, and/or - * - to simplify key expansion in the 256-bit case by - * generating an extra round key - */ -typedef struct { - uint8_t key_bytes; - volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */ - uint8_t key[32]; -} esp_aes_context; - - -/** - * \brief The AES XTS context-type definition. - */ -typedef struct { - esp_aes_context crypt; /*!< The AES context to use for AES block - encryption or decryption. */ - esp_aes_context tweak; /*!< The AES context used for tweak - computation. */ -} esp_aes_xts_context; - -/** - * \brief Lock access to AES hardware unit - * - * AES hardware unit can only be used by one - * consumer at a time. - * - * esp_aes_xxx API calls automatically manage locking & unlocking of - * hardware, this function is only needed if you want to call - * ets_aes_xxx functions directly. - */ -void esp_aes_acquire_hardware( void ); - -/** - * \brief Unlock access to AES hardware unit - * - * esp_aes_xxx API calls automatically manage locking & unlocking of - * hardware, this function is only needed if you want to call - * ets_aes_xxx functions directly. - */ -void esp_aes_release_hardware( void ); - -/** - * \brief Initialize AES context - * - * \param ctx AES context to be initialized - */ -void esp_aes_init( esp_aes_context *ctx ); - -/** - * \brief Clear AES context - * - * \param ctx AES context to be cleared - */ -void esp_aes_free( esp_aes_context *ctx ); - -/* - * \brief This function initializes the specified AES XTS context. - * - * It must be the first API called before using - * the context. - * - * \param ctx The AES XTS context to initialize. - */ -void esp_aes_xts_init( esp_aes_xts_context *ctx ); - -/** - * \brief This function releases and clears the specified AES XTS context. - * - * \param ctx The AES XTS context to clear. - */ -void esp_aes_xts_free( esp_aes_xts_context *ctx ); - -/** - * \brief AES set key schedule (encryption or decryption) - * - * \param ctx AES context to be initialized - * \param key encryption key - * \param keybits must be 128, 192 or 256 - * - * \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH - */ - -/** - * \brief AES set key schedule (encryption or decryption) - * - * \param ctx AES context to be initialized - * \param key encryption key - * \param keybits must be 128, 192 or 256 - * - * \return 0 if successful, or ERR_AES_INVALID_KEY_LENGTH - */ -int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, unsigned int keybits ); - -/** - * \brief AES-ECB block encryption/decryption - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param input 16-byte input block - * \param output 16-byte output block - * - * \return 0 if successful - */ -int esp_aes_crypt_ecb( esp_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16] ); - -/** - * \brief AES-CBC buffer encryption/decryption - * Length should be a multiple of the block - * size (16 bytes) - * - * \note Upon exit, the content of the IV is updated so that you can - * call the function same function again on the following - * block(s) of data and get the same result as if it was - * encrypted in one call. This allows a "streaming" usage. - * If on the other hand you need to retain the contents of the - * IV, you should either save it manually or use the cipher - * module instead. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful, or ERR_AES_INVALID_INPUT_LENGTH - */ -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 ); - - -/** - * \brief AES-CFB128 buffer encryption/decryption. - * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * esp_aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \note Upon exit, the content of the IV is updated so that you can - * call the function same function again on the following - * block(s) of data and get the same result as if it was - * encrypted in one call. This allows a "streaming" usage. - * If on the other hand you need to retain the contents of the - * IV, you should either save it manually or use the cipher - * module instead. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv_off offset in IV (updated after use) - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -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 ); - -/** - * \brief AES-CFB8 buffer encryption/decryption. - * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * esp_aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \note Upon exit, the content of the IV is updated so that you can - * call the function same function again on the following - * block(s) of data and get the same result as if it was - * encrypted in one call. This allows a "streaming" usage. - * If on the other hand you need to retain the contents of the - * IV, you should either save it manually or use the cipher - * module instead. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -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 ); - -/** - * \brief AES-CTR buffer encryption/decryption - * - * Warning: You have to keep the maximum use of your counter in mind! - * - * Note: Due to the nature of CTR you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * esp_aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \param ctx AES context - * \param length The length of the data - * \param nc_off The offset in the current stream_block (for resuming - * within current cipher stream). The offset pointer to - * should be 0 at the start of a stream. - * \param nonce_counter The 128-bit nonce and counter. - * \param stream_block The saved stream-block for resuming. Is overwritten - * by the function. - * \param input The input data stream - * \param output The output data stream - * - * \return 0 if successful - */ -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 ); - -/** - * \brief This function performs an AES-OFB (Output Feedback Mode) - * encryption or decryption operation. - * - * \param ctx The AES context to use for encryption or decryption. - * It must be initialized and bound to a key. - * \param length The length of the input data. - * \param iv_off The offset in IV (updated after use). - * It must point to a valid \c size_t. - * \param iv The initialization vector (updated after use). - * It must be a readable and writeable buffer of \c 16 Bytes. - * \param input The buffer holding the input data. - * It must be readable and of size \p length Bytes. - * \param output The buffer holding the output data. - * It must be writeable and of size \p length Bytes. - * - * \return \c 0 on success. - */ -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 ); - -/** - * \brief This function prepares an XTS context for encryption and - * sets the encryption key. - * - * \param ctx The AES XTS context to which the key should be bound. - * \param key The encryption key. This is comprised of the XTS key1 - * concatenated with the XTS key2. - * \param keybits The size of \p key passed in bits. Valid options are: - *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • - *
  • 512 bits (each of key1 and key2 is a 256-bit key)
- * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. - */ -int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx, - const unsigned char *key, - unsigned int keybits ); - -/** - * \brief Internal AES block encryption function - * (Only exposed to allow overriding it, - * see AES_ENCRYPT_ALT) - * - * \param ctx AES context - * \param input Plaintext block - * \param output Output (ciphertext) block - */ -int esp_aes_xts_setkey_dec( esp_aes_xts_context *ctx, - const unsigned char *key, - unsigned int keybits ); - - -/** - * \brief Internal AES block encryption function - * (Only exposed to allow overriding it, - * see AES_ENCRYPT_ALT) - * - * \param ctx AES context - * \param input Plaintext block - * \param output Output (ciphertext) block - */ -int esp_internal_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); - -/** Deprecated, see esp_aes_internal_encrypt */ -void esp_aes_encrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) __attribute__((deprecated)); - -/** - * \brief Internal AES block decryption function - * (Only exposed to allow overriding it, - * see AES_DECRYPT_ALT) - * - * \param ctx AES context - * \param input Ciphertext block - * \param output Output (plaintext) block - */ -int esp_internal_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ); - -/** Deprecated, see esp_aes_internal_decrypt */ -void esp_aes_decrypt( esp_aes_context *ctx, const unsigned char input[16], unsigned char output[16] ) __attribute__((deprecated)); - -/** AES-XTS 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 #endif /* aes.h */ diff --git a/components/mbedtls/port/include/esp32s2/gcm.h b/components/mbedtls/port/include/esp32s2/gcm.h index d1fd6bcd4c..726783e8cc 100644 --- a/components/mbedtls/port/include/esp32s2/gcm.h +++ b/components/mbedtls/port/include/esp32s2/gcm.h @@ -20,220 +20,8 @@ * * */ +#pragma once -#ifndef ESP_GCM_H -#define ESP_GCM_H +#warning "esp32s2/gcm.h is deprecated, please use aes/esp_aes_gcm.h instead" -#include "aes.h" -#include "mbedtls/cipher.h" -#ifdef __cplusplus -extern "C" { -#endif - - -#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ -#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function.*/ - -typedef enum { - ESP_AES_GCM_STATE_INIT, - ESP_AES_GCM_STATE_START, - ESP_AES_GCM_STATE_UPDATE, - ESP_AES_GCM_STATE_FINISH -} esp_aes_gcm_state; -/** - * \brief The GCM context structure. - */ -typedef struct { - uint8_t H[16]; /*!< Initial hash value */ - uint8_t ghash[16]; /*!< GHASH value. */ - uint8_t J0[16]; - uint64_t HL[16]; /*!< Precalculated HTable low. */ - uint64_t HH[16]; /*!< Precalculated HTable high. */ - uint8_t ori_j0[16]; /*!< J0 from first iteration. */ - const uint8_t *iv; - size_t iv_len; /*!< The length of IV. */ - uint64_t aad_len; /*!< The total length of the additional data. */ - size_t data_len; - int mode; - const unsigned char *aad; /*!< The additional data. */ - esp_aes_context aes_ctx; - esp_aes_gcm_state gcm_state; -} esp_gcm_context; - -/** - * \brief This function initializes the specified GCM context - * - * \param ctx The GCM context to initialize. - */ -void esp_aes_gcm_init( esp_gcm_context *ctx); - -/** - * \brief This function associates a GCM context with a - * key. - * - * \param ctx The GCM context to initialize. - * \param cipher The 128-bit block cipher to use. - * \param key The encryption key. - * \param keybits The key size in bits. Valid options are: - *
  • 128 bits
  • - *
  • 192 bits
  • - *
  • 256 bits
- * - * \return \c 0 on success. - * \return A cipher-specific error code on failure. - */ -int esp_aes_gcm_setkey( esp_gcm_context *ctx, - mbedtls_cipher_id_t cipher, - const unsigned char *key, - unsigned int keybits ); - -/** - * \brief This function starts a GCM encryption or decryption - * operation. - * - * \param ctx The GCM context. - * \param mode The operation to perform: #MBEDTLS_GCM_ENCRYPT or - * #MBEDTLS_GCM_DECRYPT. - * \param iv The initialization vector. - * \param iv_len The length of the IV. - * \param add The buffer holding the additional data, or NULL - * if \p add_len is 0. - * \param add_len The length of the additional data. If 0, - * \p add is NULL. - * - * \return \c 0 on success. - */ -int esp_aes_gcm_starts( esp_gcm_context *ctx, - int mode, - const unsigned char *iv, - size_t iv_len, - const unsigned char *aad, - size_t aad_len ); - -/** - * \brief This function feeds an input buffer into an ongoing GCM - * encryption or decryption operation. - * - * ` The function expects input to be a multiple of 16 - * Bytes. Only the last call before calling - * mbedtls_gcm_finish() can be less than 16 Bytes. - * - * \note For decryption, the output buffer cannot be the same as - * input buffer. If the buffers overlap, the output buffer - * must trail at least 8 Bytes behind the input buffer. - * - * \param ctx The GCM context. - * \param length The length of the input data. This must be a multiple of - * 16 except in the last call before mbedtls_gcm_finish(). - * \param input The buffer holding the input data. - * \param output The buffer for holding the output data. - * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. - */ -int esp_aes_gcm_update( esp_gcm_context *ctx, - size_t length, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief This function finishes the GCM operation and generates - * the authentication tag. - * - * It wraps up the GCM stream, and generates the - * tag. The tag can have a maximum length of 16 Bytes. - * - * \param ctx The GCM context. - * \param tag The buffer for holding the tag. - * \param tag_len The length of the tag to generate. Must be at least four. - * - * \return \c 0 on success. - * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. - */ -int esp_aes_gcm_finish( esp_gcm_context *ctx, - unsigned char *tag, - size_t tag_len ); - -/** - * \brief This function clears a GCM context - * - * \param ctx The GCM context to clear. - */ -void esp_aes_gcm_free( esp_gcm_context *ctx); - -/** - * \brief This function performs GCM encryption or decryption of a buffer. - * - * \note For encryption, the output buffer can be the same as the - * input buffer. For decryption, the output buffer cannot be - * the same as input buffer. If the buffers overlap, the output - * buffer must trail at least 8 Bytes behind the input buffer. - * - * \param ctx The GCM context to use for encryption or decryption. - * \param mode The operation to perform: #MBEDTLS_GCM_ENCRYPT or - * #MBEDTLS_GCM_DECRYPT. - * \param length The length of the input data. This must be a multiple of - * 16 except in the last call before mbedtls_gcm_finish(). - * \param iv The initialization vector. - * \param iv_len The length of the IV. - * \param add The buffer holding the additional data. - * \param add_len The length of the additional data. - * \param input The buffer holding the input data. - * \param output The buffer for holding the output data. - * \param tag_len The length of the tag to generate. - * \param tag The buffer for holding the tag. - * - * \return \c 0 on success. - */ -int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx, - int mode, - size_t length, - const unsigned char *iv, - size_t iv_len, - const unsigned char *add, - size_t add_len, - const unsigned char *input, - unsigned char *output, - size_t tag_len, - unsigned char *tag ); - - -/** - * \brief This function performs a GCM authenticated decryption of a - * buffer. - * - * \note For decryption, the output buffer cannot be the same as - * input buffer. If the buffers overlap, the output buffer - * must trail at least 8 Bytes behind the input buffer. - * - * \param ctx The GCM context. - * \param length The length of the input data. This must be a multiple - * of 16 except in the last call before mbedtls_gcm_finish(). - * \param iv The initialization vector. - * \param iv_len The length of the IV. - * \param add The buffer holding the additional data. - * \param add_len The length of the additional data. - * \param tag The buffer holding the tag. - * \param tag_len The length of the tag. - * \param input The buffer holding the input data. - * \param output The buffer for holding the output data. - * - * \return 0 if successful and authenticated. - * \return #MBEDTLS_ERR_GCM_AUTH_FAILED if the tag does not match. - */ -int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx, - size_t length, - const unsigned char *iv, - size_t iv_len, - const unsigned char *add, - size_t add_len, - const unsigned char *tag, - size_t tag_len, - const unsigned char *input, - unsigned char *output ); - -#ifdef __cplusplus -} -#endif - -#endif /* gcm.h */ +#include "aes/esp_aes_gcm.h" diff --git a/components/mbedtls/port/include/gcm_alt.h b/components/mbedtls/port/include/gcm_alt.h index e395b8de94..7210d92b87 100644 --- a/components/mbedtls/port/include/gcm_alt.h +++ b/components/mbedtls/port/include/gcm_alt.h @@ -23,18 +23,16 @@ #ifndef GCM_ALT_H #define GCM_ALT_H +#include "soc/soc_caps.h" + #ifdef __cplusplus extern "C" { #endif #if defined(MBEDTLS_GCM_ALT) -#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 -#if CONFIG_IDF_TARGET_ESP32C3 -#include "esp32s3/gcm.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/gcm.h" -#endif +#if SOC_AES_SUPPORT_GCM +#include "aes/esp_aes_gcm.h" typedef esp_gcm_context mbedtls_gcm_context; @@ -48,24 +46,7 @@ typedef esp_gcm_context mbedtls_gcm_context; #define mbedtls_gcm_auth_decrypt esp_aes_gcm_auth_decrypt #define mbedtls_gcm_crypt_and_tag esp_aes_gcm_crypt_and_tag -#endif // CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 - -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/gcm.h" - - -typedef esp_gcm_context mbedtls_gcm_context; - -#define mbedtls_gcm_init esp_aes_gcm_init -#define mbedtls_gcm_free esp_aes_gcm_free -#define mbedtls_gcm_setkey esp_aes_gcm_setkey -#define mbedtls_gcm_starts esp_aes_gcm_starts -#define mbedtls_gcm_update esp_aes_gcm_update -#define mbedtls_gcm_finish esp_aes_gcm_finish -#define mbedtls_gcm_auth_decrypt esp_aes_gcm_auth_decrypt -#define mbedtls_gcm_crypt_and_tag esp_aes_gcm_crypt_and_tag - -#endif // CONFIG_IDF_TARGET_ESP32S2 +#endif // SOC_AES_SUPPORT_GCM #endif /* MBEDTLS_GCM_ALT */ diff --git a/components/mbedtls/test/test_aes.c b/components/mbedtls/test/test_aes.c index 93d7d887df..b37d2165a0 100644 --- a/components/mbedtls/test/test_aes.c +++ b/components/mbedtls/test/test_aes.c @@ -335,9 +335,9 @@ TEST_CASE("mbedtls CTR stream test", "[aes]") memset(key, 0x44, 16); // allocate internal memory - uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(chipertext); TEST_ASSERT_NOT_NULL(plaintext); @@ -383,113 +383,6 @@ TEST_CASE("mbedtls CTR stream test", "[aes]") free(decryptedtext); } -TEST_CASE("mbedtls GCM stream test", "[aes]") -{ - - const unsigned SZ = 100; - mbedtls_gcm_context ctx; - uint8_t nonce[16]; - uint8_t key[16]; - uint8_t tag[16]; - mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; - - /* Cipher produced via this Python: - import os, binascii - from cryptography.hazmat.primitives.ciphers.aead import AESGCM - - key = b'\x56' * 16 - iv = b'\x89' * 16 - data = b'\xab' * 100 - - aesgcm = AESGCM(key) - - ct = aesgcm.encrypt(iv, data, '') - - ct_arr = "" - for idx, b in enumerate(ct): - if idx % 8 == 0: - ct_arr += '\n' - ct_arr += "0x{}, ".format(binascii.hexlify(b)) - print(ct_arr) - */ - const uint8_t expected_cipher[] = { - 0x03, 0x92, 0x13, 0x49, 0x1f, 0x1f, 0x24, 0x41, - 0xe8, 0xeb, 0x89, 0x47, 0x50, 0x0a, 0xce, 0xa3, - 0xc7, 0x1c, 0x10, 0x70, 0xb0, 0x89, 0x82, 0x5e, - 0x0f, 0x4a, 0x23, 0xee, 0xd2, 0xfc, 0xff, 0x45, - 0x61, 0x4c, 0xd1, 0xfb, 0x6d, 0xe2, 0xbe, 0x67, - 0x6f, 0x94, 0x72, 0xa3, 0xe7, 0x04, 0x99, 0xb3, - 0x4a, 0x46, 0xf9, 0x2b, 0xaf, 0xac, 0xa9, 0x0e, - 0x43, 0x7e, 0x8b, 0xc4, 0xbf, 0x49, 0xa4, 0x83, - 0x9c, 0x31, 0x11, 0x1c, 0x09, 0xac, 0x90, 0xdf, - 0x00, 0x34, 0x08, 0xe5, 0x70, 0xa3, 0x7e, 0x4b, - 0x36, 0x48, 0x5a, 0x3f, 0x28, 0xc7, 0x1c, 0xd9, - 0x1b, 0x1b, 0x49, 0x96, 0xe9, 0x7c, 0xea, 0x54, - 0x7c, 0x71, 0x29, 0x0d - }; - const uint8_t expected_tag[] = { - 0x35, 0x1c, 0x21, 0xc6, 0xbc, 0x6b, 0x18, 0x52, - 0x90, 0xe1, 0xf2, 0x5b, 0xe1, 0xf6, 0x15, 0xee, - }; - - - memset(nonce, 0x89, 16); - memset(key, 0x56, 16); - - // allocate internal memory - uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - - TEST_ASSERT_NOT_NULL(chipertext); - TEST_ASSERT_NOT_NULL(plaintext); - TEST_ASSERT_NOT_NULL(decryptedtext); - - memset(plaintext, 0xAB, SZ); - /* Test that all the end results are the same - no matter how many bytes we encrypt each call - */ - for (int bytes_to_process = 16; bytes_to_process < SZ; bytes_to_process = bytes_to_process + 16) { - memset(nonce, 0x89, 16); - memset(chipertext, 0x0, SZ); - memset(decryptedtext, 0x0, SZ); - memset(tag, 0x0, 16); - - mbedtls_gcm_init(&ctx); - mbedtls_gcm_setkey(&ctx, cipher, key, 128); - mbedtls_gcm_starts( &ctx, MBEDTLS_AES_ENCRYPT, nonce, sizeof(nonce), NULL, 0 ); - - // Encrypt - for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { - // Limit length of last call to avoid exceeding buffer size - size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; - mbedtls_gcm_update(&ctx, length, plaintext + idx, chipertext + idx ); - } - mbedtls_gcm_finish( &ctx, tag, sizeof(tag) ); - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, chipertext, SZ); - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag, sizeof(tag)); - - // Decrypt - memset(nonce, 0x89, 16); - mbedtls_gcm_free( &ctx ); - mbedtls_gcm_init(&ctx); - mbedtls_gcm_setkey(&ctx, cipher, key, 128); - mbedtls_gcm_starts( &ctx, MBEDTLS_AES_DECRYPT, nonce, sizeof(nonce), NULL, 0 ); - - for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { - // Limit length of last call to avoid exceeding buffer size - - size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; - mbedtls_gcm_update(&ctx, length, chipertext + idx, decryptedtext + idx ); - } - mbedtls_gcm_finish( &ctx, tag, sizeof(tag) ); - TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); - mbedtls_gcm_free( &ctx ); - } - free(plaintext); - free(chipertext); - free(decryptedtext); -} TEST_CASE("mbedtls OFB stream test", "[aes]") { @@ -534,9 +427,9 @@ TEST_CASE("mbedtls OFB stream test", "[aes]") memset(key, 0x44, 16); // allocate internal memory - uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(chipertext); TEST_ASSERT_NOT_NULL(plaintext); @@ -620,9 +513,9 @@ TEST_CASE("mbedtls CFB8 stream test", "[aes]") memset(key, 0x44, 16); // allocate internal memory - uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(chipertext); TEST_ASSERT_NOT_NULL(plaintext); @@ -703,9 +596,9 @@ TEST_CASE("mbedtls CFB128 stream test", "[aes]") memset(key, 0x44, 16); // allocate internal memory - uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(chipertext); TEST_ASSERT_NOT_NULL(plaintext); @@ -790,7 +683,7 @@ void aes_psram_ctr_test(uint32_t input_buf_caps, uint32_t output_buf_caps) // allocate memory according the requested caps uint8_t *chipertext = heap_caps_malloc(SZ + ALIGNMENT_SIZE_BYTES, output_buf_caps); uint8_t *plaintext = heap_caps_malloc(SZ + ALIGNMENT_SIZE_BYTES, input_buf_caps); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(chipertext); TEST_ASSERT_NOT_NULL(plaintext); @@ -1392,7 +1285,7 @@ const uint8_t expected_cipher_long_input_end[] = { 0x6a, 0xde, 0xe3, 0x53, }; -void aes_icache_ctr_test(uint32_t output_buf_caps) +void aes_ext_flash_ctr_test(uint32_t output_buf_caps) { mbedtls_aes_context ctx; uint8_t nonce[16]; @@ -1402,9 +1295,8 @@ void aes_icache_ctr_test(uint32_t output_buf_caps) memset(nonce, 0x2F, 16); memset(key, 0x1E, 16); - // allocate internal memory uint8_t *chipertext = heap_caps_malloc(SZ, output_buf_caps); - uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(chipertext); TEST_ASSERT_NOT_NULL(decryptedtext); @@ -1414,7 +1306,7 @@ void aes_icache_ctr_test(uint32_t output_buf_caps) size_t offset; - // Encrypt with input buffer in external ram + // Encrypt with input buffer in external flash offset = 0; memset(nonce, 0x2F, 16); mbedtls_aes_crypt_ctr(&ctx, SZ, &offset, nonce, stream_block, long_input, chipertext); @@ -1423,7 +1315,7 @@ void aes_icache_ctr_test(uint32_t output_buf_caps) // Decrypt offset = 0; memset(nonce, 0x2F, 16); - // Decrypt with input buffer in instruction memory, the crypto DMA can't access this + // Decrypt with input buffer in external flash, the crypto DMA can't access this mbedtls_aes_crypt_ctr(&ctx, SZ, &offset, nonce, stream_block, chipertext, decryptedtext); TEST_ASSERT_EQUAL_HEX8_ARRAY(long_input, decryptedtext, SZ); @@ -1435,87 +1327,16 @@ void aes_icache_ctr_test(uint32_t output_buf_caps) /* Tests how crypto DMA handles data in external memory */ TEST_CASE("mbedtls AES PSRAM tests", "[aes]") { - aes_psram_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - aes_psram_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + aes_psram_ctr_test(MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + aes_psram_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); aes_psram_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); aes_psram_one_buf_ctr_test(); } -/* Tests how crypto DMA handles data from iCache */ -TEST_CASE("mbedtls AES iCache tests", "[aes]") +/* Tests how crypto DMA handles data from external flash */ +TEST_CASE("mbedtls AES external flash tests", "[aes]") { - aes_icache_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); - aes_icache_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + aes_ext_flash_ctr_test(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + aes_ext_flash_ctr_test(MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); } #endif // CONFIG_SPIRAM_USE_MALLOC - -TEST_CASE("mbedtls AES GCM self-tests", "[aes]") -{ - TEST_ASSERT_FALSE_MESSAGE(mbedtls_gcm_self_test(1), "AES GCM self-test should pass."); -} - - -TEST_CASE("mbedtls AES GCM crypt-and-tag", "[aes]") -{ - const unsigned CALL_SZ = 32 * 1024; - mbedtls_gcm_context ctx; - unsigned char tag_buf[16]; - mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; - uint8_t iv[16]; - uint8_t key[16]; - - memset(iv, 0xEE, 16); - memset(key, 0x44, 16); - - // allocate internal memory - uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - TEST_ASSERT_NOT_NULL(buf); - uint8_t aad[16]; - memset(aad, 0x22, 16); - - mbedtls_gcm_init(&ctx); - mbedtls_gcm_setkey( &ctx, cipher, key, 128); - - memset(buf, 0xAA, CALL_SZ); - mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_AES_ENCRYPT, CALL_SZ, iv, sizeof(iv), aad, sizeof(aad), buf, buf, 16, tag_buf); - - - /* Sanity check: make sure the last ciphertext block matches - what we expect to see. - - Last block and tag produced via this Python: - - import os, binascii - from cryptography.hazmat.primitives.ciphers.aead import AESGCM - - key = b'\x44' * 16 - iv = b'\xEE' * 16 - data = b'\xAA' * 100 - aad = b'\x22 * 16 - - aesgcm = AESGCM(key) - - ct = aesgcm.encrypt(iv, data, aad) - */ - const uint8_t expected_last_block[] = { - 0x7d, 0x3d, 0x16, 0x84, 0xd0, 0xb4, 0x38, 0x30, - 0xd1, 0x24, 0x6f, 0x7e, 0x9a, 0x9c, 0x81, 0x58, - }; - - const uint8_t expected_tag[] = { - 0x7e, 0x16, 0x04, 0x07, 0x4b, 0x7e, 0x6b, 0xf7, - 0x5d, 0xce, 0x9e, 0x7d, 0x3f, 0x85, 0xc5, 0xa5, - }; - - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16, 16); - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag_buf, 16); - - - memset(iv, 0xEE, 16); - - TEST_ASSERT_EQUAL(mbedtls_gcm_auth_decrypt(&ctx, CALL_SZ, iv, sizeof(iv), aad, sizeof(aad), expected_tag, sizeof(expected_tag), buf, buf), 0); - TEST_ASSERT_EACH_EQUAL_HEX8(0xAA, buf, CALL_SZ); - - - free(buf); -} diff --git a/components/mbedtls/test/test_aes_gcm.c b/components/mbedtls/test/test_aes_gcm.c new file mode 100644 index 0000000000..352b9fa7ae --- /dev/null +++ b/components/mbedtls/test/test_aes_gcm.c @@ -0,0 +1,494 @@ +/* mbedTLS GCM test +*/ + +#include +#include +#include +#include +#include "mbedtls/aes.h" +#include "mbedtls/gcm.h" +#include "unity.h" +#include "sdkconfig.h" +#include "esp_heap_caps.h" +#include "test_utils.h" +#include "ccomp_timer.h" +#include "sys/param.h" + +#if CONFIG_MBEDTLS_HARDWARE_GCM + +/* + Python example code for generating test vectors + + import os, binascii + from cryptography.hazmat.primitives.ciphers.aead import AESGCM + + def as_c_array(byte_arr): + hex_str = '' + for idx, byte in enumerate(byte_arr): + hex_str += "0x{:02x}, ".format(byte) + bytes_per_line = 8 + if idx % bytes_per_line == bytes_per_line - 1: + hex_str += '\n' + + return hex_str + + key = b'\x44' * 16 + iv = b'\xEE' * 16 + data = b'\xAA' * 3200 + aad = b'\x76' * 16 + + aesgcm = AESGCM(key) + + ct = aesgcm.encrypt(iv, data, aad) + + print(as_c_array(ct)) +*/ + +TEST_CASE("mbedtls GCM stream test", "[aes-gcm]") +{ + + const unsigned SZ = 100; + mbedtls_gcm_context ctx; + uint8_t nonce[16]; + uint8_t key[16]; + uint8_t tag[16]; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + + const uint8_t expected_cipher[] = { + 0x03, 0x92, 0x13, 0x49, 0x1f, 0x1f, 0x24, 0x41, + 0xe8, 0xeb, 0x89, 0x47, 0x50, 0x0a, 0xce, 0xa3, + 0xc7, 0x1c, 0x10, 0x70, 0xb0, 0x89, 0x82, 0x5e, + 0x0f, 0x4a, 0x23, 0xee, 0xd2, 0xfc, 0xff, 0x45, + 0x61, 0x4c, 0xd1, 0xfb, 0x6d, 0xe2, 0xbe, 0x67, + 0x6f, 0x94, 0x72, 0xa3, 0xe7, 0x04, 0x99, 0xb3, + 0x4a, 0x46, 0xf9, 0x2b, 0xaf, 0xac, 0xa9, 0x0e, + 0x43, 0x7e, 0x8b, 0xc4, 0xbf, 0x49, 0xa4, 0x83, + 0x9c, 0x31, 0x11, 0x1c, 0x09, 0xac, 0x90, 0xdf, + 0x00, 0x34, 0x08, 0xe5, 0x70, 0xa3, 0x7e, 0x4b, + 0x36, 0x48, 0x5a, 0x3f, 0x28, 0xc7, 0x1c, 0xd9, + 0x1b, 0x1b, 0x49, 0x96, 0xe9, 0x7c, 0xea, 0x54, + 0x7c, 0x71, 0x29, 0x0d + }; + const uint8_t expected_tag[] = { + 0x35, 0x1c, 0x21, 0xc6, 0xbc, 0x6b, 0x18, 0x52, + 0x90, 0xe1, 0xf2, 0x5b, 0xe1, 0xf6, 0x15, 0xee, + }; + + + memset(nonce, 0x89, 16); + memset(key, 0x56, 16); + + // allocate internal memory + uint8_t *chipertext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *plaintext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *decryptedtext = heap_caps_malloc(SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + + TEST_ASSERT_NOT_NULL(chipertext); + TEST_ASSERT_NOT_NULL(plaintext); + TEST_ASSERT_NOT_NULL(decryptedtext); + + memset(plaintext, 0xAB, SZ); + /* Test that all the end results are the same + no matter how many bytes we encrypt each call + */ + for (int bytes_to_process = 16; bytes_to_process < SZ; bytes_to_process = bytes_to_process + 16) { + memset(nonce, 0x89, 16); + memset(chipertext, 0x0, SZ); + memset(decryptedtext, 0x0, SZ); + memset(tag, 0x0, 16); + + mbedtls_gcm_init(&ctx); + mbedtls_gcm_setkey(&ctx, cipher, key, 128); + mbedtls_gcm_starts( &ctx, MBEDTLS_AES_ENCRYPT, nonce, sizeof(nonce), NULL, 0 ); + + // Encrypt + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + mbedtls_gcm_update(&ctx, length, plaintext + idx, chipertext + idx ); + } + mbedtls_gcm_finish( &ctx, tag, sizeof(tag) ); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher, chipertext, SZ); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag, sizeof(tag)); + + // Decrypt + memset(nonce, 0x89, 16); + mbedtls_gcm_free( &ctx ); + mbedtls_gcm_init(&ctx); + mbedtls_gcm_setkey(&ctx, cipher, key, 128); + mbedtls_gcm_starts( &ctx, MBEDTLS_AES_DECRYPT, nonce, sizeof(nonce), NULL, 0 ); + + for (int idx = 0; idx < SZ; idx = idx + bytes_to_process) { + // Limit length of last call to avoid exceeding buffer size + + size_t length = (idx + bytes_to_process > SZ) ? (SZ - idx) : bytes_to_process; + mbedtls_gcm_update(&ctx, length, chipertext + idx, decryptedtext + idx ); + } + mbedtls_gcm_finish( &ctx, tag, sizeof(tag) ); + TEST_ASSERT_EQUAL_HEX8_ARRAY(plaintext, decryptedtext, SZ); + mbedtls_gcm_free( &ctx ); + } + free(plaintext); + free(chipertext); + free(decryptedtext); +} + +TEST_CASE("mbedtls AES GCM self-tests", "[aes-gcm]") +{ + TEST_ASSERT_FALSE_MESSAGE(mbedtls_gcm_self_test(1), "AES GCM self-test should pass."); +} + +typedef struct { + uint8_t *plaintext; + size_t plaintext_length; + uint32_t output_caps; + uint8_t *add_buf; + size_t add_length; + uint8_t *iv; + size_t iv_length; + uint8_t *key; + size_t key_bits; + size_t tag_len; +} aes_gcm_test_cfg_t; + +typedef struct { + const uint8_t *expected_tag; + const uint8_t *ciphertext_last_block; // Last block of the chipertext +} aes_gcm_test_expected_res_t; + + +typedef enum { + AES_GCM_TEST_CRYPT_N_TAG, + AES_GCM_TEST_START_UPDATE_FINISH, +} aes_gcm_test_type_t; + +static void aes_gcm_test(aes_gcm_test_cfg_t *cfg, aes_gcm_test_expected_res_t *res, aes_gcm_test_type_t aes_gcm_type) +{ + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + mbedtls_gcm_context ctx; + + uint8_t tag_buf_encrypt[16] = {}; + uint8_t tag_buf_decrypt[16] = {}; + uint8_t iv_buf[16] = {}; + + uint8_t *ciphertext = heap_caps_malloc(cfg->plaintext_length, cfg->output_caps); + uint8_t *output = heap_caps_malloc(cfg->plaintext_length, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + + if (cfg->plaintext_length != 0) { + TEST_ASSERT_NOT_NULL(ciphertext); + TEST_ASSERT_NOT_NULL(output); + } + + memset(ciphertext, 0, cfg->plaintext_length); + memset(output, 0, cfg->plaintext_length); + memcpy(iv_buf, cfg->iv, cfg->iv_length); + + mbedtls_gcm_init(&ctx); + mbedtls_gcm_setkey(&ctx, cipher, cfg->key, cfg->key_bits); + + /* Encrypt and tag */ + if (aes_gcm_type == AES_GCM_TEST_CRYPT_N_TAG) { + mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_AES_ENCRYPT, cfg->plaintext_length, iv_buf, cfg->iv_length, cfg->add_buf, cfg->add_length, cfg->plaintext, ciphertext, cfg->tag_len, tag_buf_encrypt); + } else if (aes_gcm_type == AES_GCM_TEST_START_UPDATE_FINISH){ + TEST_ASSERT(mbedtls_gcm_starts( &ctx, MBEDTLS_AES_ENCRYPT, iv_buf, cfg->iv_length, cfg->add_buf, cfg->add_length) == 0 ); + TEST_ASSERT(mbedtls_gcm_update( &ctx, cfg->plaintext_length, cfg->plaintext, ciphertext) == 0 ); + TEST_ASSERT(mbedtls_gcm_finish( &ctx, tag_buf_encrypt, cfg->tag_len) == 0 ); + } + size_t offset = cfg->plaintext_length > 16 ? cfg->plaintext_length - 16 : 0; + /* Sanity check: make sure the last ciphertext block matches what we expect to see. */ + TEST_ASSERT_EQUAL_HEX8_ARRAY(res->ciphertext_last_block, ciphertext + offset, MIN(16, cfg->plaintext_length)); + TEST_ASSERT_EQUAL_HEX8_ARRAY(res->expected_tag, tag_buf_encrypt, cfg->tag_len); + + + /* Decrypt and authenticate */ + if (aes_gcm_type == AES_GCM_TEST_CRYPT_N_TAG) { + TEST_ASSERT(mbedtls_gcm_auth_decrypt(&ctx, cfg->plaintext_length, iv_buf, cfg->iv_length, cfg->add_buf, cfg->add_length, res->expected_tag, cfg->tag_len, ciphertext, output) == 0); + } else if (aes_gcm_type == AES_GCM_TEST_START_UPDATE_FINISH){ + TEST_ASSERT(mbedtls_gcm_starts( &ctx, MBEDTLS_AES_DECRYPT, iv_buf, cfg->iv_length, cfg->add_buf, cfg->add_length) == 0 ); + TEST_ASSERT(mbedtls_gcm_update( &ctx, cfg->plaintext_length, ciphertext, output) == 0 ); + TEST_ASSERT(mbedtls_gcm_finish( &ctx, tag_buf_decrypt, cfg->tag_len) == 0 ); + + /* mbedtls_gcm_auth_decrypt already checks tag so only needed for AES_GCM_TEST_START_UPDATE_FINISH */ + TEST_ASSERT_EQUAL_HEX8_ARRAY(res->expected_tag, tag_buf_decrypt, cfg->tag_len); + } + + TEST_ASSERT_EQUAL_HEX8_ARRAY(cfg->plaintext, output, cfg->plaintext_length); + + free(ciphertext); + free(output); +} + + + +TEST_CASE("mbedtls AES GCM", "[aes-gcm]") +{ + uint8_t iv[16]; + uint8_t key[16]; + uint8_t add[30]; + + memset(iv, 0xB1, sizeof(iv)); + memset(key, 0x27, sizeof(key)); + memset(add, 0x90, sizeof(add)); + + size_t length[] = {10, 16, 500, 5000, 12345}; + + const uint8_t expected_last_block[][16] = { + + {0x37, 0x99, 0x4b, 0x16, 0x5f, 0x8d, 0x27, 0xb1, + 0x60, 0x72}, + + {0x37, 0x99, 0x4b, 0x16, 0x5f, 0x8d, 0x27, 0xb1, + 0x60, 0x72, 0x9a, 0x81, 0x8d, 0x3c, 0x69, 0x66}, + + {0x9d, 0x7a, 0xac, 0x84,0xe3, 0x70, 0x43, 0x0f, + 0xa7, 0x83, 0x43, 0xc9, 0x04, 0xf8, 0x7d, 0x48}, + + {0xee, 0xfd, 0xab, 0x2a, 0x09, 0x44, 0x41, 0x6a, + 0x91, 0xb0, 0x74, 0x24, 0xee, 0x35, 0xb1, 0x39}, + + {0x51, 0xf7, 0x1f, 0x67, 0x1a, 0x4a, 0x12, 0x37, + 0x60, 0x3b, 0x68, 0x01, 0x20, 0x4f, 0xf3, 0xd9}, + }; + + const uint8_t expected_tag[][16] = { + + {0x06, 0x4f, 0xb5, 0x91, 0x12, 0x24, 0xb4, 0x24, + 0x0b, 0xc2, 0x85, 0x59, 0x6a, 0x7c, 0x1f, 0xc9}, + + {0x45, 0xc2, 0xa8, 0xfe, 0xff, 0x49, 0x1f, 0x45, + 0x8e, 0x29, 0x74, 0x41, 0xed, 0x9b, 0x54, 0x28}, + + {0xe1, 0xf9, 0x40, 0xfa, 0x29, 0x6f, 0x30, 0xae, + 0xb6, 0x9b, 0x33, 0xdb, 0x8a, 0xf9, 0x70, 0xc4}, + + {0x22, 0xe1, 0x22, 0x34, 0x0c, 0x91, 0x0b, 0xcf, + 0xa3, 0x42, 0xe0, 0x48, 0xe6, 0xfe, 0x2e, 0x28}, + + {0xfb, 0xfe, 0x5a, 0xed, 0x26, 0x5c, 0x5e, 0x66, + 0x4e, 0xb2, 0x48, 0xce, 0xe9, 0x88, 0x1c, 0xe0}, + }; + + aes_gcm_test_cfg_t cfg = { + .output_caps = MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, + .iv = iv, + .iv_length = sizeof(iv), + .key = key, + .key_bits = 8*sizeof(key), + .add_buf = add, + .add_length = sizeof(add), + .tag_len = 16 + }; + + aes_gcm_test_expected_res_t res = { + }; + + for (int i = 0; i < sizeof(length)/sizeof(length[0]); i++) { + printf("Test AES-GCM with plaintext length = %d\n", length[i]); + uint8_t *input = heap_caps_malloc(length[i], MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT(input != NULL || length[i] == 0); + memset(input, 0x36, length[i]); + + cfg.plaintext = input; + cfg.plaintext_length = length[i]; + res.expected_tag = expected_tag[i]; + res.ciphertext_last_block = expected_last_block[i], + + aes_gcm_test(&cfg, &res, AES_GCM_TEST_CRYPT_N_TAG); + aes_gcm_test(&cfg, &res, AES_GCM_TEST_START_UPDATE_FINISH); + + free(input); + } +} + + +TEST_CASE("mbedtls AES GCM - Different add messages", "[aes-gcm]") +{ + const unsigned CALL_SZ = 160; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t *input = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(input); + + memset(input, 0x67, CALL_SZ); + memset(iv, 0xA2, sizeof(iv)); + memset(key, 0x48, sizeof(key)); + + const uint8_t expected_last_block[] = { + 0xcd, 0xb9, 0xad, 0x6f, 0xc9, 0x35, 0x21, 0x0d, + 0xc9, 0x5d, 0xea, 0xd9, 0xf7, 0x1d, 0x43, 0xed + }; + + size_t add_len[] = {0, 10, 16, 500, 5000}; + + const uint8_t expected_tag[][16] = { + {0xe3, 0x91, 0xad, 0x40, 0x96, 0xb7, 0x8c, 0x53, + 0x4d, 0x15, 0x7d, 0x55, 0x15, 0xdf, 0x10, 0x69}, + + {0xc2, 0x38, 0x36, 0xe9, 0x12, 0x72, 0x5b, 0x31, + 0x0c, 0xde, 0xb5, 0xc9, 0x8c, 0xa3, 0xcb, 0xe7}, + + {0x57, 0x10, 0x22, 0x91, 0x65, 0xfa, 0x89, 0xba, + 0x0a, 0x3e, 0xc1, 0x7c, 0x93, 0x6e, 0x35, 0xac}, + + {0x3c, 0x28, 0x03, 0xc2, 0x14, 0x40, 0xec, 0xb6, + 0x25, 0xfb, 0xdd, 0x55, 0xa0, 0xb2, 0x47, 0x7b}, + + {0xfa, 0x66, 0x4a, 0x97, 0x2d, 0x02, 0x32, 0x5b, + 0x92, 0x94, 0xf1, 0x00, 0x1c, 0xfa, 0xe3, 0x07} + }; + + aes_gcm_test_cfg_t cfg = { + .plaintext = input, + .plaintext_length = CALL_SZ, + .output_caps = MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL, + .iv = iv, + .iv_length = sizeof(iv), + .key = key, + .key_bits = 8*sizeof(key), + .tag_len = 16 + }; + + aes_gcm_test_expected_res_t res = { + .ciphertext_last_block = expected_last_block, + }; + + for (int i = 0; i < sizeof(add_len)/sizeof(add_len[0]); i++) { + printf("Test AES-GCM with add length = %d\n", add_len[i]); + uint8_t *add = heap_caps_malloc(add_len[i], MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT(add != NULL || add_len[i] == 0); + memset(add, 0x12, add_len[i]); + + cfg.add_buf = add; + cfg.add_length = add_len[i]; + res.expected_tag = expected_tag[i]; + + aes_gcm_test(&cfg, &res, AES_GCM_TEST_CRYPT_N_TAG); + aes_gcm_test(&cfg, &res, AES_GCM_TEST_START_UPDATE_FINISH); + + free(add); + } + free(input); +} + + + +TEST_CASE("mbedtls AES GCM performance, start, update, ret", "[aes-gcm]") +{ + const unsigned CALL_SZ = 16*3200; + mbedtls_gcm_context ctx; + float elapsed_usec; + unsigned char tag_buf[16]; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t aad[16]; + + memset(iv, 0xEE, 16); + memset(key, 0x44, 16); + memset(aad, 0x76, 16); + + // allocate internal memory + uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buf); + + mbedtls_gcm_init(&ctx); + mbedtls_gcm_setkey( &ctx, cipher, key, 128); + + ccomp_timer_start(); + + memset(buf, 0xAA, CALL_SZ); + + TEST_ASSERT(mbedtls_gcm_starts( &ctx, MBEDTLS_AES_ENCRYPT, iv, sizeof(iv), aad, sizeof(aad) ) == 0 ); + TEST_ASSERT(mbedtls_gcm_update( &ctx, CALL_SZ, buf, buf ) == 0 ); + TEST_ASSERT(mbedtls_gcm_finish( &ctx, tag_buf, 16 ) == 0 ); + + elapsed_usec = ccomp_timer_stop(); + + /* Sanity check: make sure the last ciphertext block matches + what we expect to see. +*/ + const uint8_t expected_last_block[] = { + 0xd4, 0x25, 0x88, 0xd4, 0x32, 0x52, 0x3d, 0x6f, + 0xae, 0x49, 0x19, 0xb5, 0x95, 0x01, 0xde, 0x7d, + }; + + const uint8_t expected_tag[] = { + 0xf5, 0x10, 0x1f, 0x21, 0x5b, 0x07, 0x0d, 0x3f, + 0xac, 0xc9, 0xd0, 0x42, 0x45, 0xef, 0xc7, 0xfa, + }; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16 , 16); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag_buf, 16); + + free(buf); + + // bytes/usec = MB/sec + float mb_sec = CALL_SZ / elapsed_usec; + printf("GCM encryption rate %.3fMB/sec\n", mb_sec); + +#ifdef CONFIG_MBEDTLS_HARDWARE_GCM + // Don't put a hard limit on software AES performance + TEST_PERFORMANCE_GREATER_THAN(AES_GCM_UPDATE_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec); +#endif +} + + +TEST_CASE("mbedtls AES GCM performance, crypt-and-tag", "[aes-gcm]") +{ + const unsigned CALL_SZ = 16*3200; + mbedtls_gcm_context ctx; + float elapsed_usec; + unsigned char tag_buf[16] = {}; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + uint8_t iv[16]; + uint8_t key[16]; + uint8_t aad[16]; + + memset(iv, 0xEE, 16); + memset(key, 0x44, 16); + memset(aad, 0x76, 16); + + // allocate internal memory + uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + TEST_ASSERT_NOT_NULL(buf); + + mbedtls_gcm_init(&ctx); + mbedtls_gcm_setkey( &ctx, cipher, key, 128); + + memset(buf, 0xAA, CALL_SZ); + + ccomp_timer_start(); + mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_AES_ENCRYPT, CALL_SZ, iv, sizeof(iv), aad, sizeof(aad), buf, buf, 16, tag_buf); + + elapsed_usec = ccomp_timer_stop(); + + /* Sanity check: make sure the last ciphertext block matches + what we expect to see. + */ + + const uint8_t expected_last_block[] = { + 0xd4, 0x25, 0x88, 0xd4, 0x32, 0x52, 0x3d, 0x6f, + 0xae, 0x49, 0x19, 0xb5, 0x95, 0x01, 0xde, 0x7d, + }; + + const uint8_t expected_tag[] = { + 0xf5, 0x10, 0x1f, 0x21, 0x5b, 0x07, 0x0d, 0x3f, + 0xac, 0xc9, 0xd0, 0x42, 0x45, 0xef, 0xc7, 0xfa, + }; + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16 , 16); + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag_buf, 16); + + free(buf); + + // bytes/usec = MB/sec + float mb_sec = CALL_SZ / elapsed_usec; + printf("GCM encryption rate %.3fMB/sec\n", mb_sec); + +#ifdef CONFIG_MBEDTLS_HARDWARE_GCM + // Don't put a hard limit on software AES performance + TEST_PERFORMANCE_GREATER_THAN(AES_GCM_CRYPT_TAG_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec); +#endif +} + +#endif //CONFIG_MBEDTLS_HARDWARE_GCM diff --git a/components/mbedtls/test/test_aes_perf.c b/components/mbedtls/test/test_aes_perf.c index 80fff08de4..5a455f4f38 100644 --- a/components/mbedtls/test/test_aes_perf.c +++ b/components/mbedtls/test/test_aes_perf.c @@ -25,7 +25,7 @@ TEST_CASE("mbedtls AES performance", "[aes][timeout=60]") memset(key, 0x44, 16); // allocate internal memory - uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(buf); mbedtls_aes_init(&ctx); mbedtls_aes_setkey_enc(&ctx, key, 128); @@ -67,75 +67,3 @@ TEST_CASE("mbedtls AES performance", "[aes][timeout=60]") TEST_PERFORMANCE_GREATER_THAN(AES_CBC_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec); #endif } - - -TEST_CASE("mbedtls AES GCM performance", "[aes]") -{ - const unsigned CALL_SZ = 32 * 1024; - mbedtls_gcm_context ctx; - float elapsed_usec; - unsigned char tag_buf[16]; - mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; - uint8_t iv[16]; - uint8_t key[16]; - - memset(iv, 0xEE, 16); - memset(key, 0x44, 16); - - // allocate internal memory - uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - TEST_ASSERT_NOT_NULL(buf); - uint8_t aad[16]; - memset(aad, 0x22, 16); - - mbedtls_gcm_init(&ctx); - mbedtls_gcm_setkey( &ctx, cipher, key, 128); - - ccomp_timer_start(); - - memset(buf, 0xAA, CALL_SZ); - mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_AES_ENCRYPT, CALL_SZ, iv, sizeof(iv), aad, sizeof(aad), buf, buf, 16, tag_buf); - - elapsed_usec = ccomp_timer_stop(); - - /* Sanity check: make sure the last ciphertext block matches - what we expect to see. - - Last block and tag produced via this Python: - - import os, binascii - from cryptography.hazmat.primitives.ciphers.aead import AESGCM - - key = b'\x44' * 16 - iv = b'\xEE' * 16 - data = b'\xAA' * 100 - aad = b'\x22 * 16 - - aesgcm = AESGCM(key) - - ct = aesgcm.encrypt(iv, data, aad) - */ - const uint8_t expected_last_block[] = { - 0x7d, 0x3d, 0x16, 0x84, 0xd0, 0xb4, 0x38, 0x30, - 0xd1, 0x24, 0x6f, 0x7e, 0x9a, 0x9c, 0x81, 0x58, - }; - - const uint8_t expected_tag[] = { - 0x7e, 0x16, 0x04, 0x07, 0x4b, 0x7e, 0x6b, 0xf7, - 0x5d, 0xce, 0x9e, 0x7d, 0x3f, 0x85, 0xc5, 0xa5, - }; - - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16 , 16); - TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag_buf, 16); - - free(buf); - - // bytes/usec = MB/sec - float mb_sec = CALL_SZ / elapsed_usec; - printf("GCM encryption rate %.3fMB/sec\n", mb_sec); - -#ifdef CONFIG_MBEDTLS_HARDWARE_GCM - // Don't put a hard limit on software AES performance - TEST_PERFORMANCE_GREATER_THAN(AES_GCM_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec); -#endif -} diff --git a/components/mbedtls/test/test_esp_crt_bundle.c b/components/mbedtls/test/test_esp_crt_bundle.c index 9d7e7803d8..82b57ee60d 100644 --- a/components/mbedtls/test/test_esp_crt_bundle.c +++ b/components/mbedtls/test/test_esp_crt_bundle.c @@ -309,35 +309,36 @@ exit: return ret; } + TEST_CASE("custom certificate bundle", "[mbedtls]") { - esp_crt_validate_res_t validate_res; + esp_crt_validate_res_t validate_res; - test_case_uses_tcpip(); + test_case_uses_tcpip(); - xSemaphoreHandle exit_sema = xSemaphoreCreateBinary(); + xSemaphoreHandle exit_sema = xSemaphoreCreateBinary(); - exit_flag = false; - xTaskCreate(server_task, "server task", 8192, &exit_sema, 10, NULL); + exit_flag = false; + xTaskCreate(server_task, "server task", 8192, &exit_sema, 10, NULL); - // Wait for the server to start up - vTaskDelay(100 / portTICK_PERIOD_MS); + // Wait for the server to start up + vTaskDelay(100 / portTICK_PERIOD_MS); - /* Test with default crt bundle that doesnt contain the ca crt */ - client_task(NULL, &validate_res); - TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_FAIL); + /* Test with default crt bundle that doesnt contain the ca crt */ + client_task(NULL, &validate_res); + TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_FAIL); - /* Test with bundle that does contain the CA crt */ - client_task(server_cert_bundle_start, &validate_res); - TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_OK); + /* Test with bundle that does contain the CA crt */ + client_task(server_cert_bundle_start, &validate_res); + TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_OK); - exit_flag = true; + exit_flag = true; - if (!xSemaphoreTake(exit_sema, 10000 / portTICK_PERIOD_MS)) { - TEST_FAIL_MESSAGE("exit_sem not released by server task"); - } + if (!xSemaphoreTake(exit_sema, 10000 / portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("exit_sem not released by server task"); + } - vSemaphoreDelete(exit_sema); + vSemaphoreDelete(exit_sema); } TEST_CASE("custom certificate bundle - weak hash", "[mbedtls]") diff --git a/components/mbedtls/test/test_sha_perf.c b/components/mbedtls/test/test_sha_perf.c index da51d3f8f4..c21085fb26 100644 --- a/components/mbedtls/test/test_sha_perf.c +++ b/components/mbedtls/test/test_sha_perf.c @@ -20,7 +20,7 @@ TEST_CASE("mbedtls SHA performance", "[aes]") unsigned char sha256[32]; // allocate internal memory - uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_DMA | MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); TEST_ASSERT_NOT_NULL(buf); memset(buf, 0x55, CALL_SZ); diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index d83ce33999..e5e2393e48 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -258,6 +258,11 @@ #define SOC_RSA_MAX_BIT_LEN (4096) +/*-------------------------- AES CAPS -----------------------------------------*/ +#define SOC_AES_SUPPORT_AES_128 (1) +#define SOC_AES_SUPPORT_AES_192 (1) +#define SOC_AES_SUPPORT_AES_256 (1) + /* ---------------------------- Compatibility ------------------------------- */ #define SOC_CAN_SUPPORTED SOC_TWAI_SUPPORTED #define CAN_BRP_MIN SOC_TWAI_BRP_MIN diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 4d8ac7ca01..38146e6d65 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -44,3 +44,12 @@ /*-------------------------- TOUCH SENSOR CAPS -------------------------------*/ #define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */ + +/*-------------------------- AES CAPS -----------------------------------------*/ +#define SOC_AES_SUPPORT_DMA (1) + +/* Has a centralized DMA, which is shared with all peripherals */ +#define SOC_AES_GENERAL_DMA (1) + +#define SOC_AES_SUPPORT_AES_128 (1) +#define SOC_AES_SUPPORT_AES_256 (1) diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 7dfacf528f..ff620ac6ad 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -276,6 +276,18 @@ #define SOC_RSA_MAX_BIT_LEN (4096) +/*-------------------------- AES CAPS -----------------------------------------*/ +#define SOC_AES_SUPPORT_DMA (1) +#define SOC_AES_SUPPORT_GCM (1) + +/* Has "crypto DMA", which is shared with SHA */ +#define SOC_AES_CRYPTO_DMA (1) + +#define SOC_AES_SUPPORT_AES_128 (1) +#define SOC_AES_SUPPORT_AES_192 (1) +#define SOC_AES_SUPPORT_AES_256 (1) + + /* ---------------------------- Compatibility ------------------------------- */ // No contents diff --git a/components/soc/esp32s3/include/soc/soc.h b/components/soc/esp32s3/include/soc/soc.h index a9d386b560..6560a188ab 100644 --- a/components/soc/esp32s3/include/soc/soc.h +++ b/components/soc/esp32s3/include/soc/soc.h @@ -258,10 +258,14 @@ #define SOC_DIRAM_DRAM_LOW 0x3FC88000 #define SOC_DIRAM_DRAM_HIGH 0x3FCF0000 -// Region of memory accessible via DMA. See esp_ptr_dma_capable(). +// Region of memory accessible via DMA in internal memory. See esp_ptr_dma_capable(). #define SOC_DMA_LOW 0x3FC88000 #define SOC_DMA_HIGH 0x3FD00000 +// Region of memory accessible via DMA in external memory. See esp_ptr_dma_ext_capable(). +#define SOC_DMA_EXT_LOW 0x3C000000 +#define SOC_DMA_EXT_HIGH 0x3DFFFFFF + // Region of memory that is byte-accessible. See esp_ptr_byte_accessible(). #define SOC_BYTE_ACCESSIBLE_LOW 0x3FC88000 #define SOC_BYTE_ACCESSIBLE_HIGH 0x3FD00000 diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 2a1d68caa9..d080d9e9e2 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -138,9 +138,19 @@ #define SOC_RSA_MAX_BIT_LEN (4096) +/*-------------------------- AES CAPS -----------------------------------------*/ +#define SOC_AES_SUPPORT_DMA (1) + +/* Has a centralized DMA, which is shared with all peripherals */ +#define SOC_AES_GENERAL_DMA (1) + +#define SOC_AES_SUPPORT_AES_128 (1) +#define SOC_AES_SUPPORT_AES_256 (1) + // Attention: These fixed DMA channels are temporarily workaround before we have a centralized DMA controller API to help alloc the channel dynamically // Remove them when GDMA driver API is ready #define SOC_GDMA_M2M_DMA_CHANNEL (0) #define SOC_GDMA_SPI2_DMA_CHANNEL (1) #define SOC_GDMA_SPI3_DMA_CHANNEL (2) #define SOC_GDMA_SHA_DMA_CHANNEL (3) +#define SOC_GDMA_AES_DMA_CHANNEL (4) diff --git a/components/soc/include/soc/soc_memory_layout.h b/components/soc/include/soc/soc_memory_layout.h index 615304d31b..9620237a7f 100644 --- a/components/soc/include/soc/soc_memory_layout.h +++ b/components/soc/include/soc/soc_memory_layout.h @@ -148,7 +148,7 @@ inline static bool IRAM_ATTR esp_ptr_dma_capable(const void *p) inline static bool IRAM_ATTR esp_ptr_dma_ext_capable(const void *p) { -#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 return (intptr_t)p >= SOC_DMA_EXT_LOW && (intptr_t)p < SOC_DMA_EXT_HIGH; #else return false;