2018-07-02 11:10:43 +00:00
|
|
|
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#include "nvs_encr.hpp"
|
|
|
|
#include "nvs_types.hpp"
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
namespace nvs
|
|
|
|
{
|
|
|
|
|
|
|
|
bool EncrMgr::isActive = false;
|
|
|
|
EncrMgr* EncrMgr::instance = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
EncrMgr* EncrMgr::getInstance()
|
|
|
|
{
|
|
|
|
if(!isActive)
|
|
|
|
{
|
2019-12-06 06:36:28 +00:00
|
|
|
instance = new (std::nothrow) EncrMgr();
|
|
|
|
if (instance) {
|
|
|
|
isActive = true;
|
|
|
|
}
|
2018-07-02 11:10:43 +00:00
|
|
|
}
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EncrMgr::resetInstance()
|
|
|
|
{
|
|
|
|
if(isActive) {
|
|
|
|
delete instance;
|
|
|
|
instance = nullptr;
|
|
|
|
isActive = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EncrMgr::isEncrActive() {
|
|
|
|
return isActive;
|
|
|
|
}
|
|
|
|
|
|
|
|
XtsCtxt* EncrMgr::findXtsCtxtFromAddr(uint32_t addr) {
|
|
|
|
|
|
|
|
auto it = find_if(std::begin(xtsCtxtList), std::end(xtsCtxtList), [=](XtsCtxt& ctx) -> bool
|
|
|
|
{ return (ctx.baseSector * SPI_FLASH_SEC_SIZE <= addr)
|
|
|
|
&& (addr < (ctx.baseSector + ctx.sectorCount) * SPI_FLASH_SEC_SIZE); });
|
|
|
|
|
|
|
|
if (it == std::end(xtsCtxtList)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t EncrMgr::setSecurityContext(uint32_t baseSector, uint32_t sectorCount, nvs_sec_cfg_t* cfg) {
|
|
|
|
|
|
|
|
uint8_t* eky = reinterpret_cast<uint8_t*>(cfg);
|
|
|
|
|
2019-12-06 06:36:28 +00:00
|
|
|
auto ctxt = new (std::nothrow) XtsCtxt();
|
|
|
|
|
|
|
|
if (!ctxt) return ESP_ERR_NO_MEM;
|
2018-07-02 11:10:43 +00:00
|
|
|
|
|
|
|
ctxt->baseSector = baseSector;
|
|
|
|
ctxt->sectorCount = sectorCount;
|
|
|
|
|
|
|
|
mbedtls_aes_xts_init(ctxt->ectxt);
|
|
|
|
mbedtls_aes_xts_init(ctxt->dctxt);
|
|
|
|
|
|
|
|
if(mbedtls_aes_xts_setkey_enc(ctxt->ectxt, eky, 2 * NVS_KEY_SIZE * 8)) {
|
|
|
|
return ESP_ERR_NVS_XTS_CFG_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mbedtls_aes_xts_setkey_dec(ctxt->dctxt, eky, 2 * NVS_KEY_SIZE * 8)) {
|
|
|
|
return ESP_ERR_NVS_XTS_CFG_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
xtsCtxtList.push_back(ctxt);
|
|
|
|
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t EncrMgr::removeSecurityContext(uint32_t baseSector) {
|
|
|
|
auto xtsCtxt = findXtsCtxtFromAddr(baseSector * SPI_FLASH_SEC_SIZE);
|
|
|
|
if(!xtsCtxt) {
|
|
|
|
return ESP_ERR_NVS_XTS_CFG_NOT_FOUND;
|
|
|
|
}
|
|
|
|
xtsCtxtList.erase(xtsCtxt);
|
|
|
|
delete xtsCtxt;
|
|
|
|
|
|
|
|
if(!xtsCtxtList.size()) {
|
|
|
|
resetInstance();
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
esp_err_t EncrMgr::encryptNvsData(uint8_t* ptxt, uint32_t addr, uint32_t ptxtLen, XtsCtxt* xtsCtxt) {
|
|
|
|
|
|
|
|
uint8_t entrySize = sizeof(Item);
|
|
|
|
|
|
|
|
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
|
|
|
uint8_t data_unit[16];
|
|
|
|
|
|
|
|
assert(ptxtLen % entrySize == 0);
|
|
|
|
|
|
|
|
/* Use relative address instead of absolute address (relocatable), so that host-generated
|
|
|
|
* encrypted nvs images can be used*/
|
|
|
|
uint32_t relAddr = addr - (xtsCtxt->baseSector * SPI_FLASH_SEC_SIZE);
|
|
|
|
|
|
|
|
memset(data_unit, 0, sizeof(data_unit));
|
|
|
|
|
|
|
|
for(uint8_t entry = 0; entry < (ptxtLen/entrySize); entry++)
|
|
|
|
{
|
|
|
|
uint32_t offset = entry * entrySize;
|
|
|
|
uint32_t *addr_loc = (uint32_t*) &data_unit[0];
|
|
|
|
|
|
|
|
*addr_loc = relAddr + offset;
|
|
|
|
if(mbedtls_aes_crypt_xts(xtsCtxt->ectxt, MBEDTLS_AES_ENCRYPT, entrySize, data_unit, ptxt + offset, ptxt + offset)) {
|
|
|
|
return ESP_ERR_NVS_XTS_ENCR_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
esp_err_t EncrMgr::decryptNvsData(uint8_t* ctxt, uint32_t addr, uint32_t ctxtLen, XtsCtxt* xtsCtxt) {
|
|
|
|
|
|
|
|
//sector num required as an arr by mbedtls. Should have been just uint64/32.
|
|
|
|
uint8_t data_unit[16];
|
|
|
|
|
|
|
|
|
|
|
|
/** Currently upper layer of NVS reads entries one by one even for variable size
|
|
|
|
* multi-entry data types. So length should always be equal to size of an entry.*/
|
|
|
|
assert(ctxtLen == sizeof(Item));
|
|
|
|
|
|
|
|
uint32_t relAddr = addr - (xtsCtxt->baseSector * SPI_FLASH_SEC_SIZE);
|
|
|
|
|
|
|
|
memset(data_unit, 0, sizeof(data_unit));
|
|
|
|
|
|
|
|
memcpy(data_unit, &relAddr, sizeof(relAddr));
|
|
|
|
|
|
|
|
if(mbedtls_aes_crypt_xts(xtsCtxt->dctxt, MBEDTLS_AES_DECRYPT, ctxtLen, data_unit, ctxt, ctxt)) {
|
|
|
|
return ESP_ERR_NVS_XTS_DECR_FAILED;
|
|
|
|
}
|
|
|
|
return ESP_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace nvs
|