esp_flash: add support for encrypted read and write

Using legacy implementation.
This commit is contained in:
Michael (XIAO Xufeng) 2019-09-05 18:45:45 +08:00
parent 5e0cc123ee
commit b9a2639ab4
3 changed files with 111 additions and 16 deletions

View File

@ -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

View File

@ -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.

View File

@ -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];