]> granicus.if.org Git - esp-idf/commitdiff
esp_flash: add support for encrypted read and write
authorMichael (XIAO Xufeng) <xiaoxufeng@espressif.com>
Thu, 5 Sep 2019 10:45:45 +0000 (18:45 +0800)
committerMichael (XIAO Xufeng) <xiaoxufeng@espressif.com>
Thu, 12 Sep 2019 04:41:50 +0000 (12:41 +0800)
Using legacy implementation.

components/spi_flash/esp_flash_api.c
components/spi_flash/include/esp_flash.h
components/spi_flash/test/test_flash_encryption.c

index 146ebd12f8c0921c02e6ede78cab9e86f7279178..e45f906abc81480e6f23452336180ce80da39783 100644 (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
index 4a7c184de43137621f9b9bae2a3f9e0c857a95be..0de03e1218f25e8cceca73a7c032f81dbb052952 100644 (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.
 
index e16ca93719802f6cc92f6979d772639895e9d52d..a5cc5201ed8383013db2fb2d7944229480c0fbf6 100644 (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];