mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
457ce080ae
Refactor the AES driver and add HAL, LL and caps. Add better support for running AES-GCM fully in hardware.
228 lines
6.2 KiB
C
228 lines
6.2 KiB
C
// 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
|