#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if defined(WOLFSSL_ESPIDF)
#include "sdkconfig.h"
#include <wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h>
#ifndef NO_AES
#if defined(WOLFSSL_ESP32_CRYPT) && !defined(NO_WOLFSSL_ESP32_CRYPT_AES)
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
static const char* TAG = "wolf_hw_aes";
static wolfSSL_Mutex aes_mutex;
#define WOLFSSL_AES_MUTEX_WAIT 5000
static int espaes_CryptHwMutexInit = 0;
#if defined(WOLFSSL_HW_METRICS)
static unsigned long esp_aes_unsupported_length_usage_ct = 0;
#endif
static int esp_aes_hw_InUse(void)
{
int ret = ESP_OK;
ESP_LOGV(TAG, "enter esp_aes_hw_InUse");
if (espaes_CryptHwMutexInit == 0) {
ret = esp_CryptHwMutexInit(&aes_mutex);
if (ret == ESP_OK) {
espaes_CryptHwMutexInit = 1;
}
else {
ESP_LOGE(TAG, "aes mutex initialization failed.");
}
}
else {
}
if (ret == ESP_OK) {
ret = esp_CryptHwMutexLock(&aes_mutex, WOLFSSL_AES_MUTEX_WAIT);
if (ret == ESP_OK) {
ESP_LOGV(TAG, "esp_CryptHwMutexLock aes success");
}
else {
ESP_LOGW(TAG, "esp_CryptHwMutexLock aes timeout! %d", ret);
}
}
else {
ESP_LOGE(TAG, "aes engine lock failed.");
}
if (ret == ESP_OK) {
periph_module_enable(PERIPH_AES_MODULE);
#if defined(CONFIG_IDF_TARGET_ESP32S2) || \
defined(CONFIG_IDF_TARGET_ESP32S3)
{
DPORT_REG_WRITE(AES_DMA_ENABLE_REG, 0);
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || \
defined(CONFIG_IDF_TARGET_ESP32C6)
{
DPORT_REG_WRITE(AES_DMA_ENABLE_REG, 0);
}
#endif
}
ESP_LOGV(TAG, "leave esp_aes_hw_InUse");
return ret;
}
static void esp_aes_hw_Leave( void )
{
ESP_LOGV(TAG, "enter esp_aes_hw_Leave");
periph_module_disable(PERIPH_AES_MODULE);
esp_CryptHwMutexUnLock(&aes_mutex);
ESP_LOGV(TAG, "leave esp_aes_hw_Leave");
}
static int esp_aes_hw_Set_KeyMode(Aes *ctx, ESP32_AESPROCESS mode)
{
int ret = ESP_OK;
word32 i;
word32 mode_ = 0;
ESP_LOGV(TAG, " enter esp_aes_hw_Set_KeyMode %d", mode);
if (mode == ESP32_AES_UPDATEKEY_ENCRYPT) {
mode_ = 0;
}
else {
if (mode == ESP32_AES_UPDATEKEY_DECRYPT) {
mode_ = 4;
}
else {
ESP_LOGE(TAG, " >> unexpected error.");
ret = BAD_FUNC_ARG;
}
}
switch(ctx->keylen){
case 24: mode_ += 1; break;
case 32: mode_ += 2; break;
default: break;
}
#if defined(CONFIG_IDF_TARGET_ESP32)
#define TARGET_AES_KEY_BASE AES_KEY_BASE
if (mode_ == 3 || mode_ > 6) {
ESP_LOGE(TAG, "esp_aes_hw_Set_KeyMode unsupported mode: %i", mode_);
ret = BAD_FUNC_ARG;
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
#define TARGET_AES_KEY_BASE AES_KEY_BASE
if (mode_ == 1 || mode_ == 3 || mode_ == 5 || mode_ > 6) {
ESP_LOGE(TAG, "esp_aes_hw_Set_KeyMode unsupported mode: %i", mode_);
ret = BAD_FUNC_ARG;
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#define TARGET_AES_KEY_BASE AES_KEY_BASE
if (mode_ == 1 || mode_ == 3|| mode_ == 5 || mode_ > 6) {
ESP_LOGE(TAG, "esp_aes_hw_Set_KeyMode unsupported mode: %i", mode_);
ret = BAD_FUNC_ARG;
}
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define TARGET_AES_KEY_BASE AES_KEY_0_REG
if (mode_ == 1 || mode_ == 3 || mode_ == 5 || mode_ > 6) {
ESP_LOGE(TAG, "esp_aes_hw_Set_KeyMode unsupported mode: %i", mode_);
ret = BAD_FUNC_ARG;
}
#else
#define TARGET_AES_KEY_BASE AES_KEY_BASE
#endif
if (ret == ESP_OK) {
for (i = 0; i < (ctx->keylen) / sizeof(word32); i++) {
DPORT_REG_WRITE((volatile word32*)(TARGET_AES_KEY_BASE + (i * 4)),
*(((word32*)ctx->key) + i)
);
}
if (ret == ESP_OK) {
DPORT_REG_WRITE(AES_MODE_REG, mode_);
}
ESP_LOGV(TAG, " leave esp_aes_hw_Setkey");
}
return ret;
}
static void esp_aes_bk(const byte* in, byte* out)
{
const word32* inwords;
uint32_t* outwords;
inwords = (const word32*)in;
outwords = (uint32_t*)out;
ESP_LOGV(TAG, "enter esp_aes_bk");
#if defined(CONFIG_IDF_TARGET_ESP32)
DPORT_REG_WRITE(AES_TEXT_BASE, inwords[0]);
DPORT_REG_WRITE(AES_TEXT_BASE + 4, inwords[1]);
DPORT_REG_WRITE(AES_TEXT_BASE + 8, inwords[2]);
DPORT_REG_WRITE(AES_TEXT_BASE + 12, inwords[3]);
DPORT_REG_WRITE(AES_START_REG, 1);
while (1) {
if (DPORT_REG_READ(AES_IDLE_REG) == 1) {
break;
}
}
esp_dport_access_read_buffer(outwords, AES_TEXT_BASE, 4);
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
DPORT_REG_WRITE(AES_TEXT_IN_BASE, inwords[0]);
DPORT_REG_WRITE(AES_TEXT_IN_BASE + 4, inwords[1]);
DPORT_REG_WRITE(AES_TEXT_IN_BASE + 8, inwords[2]);
DPORT_REG_WRITE(AES_TEXT_IN_BASE + 12, inwords[3]);
DPORT_REG_WRITE(AES_TRIGGER_REG, 1);
while (DPORT_REG_READ(AES_STATE_REG) != 0) {
}
esp_dport_access_read_buffer((uint32_t*)outwords, AES_TEXT_OUT_BASE, 4);
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
DPORT_REG_WRITE(AES_TEXT_IN_0_REG, inwords[0]);
DPORT_REG_WRITE(AES_TEXT_IN_1_REG, inwords[1]);
DPORT_REG_WRITE(AES_TEXT_IN_2_REG, inwords[2]);
DPORT_REG_WRITE(AES_TEXT_IN_3_REG, inwords[3]);
DPORT_REG_WRITE(AES_TRIGGER_REG, 1);
while (DPORT_REG_READ(AES_STATE_REG) != 0) {
}
esp_dport_access_read_buffer(outwords, AES_TEXT_OUT_0_REG, 4);
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
DPORT_REG_WRITE(AES_TEXT_IN_BASE, inwords[0]);
DPORT_REG_WRITE(AES_TEXT_IN_BASE + 4, inwords[1]);
DPORT_REG_WRITE(AES_TEXT_IN_BASE + 8, inwords[2]);
DPORT_REG_WRITE(AES_TEXT_IN_BASE + 12, inwords[3]);
DPORT_REG_WRITE(AES_TRIGGER_REG, 1);
while (DPORT_REG_READ(AES_STATE_REG) != 0) {
}
esp_dport_access_read_buffer(outwords, AES_TEXT_OUT_BASE, 4);
#else
ESP_LOGW(TAG, "Warning: esp_aes_bk called for unsupported target: %s",
CONFIG_IDF_TARGET)
#endif
ESP_LOGV(TAG, "leave esp_aes_bk");
}
int wc_esp32AesSupportedKeyLenValue(int keylen)
{
int ret = ESP_OK;
#if defined(CONFIG_IDF_TARGET_ESP32)
if (keylen == 16 || keylen == 24 || keylen == 32) {
ret = 1;
}
else {
ret = ESP_OK;
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
if (keylen == 16 || keylen == 32) {
ret = 1;
}
else {
ret = ESP_OK;
}
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
if (keylen == 16 || keylen == 32) {
ret = 1;
}
else {
ret = ESP_OK;
}
#elif defined(CONFIG_IDF_TARGET_ESP32H2)
ret = ESP_OK;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
if (keylen == 16 || keylen == 32) {
ret = 1;
}
else {
ret = ESP_OK;
}
#else
ret = ESP_OK;
#endif
return ret;
}
int wc_esp32AesSupportedKeyLen(struct Aes* aes)
{
int ret;
if (aes == NULL) {
ret = ESP_OK;
}
else {
ret = wc_esp32AesSupportedKeyLenValue(aes->keylen);
}
return ret;
}
int wc_esp32AesEncrypt(Aes *aes, const byte* in, byte* out)
{
int ret = ESP_OK;
ESP_LOGV(TAG, "enter wc_esp32AesEncrypt");
ret = esp_aes_hw_InUse();
if (ret == ESP_OK) {
ret = esp_aes_hw_Set_KeyMode(aes, ESP32_AES_UPDATEKEY_ENCRYPT);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "wc_esp32AesEncrypt failed "
"during esp_aes_hw_Set_KeyMode");
}
}
if (ret == ESP_OK) {
esp_aes_bk(in, out);
}
esp_aes_hw_Leave();
return ret;
}
int wc_esp32AesDecrypt(Aes *aes, const byte* in, byte* out)
{
int ret;
ESP_LOGV(TAG, "enter wc_esp32AesDecrypt");
ret = esp_aes_hw_InUse();
if (ret == ESP_OK) {
ret = esp_aes_hw_Set_KeyMode(aes, ESP32_AES_UPDATEKEY_DECRYPT);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "wc_esp32AesDecrypt failed "
"during esp_aes_hw_Set_KeyMode");
esp_aes_hw_Leave();
ret = BAD_FUNC_ARG;
}
}
if (ret == ESP_OK) {
esp_aes_bk(in, out);
esp_aes_hw_Leave();
}
return ret;
}
int wc_esp32AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
int i;
int offset = 0;
word32 blocks = (sz / WC_AES_BLOCK_SIZE);
byte *iv;
byte temp_block[WC_AES_BLOCK_SIZE];
ESP_LOGV(TAG, "enter wc_esp32AesCbcEncrypt");
iv = (byte*)aes->reg;
ret = esp_aes_hw_InUse();
if (ret == ESP_OK) {
ret = esp_aes_hw_Set_KeyMode(aes, ESP32_AES_UPDATEKEY_ENCRYPT);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "wc_esp32AesCbcEncrypt failed HW Set KeyMode");
}
}
if (ret == ESP_OK) {
while (blocks--) {
XMEMCPY(temp_block, in + offset, WC_AES_BLOCK_SIZE);
for (i = 0; i < WC_AES_BLOCK_SIZE; i++) {
temp_block[i] ^= iv[i];
}
esp_aes_bk(temp_block, (out + offset));
offset += WC_AES_BLOCK_SIZE;
XMEMCPY(iv, out + offset - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
}
}
esp_aes_hw_Leave();
ESP_LOGV(TAG, "leave wc_esp32AesCbcEncrypt");
return ret;
}
int wc_esp32AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
int i;
int offset = 0;
word32 blocks = (sz / WC_AES_BLOCK_SIZE);
byte* iv;
byte temp_block[WC_AES_BLOCK_SIZE];
ESP_LOGV(TAG, "enter wc_esp32AesCbcDecrypt");
iv = (byte*)aes->reg;
ret = esp_aes_hw_InUse();
if (ret == ESP_OK) {
ret = esp_aes_hw_Set_KeyMode(aes, ESP32_AES_UPDATEKEY_DECRYPT);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "wc_esp32AesCbcDecrypt failed HW Set KeyMode");
}
}
if (ret == ESP_OK) {
while (blocks--) {
XMEMCPY(temp_block, in + offset, WC_AES_BLOCK_SIZE);
esp_aes_bk((in + offset), (out + offset));
for (i = 0; i < WC_AES_BLOCK_SIZE; i++) {
(out + offset)[i] ^= iv[i];
}
XMEMCPY(iv, temp_block, WC_AES_BLOCK_SIZE);
offset += WC_AES_BLOCK_SIZE;
}
}
esp_aes_hw_Leave();
ESP_LOGV(TAG, "leave wc_esp32AesCbcDecrypt");
return ret;
}
#endif
#endif
#if defined(WOLFSSL_ESP32_CRYPT) && !defined(NO_WOLFSSL_ESP32_CRYPT_AES)
#if defined(WOLFSSL_HW_METRICS)
int wc_esp32AesUnupportedLengthCountAdd(void) {
esp_aes_unsupported_length_usage_ct++;
return esp_aes_unsupported_length_usage_ct;
}
#endif
int esp_hw_show_aes_metrics(void)
{
int ret = ESP_OK;
#if defined(WOLFSSL_HW_METRICS)
ESP_LOGI(TAG, "--------------------------------------------------------");
ESP_LOGI(TAG, "------------- wolfSSL ESP HW AES Metrics -------------");
ESP_LOGI(TAG, "--------------------------------------------------------");
ESP_LOGI(TAG, "esp_aes_unsupported_length_usage_ct = %lu",
esp_aes_unsupported_length_usage_ct);
#else
#endif
return ret;
}
#endif
#endif