From d008c47dac652c0cc7593b04c9b219c9ffd6c30e Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Thu, 5 Sep 2019 18:45:45 +0800 Subject: [PATCH] esp_flash: add support for encrypted read and write Using legacy implementation. --- components/spi_flash/esp_flash_api.c | 44 ++++++++----- components/spi_flash/include/esp_flash.h | 21 ++++++- .../spi_flash/test/test_flash_encryption.c | 62 +++++++++++++++++++ 3 files changed, 111 insertions(+), 16 deletions(-) diff --git a/components/spi_flash/esp_flash_api.c b/components/spi_flash/esp_flash_api.c index 146ebd12f8..e45f906abc 100644 --- a/components/spi_flash/esp_flash_api.c +++ b/components/spi_flash/esp_flash_api.c @@ -569,28 +569,27 @@ esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint3 return err; } +//currently the legacy implementation is used, from flash_ops.c +esp_err_t spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t size); + esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length) { - VERIFY_OP(write_encrypted); - if (((memspi_host_data_t*)chip->host->driver_data)->spi != 0) { - // Encrypted operations have to use SPI0 - return ESP_ERR_FLASH_UNSUPPORTED_HOST; + /* + * Since currently this feature is supported only by the hardware, there + * is no way to support non-standard chips. We use the legacy + * implementation and skip the chip and driver layers. + */ + if (chip == NULL) { + chip = esp_flash_default_chip; + } else if (chip != esp_flash_default_chip) { + return ESP_ERR_NOT_SUPPORTED; } if (buffer == NULL || address > chip->size || address+length > chip->size) { return ESP_ERR_INVALID_ARG; } - - esp_err_t err = spiflash_start(chip); - if (err != ESP_OK) { - return err; - } - - err = chip->chip_drv->write_encrypted(chip, buffer, address, length); - - return spiflash_end(chip, err); + return spi_flash_write_encrypted(address, buffer, length); } - inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len) { uint32_t a_end = a_start + a_len; @@ -598,6 +597,23 @@ inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,ui return (a_end > b_start && b_end > a_start); } +//currently the legacy implementation is used, from flash_ops.c +esp_err_t spi_flash_read_encrypted(size_t src, void *dstv, size_t size); + +esp_err_t IRAM_ATTR esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address, void *out_buffer, uint32_t length) +{ + /* + * Since currently this feature is supported only by the hardware, there + * is no way to support non-standard chips. We use the legacy + * implementation and skip the chip and driver layers. + */ + if (chip == NULL) { + chip = esp_flash_default_chip; + } else if (chip != esp_flash_default_chip) { + return ESP_ERR_NOT_SUPPORTED; + } + return spi_flash_read_encrypted(address, out_buffer, length); +} /*------------------------------------------------------------------------------ Adapter layer to original api before IDF v4.0 diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index 4a7c184de4..0de03e1218 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -247,17 +247,34 @@ esp_err_t esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t addres /** @brief Encrypted and write data to the SPI flash chip using on-chip hardware flash encryption * - * @param chip Pointer to identify flash chip. Must have been successfully initialised via esp_flash_init() + * @param chip Pointer to identify flash chip. Must be NULL (the main flash chip). For other chips, encrypted write is not supported. * @param address Address on flash to write to. 16 byte aligned. Must be previously erased (SPI NOR flash can only write bits 1->0). * @param buffer Pointer to a buffer with the data to write. * @param length Length (in bytes) of data to write. 16 byte aligned. * * @note Both address & length must be 16 byte aligned, as this is the encryption block size * - * @return ESP_OK on success, or a flash error code if operation failed. + * @return + * - ESP_OK: on success + * - ESP_ERR_NOT_SUPPORTED: encrypted write not supported for this chip. + * - ESP_ERR_INVALID_ARG: Either the address, buffer or length is invalid. + * - or other flash error code from spi_flash_write_encrypted(). */ esp_err_t esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length); +/** @brief Read and decrypt data from the SPI flash chip using on-chip hardware flash encryption + * + * @param chip Pointer to identify flash chip. Must be NULL (the main flash chip). For other chips, encrypted read is not supported. + * @param address Address on flash to read from. + * @param out_buffer Pointer to a buffer for the data to read to. + * @param length Length (in bytes) of data to read. + * + * @return + * - ESP_OK: on success + * - ESP_ERR_NOT_SUPPORTED: encrypted read not supported for this chip. + * - or other flash error code from spi_flash_read_encrypted(). + */ +esp_err_t esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address, void *out_buffer, uint32_t length); /** @brief Pointer to the "default" SPI flash chip, ie the main chip attached to the MCU. diff --git a/components/spi_flash/test/test_flash_encryption.c b/components/spi_flash/test/test_flash_encryption.c index e16ca93719..a5cc5201ed 100644 --- a/components/spi_flash/test/test_flash_encryption.c +++ b/components/spi_flash/test/test_flash_encryption.c @@ -12,6 +12,7 @@ #ifdef CONFIG_SECURE_FLASH_ENC_ENABLED static void test_encrypted_write(size_t offset, const uint8_t *data, size_t length); +static void test_encrypted_write_new_impl(size_t offset, const uint8_t *data, size_t length); static void verify_erased_flash(size_t offset, size_t length); static size_t start; @@ -86,6 +87,67 @@ static void test_encrypted_write(size_t offset, const uint8_t *data, size_t leng TEST_ASSERT_EQUAL_HEX8_ARRAY(data, readback, length); } +TEST_CASE("test 16 byte encrypted writes (esp_flash)", "[flash_encryption][esp_flash_enc][test_env=UT_T1_FlashEncryption]") +{ + setup_tests(); + + TEST_ASSERT_EQUAL_HEX(ESP_OK, + spi_flash_erase_sector(start / SPI_FLASH_SEC_SIZE)); + + uint8_t fortyeight_bytes[0x30]; // 0, 1, 2, 3, 4... 47 + for(int i = 0; i < sizeof(fortyeight_bytes); i++) { + fortyeight_bytes[i] = i; + } + + /* Verify unaligned start or length fails */ + TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_ARG, + esp_flash_write_encrypted(NULL, start+1, fortyeight_bytes, 32)); + + TEST_ASSERT_EQUAL_HEX(ESP_ERR_INVALID_SIZE, + esp_flash_write_encrypted(NULL, start, fortyeight_bytes, 15)); + + /* ensure nothing happened to the flash yet */ + verify_erased_flash(start, 0x20); + + /* Write 32 byte block, this is the "normal" encrypted write */ + test_encrypted_write_new_impl(start, fortyeight_bytes, 0x20); + verify_erased_flash(start + 0x20, 0x20); + + /* Slip in an unaligned esp_flash_read_encrypted() test */ + uint8_t buf[0x10]; + esp_flash_read_encrypted(NULL, start+0x10, buf, 0x10); + TEST_ASSERT_EQUAL_HEX8_ARRAY(fortyeight_bytes+0x10, buf, 16); + + /* Write 16 bytes unaligned */ + test_encrypted_write_new_impl(start + 0x30, fortyeight_bytes, 0x10); + /* the 16 byte regions before and after the 16 bytes we just wrote should still be 0xFF */ + verify_erased_flash(start + 0x20, 0x10); + verify_erased_flash(start + 0x40, 0x10); + + /* Write 48 bytes starting at a 32-byte aligned offset */ + test_encrypted_write_new_impl(start + 0x40, fortyeight_bytes, 0x30); + /* 16 bytes after this write should still be 0xFF -unencrypted- */ + verify_erased_flash(start + 0x70, 0x10); + + /* Write 48 bytes starting at a 16-byte aligned offset */ + test_encrypted_write_new_impl(start + 0x90, fortyeight_bytes, 0x30); + /* 16 bytes after this write should still be 0xFF -unencrypted- */ + verify_erased_flash(start + 0x120, 0x10); +} + +static void test_encrypted_write_new_impl(size_t offset, const uint8_t *data, size_t length) +{ + uint8_t readback[length]; + printf("encrypt %d bytes at 0x%x\n", length, offset); + TEST_ASSERT_EQUAL_HEX(ESP_OK, + esp_flash_write_encrypted(NULL, offset, data, length)); + + TEST_ASSERT_EQUAL_HEX(ESP_OK, + esp_flash_read_encrypted(NULL, offset, readback, length)); + + TEST_ASSERT_EQUAL_HEX8_ARRAY(data, readback, length); +} + static void verify_erased_flash(size_t offset, size_t length) { uint8_t readback[length];