diff --git a/hw/misc/esp32c3_xts_aes.c b/hw/misc/esp32c3_xts_aes.c new file mode 100644 index 0000000000..04a13dd17a --- /dev/null +++ b/hw/misc/esp32c3_xts_aes.c @@ -0,0 +1,371 @@ +/* + * ESP32-C3 XTS-AES emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/error-report.h" +#include "crypto/aes.h" +#include "crypto/xts.h" +#include "hw/riscv/esp32c3_clk.h" +#include "hw/nvram/esp32c3_efuse.h" +#include "hw/misc/esp32c3_xts_aes.h" +#include "hw/nvram/esp32c3_efuse.h" +#include "hw/riscv/esp32c3_clk.h" + +#define XTS_AES_WARNING 0 +#define XTS_AES_DEBUG 0 + +#define EFUSE_KEY_PURPOSE_XTS_AES_128_KEY 4 +#define XTS_AES_KEY_SIZE 32 +#define ESP32C3_XTS_AES_DATA_UNIT_SIZE 128 +#define ESP32S3_XTS_AES_TWEAK_VALUE 0xFFFF80 + +struct xts_aes_keys_ctx { + AES_KEY enc; + AES_KEY dec; +}; + +static void xts_aes_encrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const struct xts_aes_keys_ctx *aesctx = ctx; + + AES_encrypt(src, dst, &aesctx->enc); +} + +static void xts_aes_decrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const struct xts_aes_keys_ctx *aesctx = ctx; + + AES_decrypt(src, dst, &aesctx->dec); +} + +static bool esp32c3_xts_aes_is_ciphertext_spi_visible(ESP32C3XtsAesState *s) +{ + return (s->state == XTS_AES_RELEASE); +} + +static bool esp32c3_xts_aes_is_manual_enc_enabled(ESP32C3XtsAesState *s) +{ + ESP32C3ClockClass *clock_class = ESP32C3_CLOCK_GET_CLASS(s->clock); + ESPEfuseClass *efuse_class = ESP_EFUSE_GET_CLASS(s->efuse); + uint32_t ext_dev_enc_dec_ctrl_reg = clock_class->get_ext_dev_enc_dec_ctrl(s->clock); + return ((ext_dev_enc_dec_ctrl_reg & 1) || ((ext_dev_enc_dec_ctrl_reg & 8) && (efuse_class->get_dis_download_man_encrypt == 0))); +} + +static bool esp32c3_xts_aes_is_flash_enc_enabled(ESP32C3XtsAesState *s) +{ + ESPEfuseClass *efuse_class = ESP_EFUSE_GET_CLASS(s->efuse); + uint32_t spi_boot_crypt_cnt = efuse_class->get_spi_boot_crypt_cnt(s->efuse); + return (ctpop32(spi_boot_crypt_cnt) & 1); +} + +static void esp32c3_xts_aes_get_key(ESP32C3XtsAesState *s, uint8_t *key) +{ + ESPEfuseClass *efuse_class = ESP_EFUSE_GET_CLASS(s->efuse); + + for (int i = EFUSE_BLOCK_KEY0; i < EFUSE_BLOCK_KEY6; i++) { + if (efuse_class->get_key_purpose(s->efuse, i) == EFUSE_KEY_PURPOSE_XTS_AES_128_KEY) { + efuse_class->get_key(s->efuse, i, key); + // flash encryption key is stored in reverse byte order in the efuse block, correct it + uint8_t temp; + for (int j = 0; j < XTS_AES_KEY_SIZE / 2; j++) { + temp = key[j]; + key[j] = key[XTS_AES_KEY_SIZE - j - 1]; + key[XTS_AES_KEY_SIZE - j - 1] = temp; + } + return; + } + } + memset(key, 0, XTS_AES_KEY_SIZE); +} + +static void esp32c3_xts_aes_read_ciphertext(ESP32C3XtsAesState *s, uint32_t* spi_data_regs, uint32_t* spi_data_size, uint32_t* spi_addr, uint32_t* spi_addr_size) +{ + *spi_data_size = s->linesize == 0 ? 16 : 32; + memcpy(spi_data_regs, s->ciphertext, *spi_data_size); + /* Right shift address by 8 as the target memory space is a 24-bit address */ + *spi_addr = (cpu_to_be32(s->physical_addr)) >> 8; + *spi_addr_size = 24 / 8; +} + +static void esp32c3_xts_aes_encrypt(ESP32C3XtsAesState *s) +{ + uint8_t efuse_key[XTS_AES_KEY_SIZE]; + uint8_t tweak[16]; + uint32_t linesize = s->linesize == 0 ? 16 : 32; + + uint8_t input_plaintext[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + uint8_t input_plaintext_reversed[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + uint8_t output_ciphertext[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + uint8_t output_ciphertext_reversed[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + + *((uint32_t *) tweak) = cpu_to_le32(s->physical_addr & ESP32S3_XTS_AES_TWEAK_VALUE); + memset(tweak + 4, 0, 12); + + esp32c3_xts_aes_get_key(s, efuse_key); + + struct xts_aes_keys_ctx aesdata = {}; + struct xts_aes_keys_ctx aestweak = {}; + + AES_set_encrypt_key(efuse_key, XTS_AES_KEY_SIZE / 2 * 8, &aesdata.enc); + AES_set_decrypt_key(efuse_key, XTS_AES_KEY_SIZE / 2 * 8, &aesdata.dec); + AES_set_encrypt_key(efuse_key + XTS_AES_KEY_SIZE / 2, XTS_AES_KEY_SIZE / 2 * 8, &aestweak.enc); + AES_set_decrypt_key(efuse_key + XTS_AES_KEY_SIZE / 2, XTS_AES_KEY_SIZE / 2 * 8, &aestweak.dec); + + memset(input_plaintext, 0, ESP32C3_XTS_AES_DATA_UNIT_SIZE); + + uint32_t plaintext_offs = (s->physical_addr % (ESP32C3_XTS_AES_PLAIN_REG_CNT * 4)); + uint32_t pad_left = s->physical_addr % ESP32C3_XTS_AES_DATA_UNIT_SIZE; + memcpy(input_plaintext + pad_left, ((uint8_t*)s->plaintext) + plaintext_offs, linesize); + + for (int i = 0; i < ESP32C3_XTS_AES_DATA_UNIT_SIZE; i++) { + input_plaintext_reversed[i] = input_plaintext[ESP32C3_XTS_AES_DATA_UNIT_SIZE-i-1]; + } + + xts_encrypt(&aesdata, &aestweak, + xts_aes_encrypt, + xts_aes_decrypt, + tweak, ESP32C3_XTS_AES_DATA_UNIT_SIZE, output_ciphertext_reversed, input_plaintext_reversed); + + for (int i = 0; i < ESP32C3_XTS_AES_DATA_UNIT_SIZE; i++) { + output_ciphertext[i] = output_ciphertext_reversed[ESP32C3_XTS_AES_DATA_UNIT_SIZE-i-1]; + } + + memset(s->ciphertext, 0, ESP32C3_XTS_AES_PLAIN_REG_CNT * sizeof(uint32_t)); + memcpy(s->ciphertext, output_ciphertext + pad_left, linesize); +} + +static void esp32c3_xts_aes_decrypt(ESP32C3XtsAesState *s, uint32_t physical_address, uint8_t *data, uint32_t size) +{ + struct xts_aes_keys_ctx aesdata = {}; + struct xts_aes_keys_ctx aestweak = {}; + + uint8_t efuse_key[XTS_AES_KEY_SIZE]; + uint8_t tweak[16]; + + esp32c3_xts_aes_get_key(s, efuse_key); + + AES_set_encrypt_key(efuse_key, XTS_AES_KEY_SIZE / 2 * 8, &aesdata.enc); + AES_set_decrypt_key(efuse_key, XTS_AES_KEY_SIZE / 2 * 8, &aesdata.dec); + AES_set_encrypt_key(efuse_key + XTS_AES_KEY_SIZE / 2, XTS_AES_KEY_SIZE / 2 * 8, &aestweak.enc); + AES_set_decrypt_key(efuse_key + XTS_AES_KEY_SIZE / 2, XTS_AES_KEY_SIZE / 2 * 8, &aestweak.dec); + + uint8_t input_ciphertext[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + uint8_t input_ciphertext_reversed[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + uint8_t output_plaintext[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + uint8_t output_plaintext_reversed[ESP32C3_XTS_AES_DATA_UNIT_SIZE]; + + for (int i = 0; i < size; i += ESP32C3_XTS_AES_DATA_UNIT_SIZE) { + *((uint32_t *) tweak) = cpu_to_le32((physical_address + i) & ESP32S3_XTS_AES_TWEAK_VALUE); + memset(tweak + 4, 0, 12); + + memcpy(input_ciphertext, data + i, ESP32C3_XTS_AES_DATA_UNIT_SIZE); + for (int j = 0; j < ESP32C3_XTS_AES_DATA_UNIT_SIZE; j++) { + input_ciphertext_reversed[j] = input_ciphertext[ESP32C3_XTS_AES_DATA_UNIT_SIZE-j-1]; + } + + xts_decrypt(&aesdata, &aestweak, + xts_aes_encrypt, + xts_aes_decrypt, + tweak, ESP32C3_XTS_AES_DATA_UNIT_SIZE, output_plaintext_reversed, input_ciphertext_reversed); + + for (int j = 0; j < ESP32C3_XTS_AES_DATA_UNIT_SIZE; j++) { + output_plaintext[j] = output_plaintext_reversed[ESP32C3_XTS_AES_DATA_UNIT_SIZE-j-1]; + } + + memcpy(data + i, output_plaintext, ESP32C3_XTS_AES_DATA_UNIT_SIZE); + } +} + +static uint64_t esp32c3_xts_aes_read(void *opaque, hwaddr addr, unsigned int size) +{ + ESP32C3XtsAesState *s = ESP32C3_XTS_AES(opaque); + + uint64_t r = 0; + switch (addr) { + case A_XTS_AES_DATE_REG: + r = 0x20200111; + break; + + case A_XTS_AES_PLAIN_0_REG ... A_XTS_AES_PLAIN_7_REG: + r = s->plaintext[(addr - A_XTS_AES_PLAIN_0_REG) / sizeof(uint32_t)]; + break; + + case A_XTS_AES_LINESIZE_REG: + r = s->linesize; + break; + + case A_XTS_AES_DESTINATION_REG: + r = s->destination; + break; + + case A_XTS_AES_PHYSICAL_ADDRESS_REG: + r = s->physical_addr; + break; + + case A_XTS_AES_STATE_REG: + r = s->state; + break; + + default: +#if XTS_AES_WARNING + /* Other registers are not supported yet */ + warn_report("[XTS_AES] Unsupported read to %08lx\n", addr); +#endif + break; + } + +#if XTS_AES_DEBUG + info_report("[XTS_AES] Reading from %08lx (%08lx)\n", addr, r); +#endif + + return r; +} + + +static void esp32c3_xts_aes_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + ESP32C3XtsAesState *s = ESP32C3_XTS_AES(opaque); + + switch (addr) { + case A_XTS_AES_LINESIZE_REG: + s->linesize = FIELD_EX32(value, XTS_AES_LINESIZE_REG, XTS_AES_LINESIZE); + break; + + case A_XTS_AES_DESTINATION_REG: + s->destination = FIELD_EX32(value, XTS_AES_DESTINATION_REG, XTS_AES_DESTINATION); + break; + + case A_XTS_AES_PHYSICAL_ADDRESS_REG: + s->physical_addr = FIELD_EX32(value, XTS_AES_PHYSICAL_ADDRESS_REG, XTS_AES_PHYSICAL_ADDRESS); + if (s->physical_addr > 0x00FFFFFF) { + error_report("[XTS-AES] Physical Adress greater than 0x00FFFFFF"); + } + break; + + case A_XTS_AES_PLAIN_0_REG ... A_XTS_AES_PLAIN_7_REG: + s->plaintext[(addr - A_XTS_AES_PLAIN_0_REG) / sizeof(uint32_t)] = value; + break; + + case A_XTS_AES_TRIGGER_REG: + if (FIELD_EX32(value, XTS_AES_TRIGGER_REG, XTS_AES_TRIGGER) == 1) { + s->state = XTS_AES_BUSY; + esp32c3_xts_aes_encrypt(s); + s->state= XTS_AES_DONE; + } + break; + + case A_XTS_AES_RELEASE_REG: + if (FIELD_EX32(value, XTS_AES_RELEASE_REG, XTS_AES_RELEASE) == 1) { + // "Grant SPI1 access for the ciphertext" + s->state = XTS_AES_RELEASE; + } + break; + + case A_XTS_AES_DESTROY_REG: + FIELD_EX32(value, XTS_AES_DESTROY_REG, XTS_AES_DESTROY); + s->state = XTS_AES_IDLE; + memset(s->ciphertext, 0, ESP32C3_XTS_AES_PLAIN_REG_CNT * sizeof(uint32_t)); + break; + + default: +#if XTS_AES_WARNING + /* Other registers are not supported yet */ + warn_report("[XTS_AES] Unsupported write to %08lx (%08lx)\n", addr, value); +#endif + break; + } + +#if XTS_AES_DEBUG + info_report("[XTS_AES] Writing to %08lx (%08lx)\n", addr, value); +#endif + +} + +static const MemoryRegionOps esp32c3_xts_aes_ops = { + .read = esp32c3_xts_aes_read, + .write = esp32c3_xts_aes_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void esp32c3_xts_aes_reset(DeviceState *dev) +{ + ESP32C3XtsAesState *s = ESP32C3_XTS_AES(dev); + memset(s->plaintext, 0, ESP32C3_XTS_AES_PLAIN_REG_CNT * sizeof(uint32_t)); + memset(s->ciphertext, 0, ESP32C3_XTS_AES_PLAIN_REG_CNT * sizeof(uint32_t)); + s->state = XTS_AES_IDLE; + s->linesize = 0; + s->destination = 0; + s->physical_addr = 0; +} + +static void esp32c3_xts_aes_realize(DeviceState *dev, Error **errp) +{ + ESP32C3XtsAesState *s = ESP32C3_XTS_AES(dev); + + /* Make sure Efuse was set of issue an error */ + if (s->efuse == NULL) { + error_report("[XTS_AES] Efuse controller must be set!"); + } + + /* Make sure Clock was set or issue an error */ + if (s->clock == NULL) { + error_report("[XTS_AES] Clock controller must be set!"); + } +} + +static void esp32c3_xts_aes_init(Object *obj) +{ + ESP32C3XtsAesState *s = ESP32C3_XTS_AES(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &esp32c3_xts_aes_ops, s, + TYPE_ESP32C3_XTS_AES, ESP32C3_XTS_AES_REGS_SIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void esp32c3_xts_aes_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ESP32C3XtsAesClass* esp32c3_xts_aes = ESP32C3_XTS_AES_CLASS(klass); + + dc->realize = esp32c3_xts_aes_realize; + dc->legacy_reset = esp32c3_xts_aes_reset; + + esp32c3_xts_aes->is_ciphertext_spi_visible = esp32c3_xts_aes_is_ciphertext_spi_visible; + esp32c3_xts_aes->is_flash_enc_enabled = esp32c3_xts_aes_is_flash_enc_enabled; + esp32c3_xts_aes->is_manual_enc_enabled = esp32c3_xts_aes_is_manual_enc_enabled; + esp32c3_xts_aes->decrypt = esp32c3_xts_aes_decrypt; + esp32c3_xts_aes->read_ciphertext = esp32c3_xts_aes_read_ciphertext; +} + +static const TypeInfo esp32c3_xts_aes_info = { + .name = TYPE_ESP32C3_XTS_AES, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESP32C3XtsAesState), + .instance_init = esp32c3_xts_aes_init, + .class_init = esp32c3_xts_aes_class_init, + .class_size = sizeof(ESP32C3XtsAesClass) +}; + +static void esp32c3_xts_aes_register_types(void) +{ + type_register_static(&esp32c3_xts_aes_info); +} + +type_init(esp32c3_xts_aes_register_types) + diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 6d1b06d9f9..8b775501f8 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -168,6 +168,7 @@ if gcrypt.found() 'esp32c3_rsa.c', 'esp_ds.c', 'esp32c3_ds.c', + 'esp32c3_xts_aes.c' )) endif diff --git a/include/hw/misc/esp32c3_xts_aes.h b/include/hw/misc/esp32c3_xts_aes.h new file mode 100644 index 0000000000..95775b896f --- /dev/null +++ b/include/hw/misc/esp32c3_xts_aes.h @@ -0,0 +1,94 @@ +/* + * ESP32-C3 XTS-AES emulation + * + * Copyright (c) 2023 Espressif Systems (Shanghai) Co. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + + +#pragma once + +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/nvram/esp32c3_efuse.h" +#include "hw/riscv/esp32c3_clk.h" + +#define TYPE_ESP32C3_XTS_AES "misc.esp32c3.xts_aes" +#define ESP32C3_XTS_AES(obj) OBJECT_CHECK(ESP32C3XtsAesState, (obj), TYPE_ESP32C3_XTS_AES) +#define ESP32C3_XTS_AES_GET_CLASS(obj) OBJECT_GET_CLASS(ESP32C3XtsAesClass, obj, TYPE_ESP32C3_XTS_AES) +#define ESP32C3_XTS_AES_CLASS(klass) OBJECT_CLASS_CHECK(ESP32C3XtsAesClass, klass, TYPE_ESP32C3_XTS_AES) + +#define ESP32C3_XTS_AES_PLAIN_REG_CNT 8 +#define ESP32C3_XTS_AES_REGS_SIZE (0x60) + +/** + * @brief Status of the Manual Encryption block. + */ +typedef enum { + XTS_AES_IDLE = 0, + XTS_AES_BUSY = 1, + XTS_AES_DONE = 2, + XTS_AES_RELEASE = 3, +} ESP32C3XtsAesStatus; + +typedef struct ESP32C3XtsAesState { + SysBusDevice parent_obj; + MemoryRegion iomem; + + uint32_t plaintext[ESP32C3_XTS_AES_PLAIN_REG_CNT]; + uint32_t ciphertext[ESP32C3_XTS_AES_PLAIN_REG_CNT]; + uint32_t linesize; + uint32_t destination; + uint64_t physical_addr; + uint32_t state; + + ESP32C3ClockState *clock; + ESPEfuseState *efuse; +} ESP32C3XtsAesState; + +typedef struct ESP32C3XtsAesClass { + SysBusDeviceClass parent_class; + /* Virtual methods */ + bool (*is_ciphertext_spi_visible)(ESP32C3XtsAesState *s); + bool (*is_flash_enc_enabled)(ESP32C3XtsAesState *s); + bool (*is_manual_enc_enabled)(ESP32C3XtsAesState *s); + void (*read_ciphertext)(ESP32C3XtsAesState *s, uint32_t* spi_data_regs, uint32_t* spi_data_size, uint32_t* spi_addr, uint32_t* spi_addr_size); + void (*decrypt)(ESP32C3XtsAesState *s, uint32_t physical_address, uint8_t * data, uint32_t size); +} ESP32C3XtsAesClass; + +REG32(XTS_AES_PLAIN_0_REG, 0x0000) +REG32(XTS_AES_PLAIN_1_REG, 0x0004) +REG32(XTS_AES_PLAIN_2_REG, 0x0008) +REG32(XTS_AES_PLAIN_3_REG, 0x000C) +REG32(XTS_AES_PLAIN_4_REG, 0x0010) +REG32(XTS_AES_PLAIN_5_REG, 0x0014) +REG32(XTS_AES_PLAIN_6_REG, 0x0018) +REG32(XTS_AES_PLAIN_7_REG, 0x001C) + +REG32(XTS_AES_LINESIZE_REG, 0x0040) + FIELD(XTS_AES_LINESIZE_REG, XTS_AES_LINESIZE, 0, 1) + +REG32(XTS_AES_DESTINATION_REG, 0x0044) + FIELD(XTS_AES_DESTINATION_REG, XTS_AES_DESTINATION, 0, 1) + +REG32(XTS_AES_PHYSICAL_ADDRESS_REG, 0x0048) + FIELD(XTS_AES_PHYSICAL_ADDRESS_REG, XTS_AES_PHYSICAL_ADDRESS, 0, 30) + +REG32(XTS_AES_TRIGGER_REG, 0x004C) + FIELD(XTS_AES_TRIGGER_REG, XTS_AES_TRIGGER, 0, 1) + +REG32(XTS_AES_RELEASE_REG, 0x0050) + FIELD(XTS_AES_RELEASE_REG, XTS_AES_RELEASE, 0, 1) + +REG32(XTS_AES_DESTROY_REG, 0x0054) + FIELD(XTS_AES_DESTROY_REG, XTS_AES_DESTROY, 0, 1) + +REG32(XTS_AES_STATE_REG, 0x0058) + FIELD(XTS_AES_STATE_REG, XTS_AES_STATE, 0, 2) + +REG32(XTS_AES_DATE_REG, 0x005C) + FIELD(XTS_AES_DATE_REG, XTS_AES_DATE, 0, 30)