Merge branch 'feature/aes_hal' into 'master'

AES: refactor and add HAL layer

See merge request espressif/esp-idf!10979
This commit is contained in:
Angus Gratton 2020-12-11 15:39:49 +08:00
commit 8929a9cdb1
42 changed files with 3202 additions and 3297 deletions

View File

@ -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";

View File

@ -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

View File

@ -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")

227
components/hal/aes_hal.c Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
#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

View File

@ -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

View File

@ -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 <stdbool.h>
#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(&reg_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

View File

@ -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 <stdbool.h>
#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(&reg_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(&reg_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

View File

@ -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
}

View File

@ -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 <stdbool.h>
#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(&reg_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

View File

@ -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;
}

View File

@ -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 <stddef.h>
#include <stdbool.h>
#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

View File

@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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 <string.h>
#include "mbedtls/aes.h"
#include "mbedtls/platform_util.h"
#include "esp32/aes.h"
#include "aes/esp_aes.h"
#include "soc/hwcrypto_periph.h"
#include <sys/lock.h>
#include "hal/aes_hal.h"
#include "aes/esp_aes_internal.h"
#include <freertos/FreeRTOS.h>
@ -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 );
}

View File

@ -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 <stdio.h>
#include <string.h>
#include <sys/lock.h>
#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(&reg_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();

View File

@ -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 <string.h>
#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;
}

View File

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

View File

@ -38,19 +38,7 @@
#include <sys/lock.h>
#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 )
{

File diff suppressed because it is too large Load Diff

View File

@ -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:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \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 */

View File

@ -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 */

View File

@ -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 <freertos/FreeRTOS.h>
#include "aes/esp_aes.h"
#include "aes/esp_aes_gcm.h"
#include <stdbool.h>
#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 */

View File

@ -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;

View File

@ -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:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \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:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \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 */

View File

@ -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:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \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 */

View File

@ -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:
* <ul><li>128 bits</li>
* <li>192 bits</li>
* <li>256 bits</li></ul>
*
* \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"

View File

@ -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 */

View File

@ -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);
}

View File

@ -0,0 +1,494 @@
/* mbedTLS GCM test
*/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <esp_system.h>
#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

View File

@ -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
}

View File

@ -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]")

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;