espressif: ESP32, ESP32S2 and ESP32C3 native flash encryption

Native flash encryption was added as option for Espressif chips and
added to the initialization process before MCUboot workflow.

Signed-off-by: Almir Okato <almir.okato@espressif.com>
diff --git a/boot/espressif/bootloader.conf b/boot/espressif/bootloader.conf
index c4b833a..f350262 100644
--- a/boot/espressif/bootloader.conf
+++ b/boot/espressif/bootloader.conf
@@ -31,6 +31,15 @@
 # CONFIG_SECURE_BOOT_V2_ENABLED=1
 # CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
 
+# Hardware Flash Encryption related options
+# CONFIG_SECURE_FLASH_ENC_ENABLED=1
+# CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=1
+# CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=1
+# CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=1
+# CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=1
+# CONFIG_SECURE_BOOT_ALLOW_JTAG=1
+# CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=1
+
 # Options for enabling eFuse emulation in Flash
 # CONFIG_EFUSE_VIRTUAL=1
 # CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH=1
diff --git a/boot/espressif/hal/CMakeLists.txt b/boot/espressif/hal/CMakeLists.txt
index 8e879a6..742e140 100644
--- a/boot/espressif/hal/CMakeLists.txt
+++ b/boot/espressif/hal/CMakeLists.txt
@@ -56,6 +56,7 @@
 set(hal_srcs
     ${src_dir}/bootloader_wdt.c
     ${src_dir}/secure_boot.c
+    ${src_dir}/flash_encrypt.c
     ${src_dir}/${MCUBOOT_TARGET}/bootloader_init.c
     ${esp_idf_dir}/components/hal/mpu_hal.c
     ${esp_idf_dir}/components/bootloader_support/src/bootloader_common_loader.c
@@ -67,11 +68,13 @@
     ${esp_idf_dir}/components/bootloader_support/src/bootloader_panic.c
     ${esp_idf_dir}/components/bootloader_support/src/bootloader_mem.c
     ${esp_idf_dir}/components/bootloader_support/src/bootloader_random.c
+    ${esp_idf_dir}/components/bootloader_support/src/bootloader_random_${MCUBOOT_TARGET}.c
     ${esp_idf_dir}/components/bootloader_support/src/bootloader_utility.c
     ${esp_idf_dir}/components/bootloader_support/src/esp_image_format.c
     ${esp_idf_dir}/components/bootloader_support/src/secure_boot_v2/secure_boot_signatures_bootloader.c
     ${esp_idf_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/bootloader_sha.c
     ${esp_idf_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/secure_boot_secure_features.c
+    ${esp_idf_dir}/components/bootloader_support/src/${MCUBOOT_TARGET}/flash_encryption_secure_features.c
     ${esp_idf_dir}/components/spi_flash/${MCUBOOT_TARGET}/spi_flash_rom_patch.c
     ${esp_idf_dir}/components/esp_hw_support/esp_clk.c
     ${esp_idf_dir}/components/esp_hw_support/port/${MCUBOOT_TARGET}/rtc_init.c
diff --git a/boot/espressif/hal/include/esp32/sdkconfig.h b/boot/espressif/hal/include/esp32/sdkconfig.h
index cb7d4e7..6e76b63 100644
--- a/boot/espressif/hal/include/esp32/sdkconfig.h
+++ b/boot/espressif/hal/include/esp32/sdkconfig.h
@@ -16,7 +16,7 @@
 #define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
 #define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
 #define CONFIG_BOOTLOADER_OFFSET_IN_FLASH 0x1000
-#define CONFIG_PARTITION_TABLE_OFFSET 0xE000
-#define CONFIG_EFUSE_VIRTUAL_OFFSET 0xE000
+#define CONFIG_PARTITION_TABLE_OFFSET 0x10000
+#define CONFIG_EFUSE_VIRTUAL_OFFSET 0x250000
 #define CONFIG_EFUSE_VIRTUAL_SIZE 0x2000
 #define CONFIG_EFUSE_MAX_BLK_LEN 192
diff --git a/boot/espressif/hal/include/esp32c3/sdkconfig.h b/boot/espressif/hal/include/esp32c3/sdkconfig.h
index f657725..f091a13 100644
--- a/boot/espressif/hal/include/esp32c3/sdkconfig.h
+++ b/boot/espressif/hal/include/esp32c3/sdkconfig.h
@@ -14,7 +14,7 @@
 #define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
 #define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
 #define CONFIG_BOOTLOADER_OFFSET_IN_FLASH 0x0000
-#define CONFIG_PARTITION_TABLE_OFFSET 0xE000
-#define CONFIG_EFUSE_VIRTUAL_OFFSET 0xE000
+#define CONFIG_PARTITION_TABLE_OFFSET 0x10000
+#define CONFIG_EFUSE_VIRTUAL_OFFSET 0x250000
 #define CONFIG_EFUSE_VIRTUAL_SIZE 0x2000
 #define CONFIG_EFUSE_MAX_BLK_LEN 256
diff --git a/boot/espressif/hal/include/esp32s2/sdkconfig.h b/boot/espressif/hal/include/esp32s2/sdkconfig.h
index 84601c8..ed61b9b 100644
--- a/boot/espressif/hal/include/esp32s2/sdkconfig.h
+++ b/boot/espressif/hal/include/esp32s2/sdkconfig.h
@@ -14,7 +14,7 @@
 #define CONFIG_BOOTLOADER_WDT_TIME_MS 9000
 #define CONFIG_ESP_CONSOLE_UART_BAUDRATE 115200
 #define CONFIG_BOOTLOADER_OFFSET_IN_FLASH 0x1000
-#define CONFIG_PARTITION_TABLE_OFFSET 0xE000
-#define CONFIG_EFUSE_VIRTUAL_OFFSET 0xE000
+#define CONFIG_PARTITION_TABLE_OFFSET 0x10000
+#define CONFIG_EFUSE_VIRTUAL_OFFSET 0x250000
 #define CONFIG_EFUSE_VIRTUAL_SIZE 0x2000
 #define CONFIG_EFUSE_MAX_BLK_LEN 256
diff --git a/boot/espressif/hal/include/esp_mcuboot_image.h b/boot/espressif/hal/include/esp_mcuboot_image.h
new file mode 100644
index 0000000..baccf08
--- /dev/null
+++ b/boot/espressif/hal/include/esp_mcuboot_image.h
@@ -0,0 +1,26 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+/* Magic is derived from sha256sum of the string "espmcuboot"
+ * The application header magic must match this number
+ */
+#define ESP_LOAD_HEADER_MAGIC 0xace637d3
+
+/* Load header that should be a part of application image
+ * for MCUboot-Espressif port booting.
+ */
+typedef struct esp_image_load_header {
+    uint32_t header_magic;          /* Magic for load header */
+    uint32_t entry_addr;            /* Application entry address */
+    uint32_t iram_dest_addr;        /* Destination address(VMA) for IRAM region */
+    uint32_t iram_flash_offset;     /* Flash offset(LMA) for start of IRAM region */
+    uint32_t iram_size;             /* Size of IRAM region */
+    uint32_t dram_dest_addr;        /* Destination address(VMA) for DRAM region */
+    uint32_t dram_flash_offset;     /* Flash offset(LMA) for start of DRAM region */
+    uint32_t dram_size;             /* Size of DRAM region */
+} esp_image_load_header_t;
diff --git a/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h b/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h
index aada8e3..abbbd97 100644
--- a/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h
+++ b/boot/espressif/hal/include/mcuboot_config/mcuboot_config.h
@@ -8,19 +8,6 @@
 #define __MCUBOOT_CONFIG_H__
 
 /*
- * Template configuration file for MCUboot.
- *
- * When porting MCUboot to a new target, copy it somewhere that your
- * include path can find it as mcuboot_config/mcuboot_config.h, and
- * make adjustments to suit your platform.
- *
- * For examples, see:
- *
- * boot/zephyr/include/mcuboot_config/mcuboot_config.h
- * boot/mynewt/mcuboot_config/include/mcuboot_config/mcuboot_config.h
- */
-
-/*
  * Signature types
  *
  * You must choose exactly one signature type - check bootloader.conf
@@ -41,6 +28,11 @@
 #elif defined(CONFIG_ESP_SIGN_ED25519)
 #define MCUBOOT_SIGN_ED25519
 #endif
+
+#if defined(CONFIG_SECURE_FLASH_ENC_ENABLED)
+#define MCUBOOT_BOOT_MAX_ALIGN 32
+#endif
+
 /*
  * Upgrade mode
  *
@@ -132,6 +124,7 @@
  *    MCUBOOT_LOG_ERR > MCUBOOT_LOG_WRN > MCUBOOT_LOG_INF > MCUBOOT_LOG_DBG
  */
 #define MCUBOOT_HAVE_LOGGING 1
+/* #define MCUBOOT_LOG_LEVEL MCUBOOT_LOG_LEVEL_INFO */
 
 /*
  * Assertions
diff --git a/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h b/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h
index f6a16a2..130f30f 100644
--- a/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h
+++ b/boot/espressif/hal/include/mcuboot_config/mcuboot_logging.h
@@ -7,6 +7,7 @@
 #pragma once
 
 #include "sdkconfig.h"
+#include "mcuboot_config.h"
 
 extern int ets_printf(const char *fmt, ...);
 
diff --git a/boot/espressif/hal/src/flash_encrypt.c b/boot/espressif/hal/src/flash_encrypt.c
new file mode 100644
index 0000000..143571b
--- /dev/null
+++ b/boot/espressif/hal/src/flash_encrypt.c
@@ -0,0 +1,351 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <strings.h>
+#include "bootloader_flash_priv.h"
+#include "bootloader_random.h"
+#include "esp_image_format.h"
+#include "esp_flash_encrypt.h"
+#include "esp_flash_partitions.h"
+#include "esp_secure_boot.h"
+#include "esp_efuse.h"
+#include "esp_efuse_table.h"
+#include "esp_log.h"
+#include "hal/wdt_hal.h"
+
+#include "esp_mcuboot_image.h"
+
+#if CONFIG_IDF_TARGET_ESP32
+#define CRYPT_CNT ESP_EFUSE_FLASH_CRYPT_CNT
+#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT
+#else
+#define CRYPT_CNT ESP_EFUSE_SPI_BOOT_CRYPT_CNT
+#define WR_DIS_CRYPT_CNT ESP_EFUSE_WR_DIS_SPI_BOOT_CRYPT_CNT
+#endif
+
+/* This file implements FLASH ENCRYPTION related APIs to perform
+ * various operations such as programming necessary flash encryption
+ * eFuses, detect whether flash encryption is enabled (by reading eFuse)
+ * and if required encrypt the partitions in flash memory
+ */
+
+static const char *TAG = "flash_encrypt";
+
+/* Static functions for stages of flash encryption */
+static esp_err_t initialise_flash_encryption(void);
+static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis) __attribute__((unused));
+static esp_err_t encrypt_bootloader(void);
+static esp_err_t encrypt_primary_slot(void);
+
+esp_err_t esp_flash_encrypt_check_and_update(void)
+{
+    size_t flash_crypt_cnt = 0;
+    esp_efuse_read_field_cnt(CRYPT_CNT, &flash_crypt_cnt);
+    bool flash_crypt_wr_dis = esp_efuse_read_field_bit(WR_DIS_CRYPT_CNT);
+
+    ESP_LOGV(TAG, "CRYPT_CNT %d, write protection %d", flash_crypt_cnt, flash_crypt_wr_dis);
+
+    if (flash_crypt_cnt % 2 == 1) {
+        /* Flash is already encrypted */
+        int left = (CRYPT_CNT[0]->bit_count - flash_crypt_cnt) / 2;
+        if (flash_crypt_wr_dis) {
+            left = 0; /* can't update FLASH_CRYPT_CNT, no more flashes */
+        }
+        ESP_LOGI(TAG, "flash encryption is enabled (%d plaintext flashes left)", left);
+        return ESP_OK;
+    } else {
+#ifndef CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
+        /* Flash is not encrypted, so encrypt it! */
+        return encrypt_flash_contents(flash_crypt_cnt, flash_crypt_wr_dis);
+#else
+        ESP_LOGE(TAG, "flash encryption is not enabled, and SECURE_FLASH_REQUIRE_ALREADY_ENABLED "
+                      "is set, refusing to boot.");
+        return ESP_ERR_INVALID_STATE;
+#endif // CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED
+    }
+}
+
+static esp_err_t check_and_generate_encryption_keys(void)
+{
+    size_t key_size = 32;
+#ifdef CONFIG_IDF_TARGET_ESP32
+    enum { BLOCKS_NEEDED = 1 };
+    esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
+        ESP_EFUSE_KEY_PURPOSE_FLASH_ENCRYPTION,
+    };
+    esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK_ENCRYPT_FLASH);
+    if (coding_scheme != EFUSE_CODING_SCHEME_NONE && coding_scheme != EFUSE_CODING_SCHEME_3_4) {
+        ESP_LOGE(TAG, "Unknown/unsupported CODING_SCHEME value 0x%x", coding_scheme);
+        return ESP_ERR_NOT_SUPPORTED;
+    }
+    if (coding_scheme == EFUSE_CODING_SCHEME_3_4) {
+        key_size = 24;
+    }
+#else
+#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_AES256
+    enum { BLOCKS_NEEDED = 2 };
+    esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
+        ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1,
+        ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2,
+    };
+    if (esp_efuse_find_purpose(ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY, NULL)) {
+        ESP_LOGE(TAG, "XTS_AES_128_KEY is already in use, XTS_AES_256_KEY_1/2 can not be used");
+        return ESP_ERR_INVALID_STATE;
+    }
+#else
+    enum { BLOCKS_NEEDED = 1 };
+    esp_efuse_purpose_t purposes[BLOCKS_NEEDED] = {
+        ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY,
+    };
+#endif // CONFIG_SECURE_FLASH_ENCRYPTION_AES256
+#endif // CONFIG_IDF_TARGET_ESP32
+
+    /* Initialize all efuse block entries to invalid (max) value */
+    esp_efuse_block_t blocks[BLOCKS_NEEDED] = {[0 ... BLOCKS_NEEDED-1] = EFUSE_BLK_KEY_MAX};
+    bool has_key = true;
+    for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
+        bool tmp_has_key = esp_efuse_find_purpose(purposes[i], &blocks[i]);
+        if (tmp_has_key) { // For ESP32: esp_efuse_find_purpose() always returns True, need to check whether the key block is used or not.
+            tmp_has_key &= !esp_efuse_key_block_unused(blocks[i]);
+        }
+        if (i == 1 && tmp_has_key != has_key) {
+            ESP_LOGE(TAG, "Invalid efuse key blocks: Both AES-256 key blocks must be set.");
+            return ESP_ERR_INVALID_STATE;
+        }
+        has_key &= tmp_has_key;
+    }
+
+    if (!has_key) {
+        /* Generate key */
+        uint8_t keys[BLOCKS_NEEDED][32] = { 0 };
+        ESP_LOGI(TAG, "Generating new flash encryption key...");
+        for (unsigned i = 0; i < BLOCKS_NEEDED; ++i) {
+            bootloader_fill_random(keys[i], key_size);
+        }
+        ESP_LOGD(TAG, "Key generation complete");
+
+        esp_err_t err = esp_efuse_write_keys(purposes, keys, BLOCKS_NEEDED);
+        if (err != ESP_OK) {
+            if (err == ESP_ERR_NOT_ENOUGH_UNUSED_KEY_BLOCKS) {
+                ESP_LOGE(TAG, "Not enough free efuse key blocks (need %d) to continue", BLOCKS_NEEDED);
+            } else {
+                ESP_LOGE(TAG, "Failed to write efuse block with purpose (err=0x%x). Can't continue.", err);
+            }
+            return err;
+        }
+    } else {
+        for (unsigned i = 0; i < BLOCKS_NEEDED; i++) {
+            if (!esp_efuse_get_key_dis_write(blocks[i])
+                || !esp_efuse_get_key_dis_read(blocks[i])
+                || !esp_efuse_get_keypurpose_dis_write(blocks[i])) { // For ESP32: no keypurpose, it returns always True.
+                ESP_LOGE(TAG, "Invalid key state, check read&write protection for key and keypurpose(if exists)");
+                return ESP_ERR_INVALID_STATE;
+            }
+        }
+        ESP_LOGI(TAG, "Using pre-loaded flash encryption key in efuse");
+    }
+    return ESP_OK;
+}
+
+static esp_err_t initialise_flash_encryption(void)
+{
+    esp_efuse_batch_write_begin(); /* Batch all efuse writes at the end of this function */
+
+    /* Before first flash encryption pass, need to initialise key & crypto config */
+    esp_err_t err = check_and_generate_encryption_keys();
+    if (err != ESP_OK) {
+        esp_efuse_batch_write_cancel();
+        return err;
+    }
+
+    err = esp_flash_encryption_enable_secure_features();
+    if (err != ESP_OK) {
+        esp_efuse_batch_write_cancel();
+        return err;
+    }
+
+    err = esp_efuse_batch_write_commit();
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Error programming security eFuses (err=0x%x).", err);
+        return err;
+    }
+
+    return ESP_OK;
+}
+
+/* Encrypt all flash data that should be encrypted */
+static esp_err_t encrypt_flash_contents(uint32_t flash_crypt_cnt, bool flash_crypt_wr_dis)
+{
+    esp_err_t err;
+
+    /* If all flash_crypt_cnt bits are burned or write-disabled, the
+       device can't re-encrypt itself. */
+    if (flash_crypt_wr_dis || flash_crypt_cnt == CRYPT_CNT[0]->bit_count) {
+        ESP_LOGE(TAG, "Cannot re-encrypt data CRYPT_CNT %d write disabled %d", flash_crypt_cnt, flash_crypt_wr_dis);
+        return ESP_FAIL;
+    }
+
+    if (flash_crypt_cnt == 0) {
+        /* Very first flash of encrypted data: generate keys, etc. */
+        err = initialise_flash_encryption();
+        if (err != ESP_OK) {
+            return err;
+        }
+    }
+
+    err = encrypt_bootloader();
+    if (err != ESP_OK) {
+        return err;
+    }
+
+    /* If the primary slot executable application is not encrypted,
+     * then encrypt it
+     */
+    err = encrypt_primary_slot();
+    if (err != ESP_OK) {
+        return err;
+    }
+
+    /* Unconditionally encrypts remaining regions
+     * This will need changes when implementing multi-slot support
+     */
+    ESP_LOGI(TAG, "Encrypting remaining flash...");
+    uint32_t region_addr = CONFIG_ESP_APPLICATION_SECONDARY_START_ADDRESS;
+    size_t region_size = CONFIG_ESP_APPLICATION_SIZE;
+    err = esp_flash_encrypt_region(region_addr, region_size);
+    if (err != ESP_OK) {
+        return err;
+    }
+    region_addr = CONFIG_ESP_SCRATCH_OFFSET;
+    region_size = CONFIG_ESP_SCRATCH_SIZE;
+    err = esp_flash_encrypt_region(region_addr, region_size);
+    if (err != ESP_OK) {
+        return err;
+    }
+
+#ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE
+    // Go straight to max, permanently enabled
+    ESP_LOGI(TAG, "Setting CRYPT_CNT for permanent encryption");
+    size_t new_flash_crypt_cnt = CRYPT_CNT[0]->bit_count - flash_crypt_cnt;
+#else
+    /* Set least significant 0-bit in flash_crypt_cnt */
+    size_t new_flash_crypt_cnt = 1;
+#endif
+    ESP_LOGD(TAG, "CRYPT_CNT %d -> %d", flash_crypt_cnt, new_flash_crypt_cnt);
+    err = esp_efuse_write_field_cnt(CRYPT_CNT, new_flash_crypt_cnt);
+
+    ESP_LOGI(TAG, "Flash encryption completed");
+
+    return ESP_OK;
+}
+
+static esp_err_t encrypt_bootloader(void)
+{
+    esp_err_t err;
+    uint32_t image_length;
+    /* Check for plaintext bootloader (verification will fail if it's already encrypted) */
+    if (esp_image_verify_bootloader(&image_length) == ESP_OK) {
+        ESP_LOGI(TAG, "Encrypting bootloader...");
+
+        err = esp_flash_encrypt_region(ESP_BOOTLOADER_OFFSET, CONFIG_ESP_BOOTLOADER_SIZE);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to encrypt bootloader in place: 0x%x", err);
+            return err;
+        }
+        ESP_LOGI(TAG, "Bootloader encrypted successfully");
+    } else {
+        ESP_LOGW(TAG, "No valid bootloader was found");
+        return ESP_ERR_NOT_FOUND;
+    }
+
+    return ESP_OK;
+}
+
+static esp_err_t verify_img_header(uint32_t addr, const esp_image_load_header_t *image, bool silent)
+{
+    esp_err_t err = ESP_OK;
+
+    if (image->header_magic != ESP_LOAD_HEADER_MAGIC) {
+        if (!silent) {
+            ESP_LOGE(TAG, "image at 0x%x has invalid magic byte",
+                     addr);
+        }
+        err = ESP_ERR_IMAGE_INVALID;
+    }
+
+    return err;
+}
+
+static esp_err_t encrypt_primary_slot(void)
+{
+    esp_err_t err;
+
+    esp_image_load_header_t img_header;
+
+    /* Check if the slot is plaintext or encrypted, 0x20 offset is for skipping
+     * MCUboot header
+     */
+    err = bootloader_flash_read(CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS + 0x20,
+                                &img_header, sizeof(esp_image_load_header_t), true);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to read slot img header");
+        return err;
+    } else {
+        err = verify_img_header(CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS,
+                                &img_header, true);
+    }
+
+    if (err == ESP_OK) {
+        ESP_LOGI(TAG, "Encrypting primary slot...");
+
+        err = esp_flash_encrypt_region(CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS,
+                                       CONFIG_ESP_APPLICATION_SIZE);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to encrypt slot in place: 0x%x", err);
+            return err;
+        }
+    } else {
+        ESP_LOGW(TAG, "Slot already encrypted or no valid image was found");
+    }
+
+    return ESP_OK;
+}
+
+esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
+{
+    esp_err_t err;
+    uint32_t buf[FLASH_SECTOR_SIZE / sizeof(uint32_t)];
+
+    if (src_addr % FLASH_SECTOR_SIZE != 0) {
+        ESP_LOGE(TAG, "esp_flash_encrypt_region bad src_addr 0x%x", src_addr);
+        return ESP_FAIL;
+    }
+
+    wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
+    for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
+        wdt_hal_write_protect_disable(&rtc_wdt_ctx);
+        wdt_hal_feed(&rtc_wdt_ctx);
+        wdt_hal_write_protect_enable(&rtc_wdt_ctx);
+        uint32_t sec_start = i + src_addr;
+        err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, true);
+        if (err != ESP_OK) {
+            goto flash_failed;
+        }
+        err = bootloader_flash_erase_sector(sec_start / FLASH_SECTOR_SIZE);
+        if (err != ESP_OK) {
+            goto flash_failed;
+        }
+        err = bootloader_flash_write(sec_start, buf, FLASH_SECTOR_SIZE, true);
+        if (err != ESP_OK) {
+            goto flash_failed;
+        }
+    }
+    return ESP_OK;
+
+flash_failed:
+    ESP_LOGE(TAG, "flash operation failed: 0x%x", err);
+    return err;
+}
diff --git a/boot/espressif/main.c b/boot/espressif/main.c
index bd1d04d..083efc5 100644
--- a/boot/espressif/main.c
+++ b/boot/espressif/main.c
@@ -10,6 +10,8 @@
 #include <bootutil/image.h>
 
 #include "bootloader_init.h"
