1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstring>
16 #include "nvs_encrypted_partition.hpp"
17 #include "nvs_types.hpp"
18
19 namespace nvs {
20
NVSEncryptedPartition(const esp_partition_t * partition)21 NVSEncryptedPartition::NVSEncryptedPartition(const esp_partition_t *partition)
22 : NVSPartition(partition) { }
23
init(nvs_sec_cfg_t * cfg)24 esp_err_t NVSEncryptedPartition::init(nvs_sec_cfg_t* cfg)
25 {
26 uint8_t* eky = reinterpret_cast<uint8_t*>(cfg);
27
28 mbedtls_aes_xts_init(&mEctxt);
29 mbedtls_aes_xts_init(&mDctxt);
30
31 if (mbedtls_aes_xts_setkey_enc(&mEctxt, eky, 2 * NVS_KEY_SIZE * 8) != 0) {
32 return ESP_ERR_NVS_XTS_CFG_FAILED;
33 }
34
35 if (mbedtls_aes_xts_setkey_dec(&mDctxt, eky, 2 * NVS_KEY_SIZE * 8) != 0) {
36 return ESP_ERR_NVS_XTS_CFG_FAILED;
37 }
38
39 return ESP_OK;
40 }
41
read(size_t src_offset,void * dst,size_t size)42 esp_err_t NVSEncryptedPartition::read(size_t src_offset, void* dst, size_t size)
43 {
44 /** Currently upper layer of NVS reads entries one by one even for variable size
45 * multi-entry data types. So length should always be equal to size of an entry.*/
46 if (size != sizeof(Item)) return ESP_ERR_INVALID_SIZE;
47
48 // read data
49 esp_err_t read_result = esp_partition_read(mESPPartition, src_offset, dst, size);
50 if (read_result != ESP_OK) {
51 return read_result;
52 }
53
54 // decrypt data
55 //sector num required as an arr by mbedtls. Should have been just uint64/32.
56 uint8_t data_unit[16];
57
58 uint32_t relAddr = src_offset;
59
60 memset(data_unit, 0, sizeof(data_unit));
61
62 memcpy(data_unit, &relAddr, sizeof(relAddr));
63
64 uint8_t *destination = reinterpret_cast<uint8_t*>(dst);
65
66 if (mbedtls_aes_crypt_xts(&mDctxt, MBEDTLS_AES_DECRYPT, size, data_unit, destination, destination) != 0) {
67 return ESP_ERR_NVS_XTS_DECR_FAILED;
68 }
69
70 return ESP_OK;
71 }
72
write(size_t addr,const void * src,size_t size)73 esp_err_t NVSEncryptedPartition::write(size_t addr, const void* src, size_t size)
74 {
75 if (size % ESP_ENCRYPT_BLOCK_SIZE != 0) return ESP_ERR_INVALID_SIZE;
76
77 // copy data to buffer for encryption
78 uint8_t* buf = new (std::nothrow) uint8_t [size];
79
80 if (!buf) return ESP_ERR_NO_MEM;
81
82 memcpy(buf, src, size);
83
84 // encrypt data
85 uint8_t entrySize = sizeof(Item);
86
87 //sector num required as an arr by mbedtls. Should have been just uint64/32.
88 uint8_t data_unit[16];
89
90 /* Use relative address instead of absolute address (relocatable), so that host-generated
91 * encrypted nvs images can be used*/
92 uint32_t relAddr = addr;
93
94 memset(data_unit, 0, sizeof(data_unit));
95
96 for(uint8_t entry = 0; entry < (size/entrySize); entry++)
97 {
98 uint32_t offset = entry * entrySize;
99 uint32_t *addr_loc = (uint32_t*) &data_unit[0];
100
101 *addr_loc = relAddr + offset;
102 if (mbedtls_aes_crypt_xts(&mEctxt,
103 MBEDTLS_AES_ENCRYPT,
104 entrySize,
105 data_unit,
106 buf + offset,
107 buf + offset) != 0) {
108 delete buf;
109 return ESP_ERR_NVS_XTS_ENCR_FAILED;
110 }
111 }
112
113 // write data
114 esp_err_t result = esp_partition_write(mESPPartition, addr, buf, size);
115
116 delete buf;
117
118 return result;
119 }
120
121 } // nvs
122