Skip to main content

esp_storage/
encrypted.rs

1use crate::{FlashStorage, FlashStorageError, buffer::FlashSectorBuffer};
2
3impl FlashStorage<'_> {
4    /// Read bytes from encrypted flash.
5    ///
6    /// Uses the MMU to map flash pages and reads decrypted data through the cache.
7    /// Unaligned offsets and lengths are supported.
8    ///
9    /// If flash encryption is not enabled this will just read plaintext.
10    ///
11    /// # Note
12    ///
13    /// This function always allocates a [`Self::SECTOR_SIZE`]-byte buffer on
14    /// the stack. See the
15    /// [crate-level documentation](crate#buffer-alignment-and-stack-usage).
16    ///
17    /// # Errors
18    ///
19    /// Returns [`FlashStorageError::OutOfBounds`] if the read would extend past
20    /// the end of the flash.
21    #[cfg_attr(
22        multi_core,
23        doc = "Returns [`FlashStorageError::OtherCoreRunning`] if the other core is active, because this function changes the flash MMU and the cache."
24    )]
25    pub fn read_encrypted(
26        &mut self,
27        offset: u32,
28        mut bytes: &mut [u8],
29    ) -> Result<(), FlashStorageError> {
30        self.check_bounds(offset, bytes.len())?;
31
32        let mut data_offset = offset % Self::SECTOR_SIZE;
33        let mut aligned_offset = offset - data_offset;
34
35        let mut sector_data = FlashSectorBuffer::uninit();
36
37        while !bytes.is_empty() {
38            let len = bytes.len().min((Self::SECTOR_SIZE - data_offset) as _);
39
40            self.internal_read_encrypted(aligned_offset, sector_data.as_bytes_mut())?;
41            let sector_data = unsafe { sector_data.assume_init_bytes_mut() };
42            bytes[..len].copy_from_slice(&sector_data[data_offset as usize..][..len]);
43
44            aligned_offset += Self::SECTOR_SIZE;
45            data_offset = 0;
46            bytes = &mut bytes[len..];
47        }
48
49        Ok(())
50    }
51
52    /// Write bytes to encrypted flash.
53    ///
54    /// Performs read-modify-write on affected sectors: reads the current encrypted
55    /// content, merges the new bytes, erases the sector, then writes it back encrypted.
56    ///
57    /// # Note
58    ///
59    /// This function always allocates a [`Self::SECTOR_SIZE`]-byte buffer on
60    /// the stack. See the
61    /// [crate-level documentation](crate#buffer-alignment-and-stack-usage).
62    ///
63    /// # Errors
64    ///
65    /// Returns [`FlashStorageError::NotSupported`] if flash encryption is not
66    /// enabled.
67    ///
68    /// Returns [`FlashStorageError::OutOfBounds`] if the write would extend past
69    /// the end of the flash.
70    #[cfg_attr(
71        multi_core,
72        doc = "Returns [`FlashStorageError::OtherCoreRunning`] if the other core is active, because this function changes the flash MMU and the cache."
73    )]
74    pub fn write_encrypted(
75        &mut self,
76        offset: u32,
77        mut bytes: &[u8],
78    ) -> Result<(), FlashStorageError> {
79        // we have a HIL test which exploits the fact that the ROM function
80        // will actually do encryption even if the flash encryption isn't enabled via efuse
81        #[cfg(not(any(__test_esp_storage, feature = "emulation")))]
82        if !crate::flash_encryption() {
83            return Err(FlashStorageError::NotSupported);
84        }
85
86        self.check_bounds(offset, bytes.len())?;
87
88        let mut data_offset = offset % Self::SECTOR_SIZE;
89        let mut aligned_offset = offset - data_offset;
90
91        let mut sector_data = FlashSectorBuffer::uninit();
92
93        while !bytes.is_empty() {
94            let len = bytes.len().min((Self::SECTOR_SIZE - data_offset) as _);
95
96            self.internal_read_encrypted(aligned_offset, sector_data.as_bytes_mut())?;
97            let sector_data = unsafe { sector_data.assume_init_bytes_mut() };
98
99            sector_data[data_offset as usize..][..len].copy_from_slice(&bytes[..len]);
100            self.internal_erase_sector(aligned_offset / Self::SECTOR_SIZE)?;
101            self.internal_write_encrypted(aligned_offset, sector_data)?;
102
103            aligned_offset += Self::SECTOR_SIZE;
104            data_offset = 0;
105            bytes = &bytes[len..];
106        }
107
108        Ok(())
109    }
110}