+#include "bootloader_utility.h"
+#include "bootloader_random.h"
 
 #if defined(CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH) || defined(CONFIG_SECURE_BOOT)
 #include "esp_efuse.h"
@@ -17,6 +19,9 @@
 #ifdef CONFIG_SECURE_BOOT
 #include "esp_secure_boot.h"
 #endif
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+#include "esp_flash_encrypt.h"
+#endif
 
 #include "esp_loader.h"
 #include "os/os_malloc.h"
@@ -37,12 +42,31 @@
 {
     bootloader_init();
 
+    BOOT_LOG_INF("Enabling RNG early entropy source...");
+    bootloader_random_enable();
+
+    /* Rough steps for a first boot when Secure Boot and/or Flash Encryption are still disabled on device:
+     * Secure Boot:
+     *   1) Calculate the SHA-256 hash digest of the public key and write to EFUSE.
+     *   2) Validate the application images and prepare the booting process.
+     *   3) Burn EFUSE to enable Secure Boot V2 (ABS_DONE_0).
+     * Flash Encryption:
+     *   4) Generate Flash Encryption key and write to EFUSE.
+     *   5) Encrypt flash in-place including bootloader, image primary/secondary slot and scratch.
+     *   6) Burn EFUSE to enable Flash Encryption.
+     *   7) Reset system to ensure Flash Encryption cache resets properly.
+     */
+
 #ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
     BOOT_LOG_WRN("eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
     esp_efuse_init_virtual_mode_in_flash(CONFIG_EFUSE_VIRTUAL_OFFSET, CONFIG_EFUSE_VIRTUAL_SIZE);
 #endif
 
 #ifdef CONFIG_SECURE_BOOT
+    /* Steps 1 (see above for full description):
+     *   1) Compute digest of the public key.
+     */
+
     BOOT_LOG_INF("enabling secure boot v2...");
 
     bool sb_hw_enabled = esp_secure_boot_enabled();
@@ -66,8 +90,13 @@
     os_heap_init();
 
     struct boot_rsp rsp;
+
     fih_int fih_rc = FIH_FAILURE;
 
+    /* Step 2 (see above for full description):
+     *   2) MCUboot validates the application images and prepares the booting process.
+     */
+
     FIH_CALL(boot_go, fih_rc, &rsp);
 
     if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
@@ -79,6 +108,10 @@
     }
 
 #ifdef CONFIG_SECURE_BOOT
+    /* Step 3 (see above for full description):
+     *   3) Burn EFUSE to enable Secure Boot V2.
+     */
+
     if (!sb_hw_enabled) {
         BOOT_LOG_INF("blowing secure boot efuse...");
         esp_err_t err;
@@ -103,6 +136,35 @@
     }
 #endif
 
+#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED
+    /* Step 4, 5 & 6 (see above for full description):
+     *   4) Generate Flash Encryption key and write to EFUSE.
+     *   5) Encrypt flash in-place including bootloader, image primary/secondary slot and scratch.
+     *   6) Burn EFUSE to enable flash encryption
+     */
+
+    int rc;
+
+    BOOT_LOG_INF("Checking flash encryption...");
+    bool flash_encryption_enabled = esp_flash_encryption_enabled();
+    rc = esp_flash_encrypt_check_and_update();
+    if (rc != ESP_OK) {
+        BOOT_LOG_ERR("Flash encryption check failed (%d).", rc);
+        FIH_PANIC;
+    }
+
+    /* Step 7 (see above for full description):
+     *   7) Reset system to ensure flash encryption cache resets properly.
+     */
+    if (!flash_encryption_enabled && esp_flash_encryption_enabled()) {
+        BOOT_LOG_INF("Resetting with flash encryption enabled...");
+        bootloader_reset();
+    }
+#endif
+
+    BOOT_LOG_INF("Disabling RNG early entropy source...");
+    bootloader_random_disable();
+
     do_boot(&rsp);
 
     while(1);
diff --git a/boot/espressif/port/esp32/ld/bootloader.ld b/boot/espressif/port/esp32/ld/bootloader.ld
index 8249181..9933bd3 100644
--- a/boot/espressif/port/esp32/ld/bootloader.ld
+++ b/boot/espressif/port/esp32/ld/bootloader.ld
@@ -12,9 +12,9 @@
 
 MEMORY
 {
-  iram_seg (RWX) :                  org = 0x40093000, len = 0x9000
-  iram_loader_seg (RWX) :           org = 0x4009C000, len = 0x4000
-  dram_seg (RW) :                   org = 0x3FFF5000, len = 0x8000
+  iram_seg (RWX) :                  org = 0x40093000, len = 0x8800
+  iram_loader_seg (RWX) :           org = 0x4009B800, len = 0x4800
+  dram_seg (RW) :                   org = 0x3FFF5000, len = 0x8900
 }
 
 /*  Default entry point:  */
diff --git a/boot/espressif/port/esp32c3/ld/bootloader.ld b/boot/espressif/port/esp32c3/ld/bootloader.ld
index 61dd412..c627cb9 100644
--- a/boot/espressif/port/esp32c3/ld/bootloader.ld
+++ b/boot/espressif/port/esp32c3/ld/bootloader.ld
@@ -14,7 +14,7 @@
 {
   iram_seg (RWX) :                  org = 0x403C8000, len = 0x8000
   iram_loader_seg (RWX) :           org = 0x403D0000, len = 0x4800
-  dram_seg (RW) :                   org = 0x3FCD5000, len = 0x8800
+  dram_seg (RW) :                   org = 0x3FCD5000, len = 0x8C00
 }
 
 /*  Default entry point:  */
diff --git a/boot/espressif/port/esp32s2/ld/bootloader.ld b/boot/espressif/port/esp32s2/ld/bootloader.ld
index d01e7a5..3521894 100644
--- a/boot/espressif/port/esp32s2/ld/bootloader.ld
+++ b/boot/espressif/port/esp32s2/ld/bootloader.ld
@@ -9,12 +9,12 @@
  * The main purpose is to make sure the bootloader can load into main memory
  * without overwriting itself.
  */
- 
+
 MEMORY
 {
   iram_seg (RWX) :                  org = 0x40048000, len = 0x8000
   iram_loader_seg (RWX) :           org = 0x40050000, len = 0x5000
-  dram_seg (RW) :                   org = 0x3FFE5000, len = 0x8000
+  dram_seg (RW) :                   org = 0x3FFE5000, len = 0x8E00
 }
 
 /*  Default entry point:  */
diff --git a/boot/espressif/port/esp_loader.c b/boot/espressif/port/esp_loader.c
index 9e6aef6..f2f7d87 100644
--- a/boot/espressif/port/esp_loader.c
+++ b/boot/espressif/port/esp_loader.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -10,6 +10,7 @@
 #include <bootutil/fault_injection_hardening.h>
 
 #include "bootloader_flash_priv.h"
+#include "esp_flash_encrypt.h"
 #include "soc/soc_memory_layout.h"
 
 #if CONFIG_IDF_TARGET_ESP32
@@ -20,24 +21,10 @@
 #include "esp32c3/rom/uart.h"
 #endif
 
+#include "esp_mcuboot_image.h"
 #include "esp_loader.h"
 #include "flash_map_backend/flash_map_backend.h"
 
-#define ESP_LOAD_HEADER_MAGIC 0xace637d3   /* Magic is derived from sha256sum of espmcuboot */
-
-/*
- * Load header that should be a part of application image.
- */
-typedef struct image_load_header {
-    uint32_t header_magic;          /* Magic for load header */
-    uint32_t entry_addr;            /* Application entry address */
-    uint32_t iram_dest_addr;        /* Destination address(VMA) for IRAM region */
-    uint32_t iram_flash_offset;     /* Flash offset(LMA) for start of IRAM region */
-    uint32_t iram_size;             /* Size of IRAM region */
-    uint32_t dram_dest_addr;        /* Destination address(VMA) for DRAM region */
-    uint32_t dram_flash_offset;     /* Flash offset(LMA) for start of DRAM region */
-    uint32_t dram_size;             /* Size of DRAM region */
-} image_load_header_t;
 
 static int load_segment(const struct flash_area *fap, uint32_t data_addr, uint32_t data_len, uint32_t load_addr)
 {
@@ -57,16 +44,15 @@
     int area_id;
     int rc;
 
-    image_load_header_t load_header = {0};
-
     area_id = flash_area_id_from_image_slot(slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
         BOOT_LOG_ERR("%s: flash_area_open failed with %d", __func__, rc);
     }
 
-    const uint32_t *data = (const uint32_t *)bootloader_mmap((fap->fa_off + hdr_offset), sizeof(image_load_header_t));
-    memcpy((void *)&load_header, data, sizeof(image_load_header_t));
+    const uint32_t *data = (const uint32_t *)bootloader_mmap((fap->fa_off + hdr_offset), sizeof(esp_image_load_header_t));
+    esp_image_load_header_t load_header = {0};
+    memcpy((void *)&load_header, data, sizeof(esp_image_load_header_t));
     bootloader_munmap(data);
 
     if (load_header.header_magic != ESP_LOAD_HEADER_MAGIC) {
diff --git a/boot/espressif/port/esp_mcuboot.c b/boot/espressif/port/esp_mcuboot.c
index 4dd03b9..5cda2ae 100644
--- a/boot/espressif/port/esp_mcuboot.c
+++ b/boot/espressif/port/esp_mcuboot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -11,8 +11,10 @@
 #include <bootutil/bootutil.h>
 #include <bootutil/bootutil_log.h>
 
+#include "sdkconfig.h"
 #include "esp_err.h"
 #include "bootloader_flash_priv.h"
+#include "esp_flash_encrypt.h"
 
 #include "flash_map_backend/flash_map_backend.h"
 #include "sysflash/sysflash.h"
@@ -45,7 +47,7 @@
 
 _Static_assert(IS_ALIGNED(FLASH_BUFFER_SIZE, 4), "Buffer size for SPI Flash operations must be 4-byte aligned.");
 
-#define BOOTLOADER_START_ADDRESS 0x1000
+#define BOOTLOADER_START_ADDRESS CONFIG_BOOTLOADER_OFFSET_IN_FLASH
 #define BOOTLOADER_SIZE CONFIG_ESP_BOOTLOADER_SIZE
 #define APPLICATION_PRIMARY_START_ADDRESS CONFIG_ESP_APPLICATION_PRIMARY_START_ADDRESS
 #define APPLICATION_SECONDARY_START_ADDRESS CONFIG_ESP_APPLICATION_SECONDARY_START_ADDRESS
@@ -196,10 +198,12 @@
         return -1;
     }
 
+    bool flash_encryption_enabled = esp_flash_encryption_enabled();
+
     const uint32_t start_addr = fa->fa_off + off;
     BOOT_LOG_DBG("%s: Addr: 0x%08x Length: %d", __func__, (int)start_addr, (int)len);
 
-    if (bootloader_flash_write(start_addr, (void *)src, len, false) != ESP_OK) {
+    if (bootloader_flash_write(start_addr, (void *)src, len, flash_encryption_enabled) != ESP_OK) {
         BOOT_LOG_ERR("%s: Flash write failed", __func__);
         return -1;
     }
@@ -241,7 +245,18 @@
 
 uint32_t flash_area_align(const struct flash_area *area)
 {
-    return 4;
+    static size_t align = 0;
+
+    if (align == 0) {
+        bool flash_encryption_enabled = esp_flash_encryption_enabled();
+
+        if (flash_encryption_enabled) {
+            align = 32;
+        } else {
+            align = 4;
+        }
+    }
+    return align;
 }
 
 uint8_t flash_area_erased_val(const struct flash_area *area)
diff --git a/boot/espressif/secureboot-sign-ec256.conf b/boot/espressif/secureboot-sign-ec256.conf
index cbd588d..98894fa 100644
--- a/boot/espressif/secureboot-sign-ec256.conf
+++ b/boot/espressif/secureboot-sign-ec256.conf
@@ -2,11 +2,19 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
 CONFIG_SECURE_SIGNED_ON_BOOT=1
 CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
 CONFIG_SECURE_BOOT=1
 CONFIG_SECURE_BOOT_V2_ENABLED=1
 CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
 CONFIG_ESP_SIGN_KEY_FILE=root-ec-p256.pem
 CONFIG_ESP_USE_TINYCRYPT=1
 CONFIG_ESP_SIGN_EC256=1
diff --git a/boot/espressif/secureboot-sign-ed25519.conf b/boot/espressif/secureboot-sign-ed25519.conf
index a086fb6..67e6dcd 100644
--- a/boot/espressif/secureboot-sign-ed25519.conf
+++ b/boot/espressif/secureboot-sign-ed25519.conf
@@ -2,11 +2,19 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
 CONFIG_SECURE_SIGNED_ON_BOOT=1
 CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
 CONFIG_SECURE_BOOT=1
 CONFIG_SECURE_BOOT_V2_ENABLED=1
 CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
 CONFIG_ESP_SIGN_KEY_FILE=root-ed25519.pem
 CONFIG_ESP_USE_TINYCRYPT=1
 CONFIG_ESP_SIGN_ED25519=1
diff --git a/boot/espressif/secureboot-sign-rsa2048.conf b/boot/espressif/secureboot-sign-rsa2048.conf
index a0f5464..e5888f7 100644
--- a/boot/espressif/secureboot-sign-rsa2048.conf
+++ b/boot/espressif/secureboot-sign-rsa2048.conf
@@ -2,11 +2,19 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
 CONFIG_SECURE_SIGNED_ON_BOOT=1
 CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
 CONFIG_SECURE_BOOT=1
 CONFIG_SECURE_BOOT_V2_ENABLED=1
 CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
 CONFIG_ESP_SIGN_KEY_FILE=root-rsa-2048.pem
 CONFIG_ESP_USE_MBEDTLS=1
 CONFIG_ESP_SIGN_RSA=1
diff --git a/boot/espressif/secureboot-sign-rsa3072.conf b/boot/espressif/secureboot-sign-rsa3072.conf
index 0aa6be7..66825e0 100644
--- a/boot/espressif/secureboot-sign-rsa3072.conf
+++ b/boot/espressif/secureboot-sign-rsa3072.conf
@@ -2,11 +2,19 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
+# ATTENTION:
+# This configuration file targets the building for CI environment and contains
+# a set of definitions to resemble a bootloader image for RELEASE environment.
+# Running the generated firmware image may result in irreversible operations
+# to the chip!
+
 CONFIG_SECURE_SIGNED_ON_BOOT=1
 CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME=1
 CONFIG_SECURE_BOOT=1
 CONFIG_SECURE_BOOT_V2_ENABLED=1
 CONFIG_SECURE_BOOT_SUPPORTS_RSA=1
+CONFIG_SECURE_FLASH_ENC_ENABLED=1
+CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=1
 CONFIG_ESP_SIGN_KEY_FILE=root-rsa-3072.pem
 CONFIG_ESP_USE_MBEDTLS=1
 CONFIG_ESP_SIGN_RSA=1