mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/nvs_encryption_using_hmac_v2' into 'master'
nvs_flash: Add support for HMAC-based encryption key derivation scheme Closes IDF-6727 See merge request espressif/esp-idf!23079
This commit is contained in:
commit
d00e7b5af8
@ -125,6 +125,7 @@
|
||||
/components/mqtt/ @esp-idf-codeowners/network
|
||||
/components/newlib/ @esp-idf-codeowners/system @esp-idf-codeowners/tools
|
||||
/components/nvs_flash/ @esp-idf-codeowners/storage
|
||||
/components/nvs_sec_provider/ @esp-idf-codeowners/storage @esp-idf-codeowners/security
|
||||
/components/openthread/ @esp-idf-codeowners/ieee802154
|
||||
/components/partition_table/ @esp-idf-codeowners/system
|
||||
/components/perfmon/ @esp-idf-codeowners/tools
|
||||
|
@ -141,6 +141,7 @@ build:integration_test:
|
||||
- flash_multi
|
||||
- ecdsa
|
||||
- ccs811 # pytest*ccs811*
|
||||
- nvs_encr_hmac
|
||||
patterns:
|
||||
- "{0}-{1}-{2}"
|
||||
- "{0}-{2}"
|
||||
|
@ -320,6 +320,15 @@
|
||||
- "components/efuse/**/*"
|
||||
- "components/mbedtls/port/ecdsa/*"
|
||||
|
||||
.patterns-component_ut-nvs_encr_hmac: &patterns-component_ut-nvs_encr_hmac
|
||||
- "components/nvs_flash/**/*"
|
||||
- "components/nvs_sec_provider/**/*"
|
||||
|
||||
.patterns-example_test-nvs_encr_hmac: &patterns-example_test-nvs_encr_hmac
|
||||
- "components/nvs_flash/**/*"
|
||||
- "components/nvs_sec_provider/**/*"
|
||||
- "examples/security/nvs_encryption_hmac/**/*"
|
||||
|
||||
##############
|
||||
# if anchors #
|
||||
##############
|
||||
@ -627,6 +636,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -662,6 +673,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -696,6 +709,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -730,6 +745,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -764,6 +781,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -798,6 +817,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -832,6 +853,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -866,6 +889,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1145,6 +1170,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1188,6 +1215,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1230,6 +1259,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1273,6 +1304,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1315,6 +1348,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1357,6 +1392,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1399,6 +1436,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1441,6 +1480,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1544,6 +1585,8 @@
|
||||
changes: *patterns-component_ut
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1562,6 +1605,8 @@
|
||||
changes: *patterns-example_test-ethernet
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-i154
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-sdio
|
||||
- <<: *if-dev-push
|
||||
@ -1997,6 +2042,19 @@
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-flash_multi
|
||||
|
||||
.rules:test:component_ut-esp32c3-nvs_encr_hmac:
|
||||
rules:
|
||||
- <<: *if-revert-branch
|
||||
when: never
|
||||
- <<: *if-protected
|
||||
- <<: *if-label-build-only
|
||||
when: never
|
||||
- <<: *if-label-component_ut
|
||||
- <<: *if-label-component_ut_esp32c3
|
||||
- <<: *if-label-target_test
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-component_ut-nvs_encr_hmac
|
||||
|
||||
.rules:test:component_ut-esp32c3-sdio:
|
||||
rules:
|
||||
- <<: *if-revert-branch
|
||||
@ -2488,6 +2546,19 @@
|
||||
when: never
|
||||
- <<: *if-example_test-ota-include_nightly_run-rule
|
||||
|
||||
.rules:test:example_test-esp32c3-nvs_encr_hmac:
|
||||
rules:
|
||||
- <<: *if-revert-branch
|
||||
when: never
|
||||
- <<: *if-protected
|
||||
- <<: *if-label-build-only
|
||||
when: never
|
||||
- <<: *if-label-example_test
|
||||
- <<: *if-label-example_test_esp32c3
|
||||
- <<: *if-label-target_test
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_test-nvs_encr_hmac
|
||||
|
||||
.rules:test:example_test-esp32c3-sdio:
|
||||
rules:
|
||||
- <<: *if-revert-branch
|
||||
|
@ -410,6 +410,14 @@ pytest_examples_esp32c3_flash_encryption:
|
||||
- build_pytest_examples_esp32c3
|
||||
tags: [ esp32c3, flash_encryption ]
|
||||
|
||||
pytest_examples_esp32c3_nvs_encr_hmac:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
- .rules:test:example_test-esp32c3-nvs_encr_hmac
|
||||
needs:
|
||||
- build_pytest_examples_esp32c3
|
||||
tags: [ esp32c3, nvs_encr_hmac ]
|
||||
|
||||
pytest_examples_esp32s2_usb_device:
|
||||
extends:
|
||||
- .pytest_examples_dir_template
|
||||
@ -844,6 +852,14 @@ pytest_components_esp32c3_flash_encryption:
|
||||
- build_pytest_components_esp32c3
|
||||
tags: [ esp32c3, flash_encryption ]
|
||||
|
||||
pytest_components_esp32c3_nvs_encr_hmac:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
- .rules:test:component_ut-esp32c3-nvs_encr_hmac
|
||||
needs:
|
||||
- build_pytest_components_esp32c3
|
||||
tags: [ esp32c3, nvs_encr_hmac ]
|
||||
|
||||
pytest_components_esp32c3_flash_multi:
|
||||
extends:
|
||||
- .pytest_components_dir_template
|
||||
|
@ -776,6 +776,7 @@ menu "Security features"
|
||||
bool "Enable flash encryption on boot (READ DOCS FIRST)"
|
||||
default N
|
||||
select SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE
|
||||
select NVS_ENCRYPTION
|
||||
help
|
||||
If this option is set, flash contents will be encrypted by the bootloader on first boot.
|
||||
|
||||
|
@ -72,6 +72,9 @@
|
||||
#if __has_include("nvs.h")
|
||||
#include "nvs.h"
|
||||
#endif
|
||||
#if __has_include("nvs_sec_provider.h")
|
||||
#include "nvs_sec_provider.h"
|
||||
#endif
|
||||
#if __has_include("spi_flash_mmap.h")
|
||||
#include "spi_flash_mmap.h"
|
||||
#endif
|
||||
@ -829,6 +832,25 @@ static const esp_err_msg_t esp_err_msg_table[] = {
|
||||
# endif
|
||||
# ifdef ESP_ERR_TCP_TRANSPORT_NO_MEM
|
||||
ERR_TBL_IT(ESP_ERR_TCP_TRANSPORT_NO_MEM), /* 57348 0xe004 Memory allocation failed */
|
||||
# endif
|
||||
// components/nvs_sec_provider/include/nvs_sec_provider.h
|
||||
# ifdef ESP_ERR_NVS_SEC_BASE
|
||||
ERR_TBL_IT(ESP_ERR_NVS_SEC_BASE), /* 61440 0xf000 Starting number of error codes */
|
||||
# endif
|
||||
# ifdef ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND
|
||||
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND), /* 61441 0xf001 HMAC Key required to generate the NVS
|
||||
encryption keys not found */
|
||||
# endif
|
||||
# ifdef ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED
|
||||
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED), /* 61442 0xf002 Provided eFuse block for HMAC key
|
||||
generation is already in use */
|
||||
# endif
|
||||
# ifdef ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED
|
||||
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED), /* 61443 0xf003 Failed to generate/write the HMAC key to eFuse */
|
||||
# endif
|
||||
# ifdef ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED
|
||||
ERR_TBL_IT(ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED), /* 61444 0xf004 Failed to derive the NVS encryption keys
|
||||
based on the HMAC-based scheme */
|
||||
# endif
|
||||
};
|
||||
#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
|
||||
|
@ -36,9 +36,7 @@ if(${target} STREQUAL "linux")
|
||||
elseif(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
message(WARNING "Missing LIBBSD library. Install libbsd-dev package and/or check linker directories.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CONFIG_NVS_ENCRYPTION)
|
||||
else()
|
||||
target_sources(${COMPONENT_LIB} PRIVATE "src/nvs_encrypted_partition.cpp")
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE idf::mbedtls)
|
||||
endif()
|
||||
|
@ -2,13 +2,13 @@ menu "NVS"
|
||||
|
||||
config NVS_ENCRYPTION
|
||||
bool "Enable NVS encryption"
|
||||
default y
|
||||
depends on SECURE_FLASH_ENC_ENABLED
|
||||
depends on SECURE_FLASH_ENC_ENABLED || SOC_HMAC_SUPPORTED
|
||||
default y if SECURE_FLASH_ENC_ENABLED
|
||||
help
|
||||
This option enables encryption for NVS. When enabled, XTS-AES is used to encrypt
|
||||
the complete NVS data, except the page headers. It requires XTS encryption keys
|
||||
to be stored in an encrypted partition. This means enabling flash encryption is
|
||||
a pre-requisite for this feature.
|
||||
to be stored in an encrypted partition (enabling flash encryption is mandatory here)
|
||||
or to be derived from an HMAC key burnt in eFuse.
|
||||
|
||||
config NVS_COMPATIBLE_PRE_V4_3_ENCRYPTION_FLAG
|
||||
bool "NVS partition encrypted flag compatible with ESP-IDF before v4.3"
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2015-2016 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.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef nvs_flash_h
|
||||
#define nvs_flash_h
|
||||
|
||||
@ -32,6 +24,27 @@ typedef struct {
|
||||
uint8_t tky[NVS_KEY_SIZE]; /*!< XTS tweak key */
|
||||
} nvs_sec_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Callback function prototype for generating the NVS encryption keys
|
||||
*/
|
||||
typedef esp_err_t (*nvs_flash_generate_keys_t) (const void *scheme_data, nvs_sec_cfg_t* cfg);
|
||||
|
||||
/**
|
||||
* @brief Callback function prototype for reading the NVS encryption keys
|
||||
*/
|
||||
typedef esp_err_t (*nvs_flash_read_cfg_t) (const void *scheme_data, nvs_sec_cfg_t* cfg);
|
||||
|
||||
/**
|
||||
* @brief NVS encryption: Security scheme configuration structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int scheme_id; /*!< Security Scheme ID (E.g. HMAC) */
|
||||
void *scheme_data; /*!< Scheme-specific data (E.g. eFuse block for HMAC-based key generation) */
|
||||
nvs_flash_generate_keys_t nvs_flash_key_gen; /*!< Callback for the nvs_flash_key_gen implementation */
|
||||
nvs_flash_read_cfg_t nvs_flash_read_cfg; /*!< Callback for the nvs_flash_read_keys implementation */
|
||||
} nvs_sec_scheme_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the default NVS partition.
|
||||
*
|
||||
@ -220,9 +233,9 @@ esp_err_t nvs_flash_secure_init_partition(const char *partition_label, nvs_sec_c
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* -ESP_OK, if cfg was read successfully;
|
||||
* -ESP_INVALID_ARG, if partition or cfg;
|
||||
* -or error codes from esp_partition_write/erase APIs.
|
||||
* - ESP_OK, if cfg was read successfully;
|
||||
* - ESP_ERR_INVALID_ARG, if partition or cfg is NULL;
|
||||
* - or error codes from esp_partition_write/erase APIs.
|
||||
*/
|
||||
|
||||
esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg);
|
||||
@ -240,15 +253,68 @@ esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_
|
||||
* @note Provided partition is assumed to be marked 'encrypted'.
|
||||
*
|
||||
* @return
|
||||
* -ESP_OK, if cfg was read successfully;
|
||||
* -ESP_INVALID_ARG, if partition or cfg;
|
||||
* -ESP_ERR_NVS_KEYS_NOT_INITIALIZED, if the partition is not yet written with keys.
|
||||
* -ESP_ERR_NVS_CORRUPT_KEY_PART, if the partition containing keys is found to be corrupt
|
||||
* -or error codes from esp_partition_read API.
|
||||
* - ESP_OK, if cfg was read successfully;
|
||||
* - ESP_ERR_INVALID_ARG, if partition or cfg is NULL
|
||||
* - ESP_ERR_NVS_KEYS_NOT_INITIALIZED, if the partition is not yet written with keys.
|
||||
* - ESP_ERR_NVS_CORRUPT_KEY_PART, if the partition containing keys is found to be corrupt
|
||||
* - or error codes from esp_partition_read API.
|
||||
*/
|
||||
|
||||
esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partition, nvs_sec_cfg_t* cfg);
|
||||
|
||||
/**
|
||||
* @brief Registers the given security scheme for NVS encryption
|
||||
* The scheme registered with sec_scheme_id by this API be used as
|
||||
* the default security scheme for the "nvs" partition.
|
||||
* Users will have to call this API explicitly in their application.
|
||||
*
|
||||
* @param[in] scheme_cfg Pointer to the security scheme configuration structure
|
||||
* that the user (or the nvs_key_provider) wants to register.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, if security scheme registration succeeds;
|
||||
* - ESP_ERR_INVALID_ARG, if scheme_cfg is NULL;
|
||||
* - ESP_FAIL, if security scheme registration fails
|
||||
*/
|
||||
esp_err_t nvs_flash_register_security_scheme(nvs_sec_scheme_t *scheme_cfg);
|
||||
|
||||
/**
|
||||
* @brief Fetch the configuration structure for the default active
|
||||
* security scheme for NVS encryption
|
||||
*
|
||||
* @return Pointer to the default active security scheme configuration
|
||||
* (NULL if no scheme is registered yet i.e. active)
|
||||
*/
|
||||
nvs_sec_scheme_t *nvs_flash_get_default_security_scheme(void);
|
||||
|
||||
/**
|
||||
* @brief Generate (and store) the NVS keys using the specified key-protection scheme
|
||||
*
|
||||
* @param[in] scheme_cfg Security scheme specific configuration
|
||||
*
|
||||
* @param[out] cfg Security configuration (encryption keys)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, if cfg was populated successfully with generated encryption keys;
|
||||
* - ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL;
|
||||
* - ESP_FAIL, if the key generation process fails
|
||||
*/
|
||||
esp_err_t nvs_flash_generate_keys_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg);
|
||||
|
||||
/**
|
||||
* @brief Read NVS security configuration set by the specified security scheme
|
||||
*
|
||||
* @param[in] scheme_cfg Security scheme specific configuration
|
||||
*
|
||||
* @param[out] cfg Security configuration (encryption keys)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, if cfg was read successfully;
|
||||
* - ESP_ERR_INVALID_ARG, if scheme_cfg or cfg is NULL;
|
||||
* - ESP_FAIL, if the key reading process fails
|
||||
*/
|
||||
esp_err_t nvs_flash_read_security_cfg_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -6,20 +6,22 @@ NVS Partition Generator Utility
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The utility :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` creates a binary file based on key-value pairs provided in a CSV file. The binary file is compatible with NVS architecture defined in :doc:`Non-Volatile Storage </api-reference/storage/nvs_flash>`. This utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This allows manufacturers to generate many instances of the same application firmware with customized parameters for each device, such as a serial number.
|
||||
The utility :component_file:`nvs_flash/nvs_partition_generator/nvs_partition_gen.py` creates a binary file, compatible with the NVS architecture defined in :doc:`Non-Volatile Storage </api-reference/storage/nvs_flash>`, based on the key-value pairs provided in a CSV file.
|
||||
|
||||
This utility is ideally suited for generating a binary blob, containing data specific to ODM/OEM, which can be flashed externally at the time of device manufacturing. This allows manufacturers to generate many instances of the same application firmware with customized parameters for each device, such as a serial number.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
To use this utility in encryption mode, install the following packages:
|
||||
- cryptography package
|
||||
- ``cryptography``
|
||||
|
||||
All the required packages are included in `requirements.txt` in the root of the esp-idf directory.
|
||||
All the required packages are included in `requirements.txt` in the root of the ESP-IDF directory.
|
||||
|
||||
CSV File Format
|
||||
---------------
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Each line of a CSV file should contain 4 parameters, separated by a comma. The table below provides the description for each of these parameters.
|
||||
Each line of a CSV file should contain 4 parameters, separated by a comma. The table below describes each of these parameters.
|
||||
|
||||
.. list-table::
|
||||
:widths: 10 20 35 35
|
||||
@ -73,19 +75,15 @@ When a namespace entry is encountered in a CSV file, each following entry will b
|
||||
Multipage Blob Support
|
||||
----------------------
|
||||
|
||||
By default, binary blobs are allowed to span over multiple pages and are written in the format mentioned in Section :ref:`structure_of_entry`. If you intend to use an older format, the utility provides an option to disable this feature.
|
||||
By default, binary blobs are allowed to span over multiple pages and are written in the format mentioned in Section :ref:`structure_of_entry`. If you intend to use the older format, the utility provides an option to disable this feature.
|
||||
|
||||
|
||||
Encryption Support
|
||||
-------------------
|
||||
Encryption-Decryption Support
|
||||
-----------------------------
|
||||
|
||||
The NVS Partition Generator utility also allows you to create an encrypted binary file. The utility uses the XTS-AES encryption. Please refer to :ref:`nvs_encryption` for more details.
|
||||
The NVS Partition Generator utility also allows you to create an encrypted binary file and decrypt an encrypted one. The utility uses the XTS-AES encryption. Please refer to :doc:`NVS Encryption <nvs_encryption>` for more details.
|
||||
|
||||
|
||||
Decryption Support
|
||||
-------------------
|
||||
This utility allows you to decrypt an encrypted NVS binary file. The utility uses an NVS binary file encrypted using XTS-AES encryption. Please refer to :ref:`nvs_encryption` for more details.
|
||||
|
||||
Running the Utility
|
||||
-------------------
|
||||
|
||||
@ -95,141 +93,173 @@ Running the Utility
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
+-----+------------+----------------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+============+======================================================================+
|
||||
| 1 | -h, --help | Show this help message and exit |
|
||||
+-----+------------+----------------------------------------------------------------------+
|
||||
+-----+------------------------+---------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+========================+===============================================================+
|
||||
| 1 | ``-h`` \ ``--help`` | Show the help message and exit |
|
||||
+-----+------------------------+---------------------------------------------------------------+
|
||||
|
||||
**Commands**::
|
||||
|
||||
Run nvs_partition_gen.py {command} -h for additional help
|
||||
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+==============+====================================================================+
|
||||
| 1 | generate | Generate NVS partition |
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
| 2 | generate-key | Generate keys for encryption |
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
| 3 | encrypt | Generate NVS encrypted partition |
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
| 4 | decrypt | Decrypt NVS encrypted partition |
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
+-----+---------------------+---------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+=====================+===============================================================+
|
||||
| 1 | ``generate`` | Generate NVS partition |
|
||||
+-----+---------------------+---------------------------------------------------------------+
|
||||
| 2 | ``generate-key`` | Generate keys for encryption |
|
||||
+-----+---------------------+---------------------------------------------------------------+
|
||||
| 3 | ``encrypt`` | Generate NVS encrypted partition |
|
||||
+-----+---------------------+---------------------------------------------------------------+
|
||||
| 4 | ``decrypt`` | Decrypt NVS encrypted partition |
|
||||
+-----+---------------------+---------------------------------------------------------------+
|
||||
|
||||
To Generate NVS Partition (Default):
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Generate NVS Partition (Default)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Usage**::
|
||||
|
||||
python nvs_partition_gen.py generate [-h] [--version {1,2}] [--outdir OUTDIR]
|
||||
input output size
|
||||
python nvs_partition_gen.py generate [-h] [--version {1,2}] [--outdir OUTDIR] input output size
|
||||
|
||||
**Positional Arguments**:
|
||||
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+======================================================================+
|
||||
| input | Path to CSV file to parse |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| output | Path to output NVS binary file |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| size | Size of NVS partition in bytes (must be multiple of 4096) |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+===============================================================+
|
||||
| ``input`` | Path to CSV file to parse |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| ``output`` | Path to output NVS binary file |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| ``size`` | Size of NVS partition in bytes (must be multiple of 4096) |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
+-----------------+--------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=================+====================================================================+
|
||||
| -h, --help | Show this help message and exit |
|
||||
+-----------------+--------------------------------------------------------------------+
|
||||
| --version {1,2} | Set multipage blob version |
|
||||
| | Version 1 - Multipage blob support disabled |
|
||||
| | Version 2 - Multipage blob support enabled |
|
||||
| | Default: Version 2 |
|
||||
| | |
|
||||
+-----------------+--------------------------------------------------------------------+
|
||||
| --outdir OUTDIR | Output directory to store files created |
|
||||
| | (Default: current directory) |
|
||||
+-----------------+--------------------------------------------------------------------+
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+========================+======================================================================+
|
||||
| ``-h`` \ ``--help`` | Show the help message and exit |
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
| ``--version {1,2}`` | Set multipage blob version (Default: Version 2) |
|
||||
| | |
|
||||
| | Version 1 - Multipage blob support disabled |
|
||||
| | |
|
||||
| | Version 2 - Multipage blob support enabled |
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
| ``--outdir OUTDIR`` | Output directory to store file created (Default: current directory) |
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
|
||||
You can run the utility to generate NVS partition using the command below. A sample CSV file is provided with the utility::
|
||||
|
||||
python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000
|
||||
|
||||
|
||||
To Generate Only Encryption Key Partition:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Generate Encryption Keys Partition
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Usage**::
|
||||
|
||||
python nvs_partition_gen.py generate-key [-h] [--keyfile KEYFILE]
|
||||
[--outdir OUTDIR]
|
||||
python nvs_partition_gen.py generate-key [-h] [--key_protect_hmac] [--kp_hmac_keygen]
|
||||
[--kp_hmac_keyfile KP_HMAC_KEYFILE] [--kp_hmac_inputkey KP_HMAC_INPUTKEY]
|
||||
[--keyfile KEYFILE] [--outdir OUTDIR]
|
||||
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
.. list-table::
|
||||
:widths: 30 70
|
||||
:header-rows: 1
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
* - -h, --help
|
||||
- Show this help message and exit
|
||||
* - --keyfile KEYFILE
|
||||
- Path to output encryption key partition file
|
||||
* - --outdir OUTDIR
|
||||
- Output directory to store file created (Default: current directory)
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=============================================+===================================================================================+
|
||||
| ``-h`` \ ``--help`` | Show the help message and exit |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--key_protect_hmac`` | If set, the NVS encryption key protection scheme based on HMAC |
|
||||
| | peripheral is used; else the default scheme based on Flash Encryption |
|
||||
| | is used |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keygen`` | Generate the HMAC key for HMAC-based encryption scheme |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keyfile KP_HMAC_KEYFILE`` | Path to output HMAC key file |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_inputkey KP_HMAC_INPUTKEY`` | File having the HMAC key for generating the NVS encryption keys |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--keyfile KEYFILE`` | Path to output encryption keys file |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--outdir OUTDIR`` | Output directory to store files created. (Default: current directory) |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
|
||||
You can run the utility to generate only the encryption key partition using the command below::
|
||||
|
||||
python nvs_partition_gen.py generate-key
|
||||
|
||||
To Generate Encrypted NVS Partition:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
For generating encryption key for the HMAC-based scheme, the following commands can be used:
|
||||
|
||||
- Generate the HMAC key and the NVS encryption keys::
|
||||
|
||||
python nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_keygen
|
||||
|
||||
.. note:: Encryption key of the format ``<outdir>/keys/keys-<timestamp>.bin`` and HMAC key of the format ``<outdir>/keys/hmac-keys-<timestamp>.bin`` are created.
|
||||
|
||||
- Generate the NVS encryption keys, given the HMAC-key::
|
||||
|
||||
python nvs_partition_gen.py generate-key --key_protect_hmac --kp_hmac_inputkey testdata/sample_hmac_key.bin
|
||||
|
||||
.. note:: You can provide the custom filename for the HMAC key as well as the encryption key as a parameter.
|
||||
|
||||
Generate Encrypted NVS Partition
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Usage**::
|
||||
|
||||
python nvs_partition_gen.py encrypt [-h] [--version {1,2}] [--keygen]
|
||||
[--keyfile KEYFILE] [--inputkey INPUTKEY]
|
||||
[--outdir OUTDIR]
|
||||
[--keyfile KEYFILE] [--inputkey INPUTKEY] [--outdir OUTDIR]
|
||||
[--key_protect_hmac] [--kp_hmac_keygen]
|
||||
[--kp_hmac_keyfile KP_HMAC_KEYFILE] [--kp_hmac_inputkey KP_HMAC_INPUTKEY]
|
||||
input output size
|
||||
|
||||
|
||||
**Positional Arguments**:
|
||||
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+======================================================================+
|
||||
| input | Path to CSV file to parse |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| output | Path to output NVS binary file |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| size | Size of NVS partition in bytes (must be multiple of 4096) |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+===============================================================+
|
||||
| ``input`` | Path to CSV file to parse |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| ``output`` | Path to output NVS binary file |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| ``size`` | Size of NVS partition in bytes (must be multiple of 4096) |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=====================+====================================================================+
|
||||
| -h, --help | Show this help message and exit |
|
||||
| | |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --version {1,2} | Set multipage blob version |
|
||||
| | Version 1 - Multipage blob support disabled |
|
||||
| | Version 2 - Multipage blob support enabled |
|
||||
| | Default: Version 2 |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --keygen | Generates key for encrypting NVS partition |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --keyfile KEYFILE | Path to output encryption keys file |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --inputkey INPUTKEY | File having key for encrypting NVS partition |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --outdir OUTDIR | Output directory to store files created |
|
||||
| | (Default: current directory) |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=============================================+===============================================================================+
|
||||
| ``-h`` \ ``--help`` | Show the help message and exit |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--version {1,2}`` | Set multipage blob version (Default: Version 2) |
|
||||
| | |
|
||||
| | Version 1 - Multipage blob support disabled |
|
||||
| | |
|
||||
| | Version 2 - Multipage blob support enabled |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--keygen`` | Generates key for encrypting NVS partition |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--keyfile KEYFILE`` | Path to output encryption keys file |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--inputkey INPUTKEY`` | File having key for encrypting NVS partition |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--outdir OUTDIR`` | Output directory to store file created (Default: current directory) |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--key_protect_hmac`` | If set, the NVS encryption key protection scheme based on HMAC |
|
||||
| | peripheral is used; else the default scheme based on Flash Encryption |
|
||||
| | is used |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keygen`` | Generate the HMAC key for HMAC-based encryption scheme |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keyfile KP_HMAC_KEYFILE`` | Path to output HMAC key file |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_inputkey KP_HMAC_INPUTKEY`` | File having the HMAC key for generating the NVS encryption keys |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
|
||||
You can run the utility to encrypt NVS partition using the command below. A sample CSV file is provided with the utility:
|
||||
|
||||
@ -237,21 +267,38 @@ You can run the utility to encrypt NVS partition using the command below. A samp
|
||||
|
||||
python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen
|
||||
|
||||
.. note:: Encryption key of the following format ``<outdir>/keys/keys-<timestamp>.bin`` is created.
|
||||
.. note:: Encryption key of the format ``<outdir>/keys/keys-<timestamp>.bin`` is created.
|
||||
|
||||
- To generate an encrypted partition using the HMAC-based scheme, the above command can be used alongwith some additional parameters.
|
||||
|
||||
- Encrypt by allowing the utility to generate encryption keys and the HMAC-key::
|
||||
|
||||
python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen --key_protect_hmac --kp_hmac_keygen
|
||||
|
||||
.. note:: Encryption key of the format ``<outdir>/keys/keys-<timestamp>.bin`` and HMAC key of the format ``<outdir>/keys/hmac-keys-<timestamp>.bin`` are created.
|
||||
|
||||
- Encrypt by allowing the utility to generate encryption keys with user-provided HMAC-key::
|
||||
|
||||
python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen --key_protect_hmac --kp_hmac_inputkey testdata/sample_hmac_key.bin
|
||||
|
||||
.. note:: You can provide the custom filename for the HMAC key as well as the encryption key as a parameter.
|
||||
|
||||
- Encrypt by allowing the utility to generate encryption keys and store it in provided custom filename::
|
||||
|
||||
python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --keygen --keyfile sample_keys.bin
|
||||
|
||||
.. note:: Encryption key of the following format ``<outdir>/keys/sample_keys.bin`` is created.
|
||||
.. note:: This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_key_partition` for more details.
|
||||
.. note::
|
||||
|
||||
- Encryption key of the format ``<outdir>/keys/sample_keys.bin`` is created.
|
||||
|
||||
- This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_encr_key_partition` for more details.
|
||||
|
||||
- Encrypt by providing the encryption keys as input binary file::
|
||||
|
||||
python nvs_partition_gen.py encrypt sample_singlepage_blob.csv sample_encr.bin 0x3000 --inputkey sample_keys.bin
|
||||
|
||||
To Decrypt Encrypted NVS Partition:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Decrypt Encrypted NVS Partition
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Usage**::
|
||||
|
||||
@ -259,26 +306,25 @@ To Decrypt Encrypted NVS Partition:
|
||||
|
||||
**Positional Arguments**:
|
||||
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+======================================================================+
|
||||
| input | Path to encrypted NVS partition file to parse |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| key | Path to file having keys for decryption |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| output | Path to output decrypted binary file |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+===============================================================+
|
||||
| ``input`` | Path to encrypted NVS partition file to parse |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| ``key`` | Path to file having keys for decryption |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
| ``output`` | Path to output decrypted binary file |
|
||||
+--------------+---------------------------------------------------------------+
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=====================+====================================================================+
|
||||
| -h, --help | Show this help message and exit |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --outdir OUTDIR | Output directory to store files created |
|
||||
| | (Default: current directory) |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+========================+======================================================================+
|
||||
| ``-h`` / ``--help`` | Show the help message and exit |
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
| ``--outdir OUTDIR`` | Output directory to store file created (Default: current directory) |
|
||||
+------------------------+----------------------------------------------------------------------+
|
||||
|
||||
You can run the utility to decrypt encrypted NVS partition using the command below::
|
||||
|
||||
@ -289,24 +335,26 @@ You can also provide the format version number:
|
||||
- Multipage Blob Support Enabled (Version 2)
|
||||
|
||||
|
||||
Multipage Blob Support Disabled (Version 1):
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Multipage Blob Support Disabled (Version 1)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can run the utility in this format by setting the version parameter to 1, as shown below. A sample CSV file is provided with the utility::
|
||||
You can run the utility in this format by setting the version parameter to 1, as shown below. A sample CSV file for the same is provided with the utility::
|
||||
|
||||
python nvs_partition_gen.py generate sample_singlepage_blob.csv sample.bin 0x3000 --version 1
|
||||
|
||||
|
||||
Multipage Blob Support Enabled (Version 2):
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Multipage Blob Support Enabled (Version 2)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can run the utility in this format by setting the version parameter to 2, as shown below. A sample CSV file is provided with the utility::
|
||||
You can run the utility in this format by setting the version parameter to 2, as shown below. A sample CSV file for the same is provided with the utility::
|
||||
|
||||
python nvs_partition_gen.py generate sample_multipage_blob.csv sample.bin 0x4000 --version 2
|
||||
|
||||
.. note:: *Minimum NVS Partition Size needed is 0x3000 bytes.*
|
||||
.. note::
|
||||
|
||||
.. note:: *When flashing the binary onto the device, make sure it is consistent with the application's sdkconfig.*
|
||||
- Minimum NVS Partition Size needed is 0x3000 bytes.
|
||||
|
||||
- When flashing the binary onto the device, make sure it is consistent with the application's sdkconfig.
|
||||
|
||||
|
||||
Caveats
|
||||
|
@ -18,11 +18,13 @@ import os
|
||||
import random
|
||||
import struct
|
||||
import sys
|
||||
import textwrap
|
||||
import zlib
|
||||
from io import open
|
||||
|
||||
try:
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, hmac
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
except ImportError:
|
||||
print('The cryptography package is not installed.'
|
||||
@ -44,6 +46,13 @@ def reverse_hexbytes(addr_tmp):
|
||||
return reversed_bytes
|
||||
|
||||
|
||||
def desc_format(*args):
|
||||
desc = ''
|
||||
for arg in args:
|
||||
desc += textwrap.fill(replace_whitespace=False, text=arg) + '\n'
|
||||
return desc
|
||||
|
||||
|
||||
""" Class for standard NVS page structure """
|
||||
|
||||
|
||||
@ -842,16 +851,63 @@ def generate_key(args):
|
||||
distutils.dir_util.mkpath(keys_outdir)
|
||||
keys_outdir, output_keyfile = set_target_filepath(keys_outdir, args.keyfile)
|
||||
|
||||
key = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip()
|
||||
encr_key_bytes = codecs.decode(key, 'hex')
|
||||
key_len = len(encr_key_bytes)
|
||||
|
||||
keys_buf = bytearray(b'\xff') * page_max_size
|
||||
keys_buf[0:key_len] = encr_key_bytes
|
||||
crc_data = keys_buf[0:key_len]
|
||||
crc_data = bytes(crc_data)
|
||||
crc = zlib.crc32(crc_data, 0xFFFFFFFF)
|
||||
struct.pack_into('<I', keys_buf, key_len, crc & 0xFFFFFFFF)
|
||||
key = ''
|
||||
|
||||
if args.key_protect_hmac:
|
||||
HMAC_EKEY_SEED_ELEMENT = b'\x5A\x5A\xBE\xAE'
|
||||
HMAC_TKEY_SEED_ELEMENT = b'\xA5\xA5\xDE\xCE'
|
||||
hmac_key = b''
|
||||
|
||||
if args.kp_hmac_keygen:
|
||||
hmac_key_str = ''.join(random.choice('0123456789abcdef') for _ in range(64)).strip()
|
||||
hmac_key = codecs.decode(hmac_key_str, 'hex')
|
||||
hmac_keyfile = ''
|
||||
|
||||
if args.kp_hmac_keyfile:
|
||||
hmac_keyfile = args.kp_hmac_keyfile
|
||||
else:
|
||||
hmac_keyfile = 'hmac-' + args.keyfile
|
||||
|
||||
hmac_keyfile = set_target_filepath(keys_outdir, hmac_keyfile)[1]
|
||||
with open(hmac_keyfile, 'wb') as hmac_key_file:
|
||||
hmac_key_file.write(hmac_key)
|
||||
else:
|
||||
if not args.kp_hmac_inputkey:
|
||||
raise RuntimeError('HMAC Key input file (HMAC-based encryption scheme) missing!')
|
||||
|
||||
with open(args.kp_hmac_inputkey, 'rb') as input_keys_file:
|
||||
hmac_key = input_keys_file.read()
|
||||
|
||||
ekey_seed = HMAC_EKEY_SEED_ELEMENT * 8
|
||||
h_e = hmac.HMAC(hmac_key, hashes.SHA256())
|
||||
h_e.update(ekey_seed)
|
||||
e_key = h_e.finalize()
|
||||
|
||||
tkey_seed = HMAC_TKEY_SEED_ELEMENT * 8
|
||||
h_t = hmac.HMAC(hmac_key, hashes.SHA256())
|
||||
h_t.update(tkey_seed)
|
||||
t_key = h_t.finalize()
|
||||
|
||||
encr_key_bytes = e_key + t_key
|
||||
key_len = len(encr_key_bytes)
|
||||
key = f"{int.from_bytes(encr_key_bytes, 'big'):x}"
|
||||
|
||||
keys_buf[0:key_len] = encr_key_bytes
|
||||
crc_data = keys_buf[0:key_len]
|
||||
crc_data = bytes(crc_data)
|
||||
crc = zlib.crc32(crc_data, 0xFFFFFFFF)
|
||||
struct.pack_into('<I', keys_buf, key_len, crc & 0xFFFFFFFF)
|
||||
else:
|
||||
key = ''.join(random.choice('0123456789abcdef') for _ in range(128)).strip()
|
||||
encr_key_bytes = codecs.decode(key, 'hex')
|
||||
key_len = len(encr_key_bytes)
|
||||
|
||||
keys_buf[0:key_len] = encr_key_bytes
|
||||
crc_data = keys_buf[0:key_len]
|
||||
crc_data = bytes(crc_data)
|
||||
crc = zlib.crc32(crc_data, 0xFFFFFFFF)
|
||||
struct.pack_into('<I', keys_buf, key_len, crc & 0xFFFFFFFF)
|
||||
|
||||
with open(output_keyfile, 'wb') as output_keys_file:
|
||||
output_keys_file.write(keys_buf)
|
||||
@ -918,101 +974,126 @@ def generate(args, is_encr_enabled=False, encr_key=None):
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='\nESP NVS partition generation utility', formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser = argparse.ArgumentParser(description=desc_format('ESP NVS partition generation utility'), formatter_class=argparse.RawTextHelpFormatter)
|
||||
subparser = parser.add_subparsers(title='Commands',
|
||||
dest='command',
|
||||
help='\nRun nvs_partition_gen.py {command} -h for additional help\n\n')
|
||||
help=desc_format('Run nvs_partition_gen.py {command} -h for additional help'))
|
||||
|
||||
parser_gen = subparser.add_parser('generate',
|
||||
help='Generate NVS partition',
|
||||
help=desc_format('Generate NVS partition'),
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser_gen.set_defaults(func=generate)
|
||||
parser_gen.add_argument('input',
|
||||
default=None,
|
||||
help='Path to CSV file to parse')
|
||||
help=desc_format('Path to CSV file to parse'))
|
||||
parser_gen.add_argument('output',
|
||||
default=None,
|
||||
help='Path to output NVS binary file')
|
||||
help=desc_format('Path to output NVS binary file'))
|
||||
parser_gen.add_argument('size',
|
||||
default=None,
|
||||
help='Size of NVS partition in bytes\
|
||||
\n(must be multiple of 4096)')
|
||||
help=desc_format('Size of NVS partition in bytes (must be multiple of 4096)'))
|
||||
parser_gen.add_argument('--version',
|
||||
choices=[1,2],
|
||||
default=2,
|
||||
type=int,
|
||||
help='''Set multipage blob version.\
|
||||
\nVersion 1 - Multipage blob support disabled.\
|
||||
\nVersion 2 - Multipage blob support enabled.\
|
||||
\nDefault: Version 2''')
|
||||
help=desc_format(
|
||||
'Set multipage blob version.',
|
||||
'Version 1 - Multipage blob support disabled.',
|
||||
'Version 2 - Multipage blob support enabled.',
|
||||
'Default: Version 2'))
|
||||
parser_gen.add_argument('--outdir',
|
||||
default=os.getcwd(),
|
||||
help='Output directory to store files created\
|
||||
\n(Default: current directory)')
|
||||
help=desc_format('Output directory to store files created (Default: current directory)'))
|
||||
parser_gen_key = subparser.add_parser('generate-key',
|
||||
help='Generate keys for encryption',
|
||||
help=desc_format('Generate keys for encryption'),
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser_gen_key.set_defaults(func=generate_key)
|
||||
parser_gen_key.add_argument('--key_protect_hmac',
|
||||
action='store_true',
|
||||
help=desc_format(
|
||||
'If set, the NVS encryption key protection scheme based on HMAC',
|
||||
'peripheral is used; else the default scheme based on Flash Encryption',
|
||||
'is used'))
|
||||
parser_gen_key.add_argument('--kp_hmac_keygen',
|
||||
action='store_true',
|
||||
help=desc_format('Generate the HMAC key for HMAC-based encryption scheme'))
|
||||
parser_gen_key.add_argument('--kp_hmac_keyfile',
|
||||
default=None,
|
||||
help=desc_format('Path to output HMAC key file'))
|
||||
parser_gen_key.add_argument('--kp_hmac_inputkey',
|
||||
default=None,
|
||||
help=desc_format('File having the HMAC key for generating the NVS encryption keys'))
|
||||
parser_gen_key.add_argument('--keyfile',
|
||||
default=None,
|
||||
help='Path to output encryption keys file')
|
||||
help=desc_format('Path to output encryption keys file'))
|
||||
parser_gen_key.add_argument('--outdir',
|
||||
default=os.getcwd(),
|
||||
help='Output directory to store files created.\
|
||||
\n(Default: current directory)')
|
||||
help=desc_format('Output directory to store files created. (Default: current directory)'))
|
||||
parser_encr = subparser.add_parser('encrypt',
|
||||
help='Generate NVS encrypted partition',
|
||||
help=desc_format('Generate NVS encrypted partition'),
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser_encr.set_defaults(func=encrypt)
|
||||
parser_encr.add_argument('input',
|
||||
default=None,
|
||||
help='Path to CSV file to parse')
|
||||
help=desc_format('Path to CSV file to parse'))
|
||||
parser_encr.add_argument('output',
|
||||
default=None,
|
||||
help='Path to output NVS binary file')
|
||||
help=desc_format('Path to output NVS binary file'))
|
||||
parser_encr.add_argument('size',
|
||||
default=None,
|
||||
help='Size of NVS partition in bytes\
|
||||
\n(must be multiple of 4096)')
|
||||
help=desc_format('Size of NVS partition in bytes (must be multiple of 4096)'))
|
||||
parser_encr.add_argument('--version',
|
||||
choices=[1,2],
|
||||
default=2,
|
||||
type=int,
|
||||
help='''Set multipage blob version.\
|
||||
\nVersion 1 - Multipage blob support disabled.\
|
||||
\nVersion 2 - Multipage blob support enabled.\
|
||||
\nDefault: Version 2''')
|
||||
help=desc_format(
|
||||
'Set multipage blob version.',
|
||||
'Version 1 - Multipage blob support disabled.',
|
||||
'Version 2 - Multipage blob support enabled.',
|
||||
'Default: Version 2'))
|
||||
parser_encr.add_argument('--keygen',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Generates key for encrypting NVS partition')
|
||||
help=desc_format('Generates key for encrypting NVS partition'))
|
||||
parser_encr.add_argument('--keyfile',
|
||||
default=None,
|
||||
help='Path to output encryption keys file')
|
||||
help=desc_format('Path to output encryption keys file'))
|
||||
parser_encr.add_argument('--inputkey',
|
||||
default=None,
|
||||
help='File having key for encrypting NVS partition')
|
||||
help=desc_format('File having key for encrypting NVS partition'))
|
||||
parser_encr.add_argument('--outdir',
|
||||
default=os.getcwd(),
|
||||
help='Output directory to store files created.\
|
||||
\n(Default: current directory)')
|
||||
help=desc_format('Output directory to store files created. (Default: current directory)'))
|
||||
parser_encr.add_argument('--key_protect_hmac',
|
||||
action='store_true',
|
||||
help=desc_format(
|
||||
'If set, the NVS encryption key protection scheme based on HMAC',
|
||||
'peripheral is used; else the default scheme based on Flash Encryption',
|
||||
'is used'))
|
||||
parser_encr.add_argument('--kp_hmac_keygen',
|
||||
action='store_true',
|
||||
help=desc_format('Generate the HMAC key for HMAC-based encryption scheme'))
|
||||
parser_encr.add_argument('--kp_hmac_keyfile',
|
||||
default=None,
|
||||
help=desc_format('Path to output HMAC key file'))
|
||||
parser_encr.add_argument('--kp_hmac_inputkey',
|
||||
default=None,
|
||||
help=desc_format('File having the HMAC key for generating the NVS encryption keys'))
|
||||
parser_decr = subparser.add_parser('decrypt',
|
||||
help='Decrypt NVS encrypted partition',
|
||||
help=desc_format('Decrypt NVS encrypted partition'),
|
||||
formatter_class=argparse.RawTextHelpFormatter)
|
||||
parser_decr.set_defaults(func=decrypt)
|
||||
parser_decr.add_argument('input',
|
||||
default=None,
|
||||
help='Path to encrypted NVS partition file to parse')
|
||||
help=desc_format('Path to encrypted NVS partition file to parse'))
|
||||
parser_decr.add_argument('key',
|
||||
default=None,
|
||||
help='Path to file having keys for decryption')
|
||||
help=desc_format('Path to file having keys for decryption'))
|
||||
parser_decr.add_argument('output',
|
||||
default=None,
|
||||
help='Path to output decrypted binary file')
|
||||
parser_decr.add_argument('--outdir',
|
||||
default=os.getcwd(),
|
||||
help='Output directory to store files created.\
|
||||
\n(Default: current directory)')
|
||||
help=desc_format('Output directory to store files created. (Default: current directory)'))
|
||||
args = parser.parse_args()
|
||||
|
||||
args.func(args)
|
||||
|
13
components/nvs_flash/nvs_partition_generator/sample_val.csv
Normal file
13
components/nvs_flash/nvs_partition_generator/sample_val.csv
Normal file
@ -0,0 +1,13 @@
|
||||
# Sample csv file
|
||||
key,type,encoding,value
|
||||
storage,namespace,,
|
||||
u8_key,data,u8,255
|
||||
i8_key,data,i8,-128
|
||||
u16_key,data,u16,65535
|
||||
u32_key,data,u32,4294967295
|
||||
i32_key,data,i32,-2147483648
|
||||
str_key,data,string,"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Fusce quis risus justo.
|
||||
Suspendisse egestas in nisi sit amet auctor.
|
||||
Pellentesque rhoncus dictum sodales.
|
||||
In justo erat, viverra at interdum eget, interdum vel dui."
|
Can't render this file because it has a wrong number of fields in line 2.
|
1
components/nvs_flash/nvs_partition_generator/testdata/sample_encryption_keys_hmac.bin
vendored
Normal file
1
components/nvs_flash/nvs_partition_generator/testdata/sample_encryption_keys_hmac.bin
vendored
Normal file
@ -0,0 +1 @@
|
||||
˙i‰äúý-ŚłŞWCđ?›Š,…‡‡(2F‚ŕŕSŤ˝śŽ+§Q7vŚ<"ŰKŕVÚř«üšĎô:o“<1D>s¬“ÚW /˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙
|
2
components/nvs_flash/nvs_partition_generator/testdata/sample_hmac_key.bin
vendored
Normal file
2
components/nvs_flash/nvs_partition_generator/testdata/sample_hmac_key.bin
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
@ -23,6 +23,12 @@
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "nvs";
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for the active default security scheme
|
||||
* for NVS Encryption
|
||||
*/
|
||||
static nvs_sec_scheme_t nvs_sec_default_scheme_cfg;
|
||||
|
||||
class NVSHandleEntry : public intrusive_list_node<NVSHandleEntry>, public ExceptionlessAllocatable {
|
||||
public:
|
||||
NVSHandleEntry(nvs::NVSHandleSimple *handle, const char* part_name)
|
||||
@ -133,28 +139,20 @@ extern "C" esp_err_t nvs_flash_init(void)
|
||||
{
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
const esp_partition_t *key_part = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
|
||||
if (key_part == NULL) {
|
||||
ESP_LOGE(TAG, "CONFIG_NVS_ENCRYPTION is enabled, but no partition with subtype nvs_keys found in the partition table.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
nvs_sec_cfg_t cfg = {};
|
||||
ret = nvs_flash_read_security_cfg(key_part, &cfg);
|
||||
if (ret == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) {
|
||||
ESP_LOGI(TAG, "NVS key partition empty, generating keys");
|
||||
ret = nvs_flash_generate_keys(key_part, &cfg);
|
||||
|
||||
ret = nvs_flash_read_security_cfg_v2(&nvs_sec_default_scheme_cfg, &cfg);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret));
|
||||
ESP_LOGI(TAG, "Generating NVS encr-keys...");
|
||||
ret = nvs_flash_generate_keys_v2(&nvs_sec_default_scheme_cfg, &cfg);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate keys: [0x%02X] (%s)", ret, esp_err_to_name(ret));
|
||||
ESP_LOGE(TAG, "Failed to generate NVS encr-keys: [0x%02X] (%s)", ret, esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
} else if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, &cfg);
|
||||
ret = nvs_flash_secure_init(&cfg);
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_LOGE(TAG, "Failed to initialize NVS partition: [0x%02X] (%s)", ret, esp_err_to_name(ret));
|
||||
return ret;
|
||||
@ -166,7 +164,6 @@ extern "C" esp_err_t nvs_flash_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
extern "C" esp_err_t nvs_flash_secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
esp_err_t lock_result = Lock::init();
|
||||
@ -182,7 +179,6 @@ extern "C" esp_err_t nvs_flash_secure_init(nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
return nvs_flash_secure_init_partition(NVS_DEFAULT_PART_NAME, cfg);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" esp_err_t nvs_flash_erase_partition(const char *part_name)
|
||||
{
|
||||
@ -567,7 +563,7 @@ extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* use
|
||||
return err;
|
||||
}
|
||||
|
||||
#if (defined CONFIG_NVS_ENCRYPTION) && (!defined LINUX_TARGET)
|
||||
#ifndef LINUX_TARGET
|
||||
|
||||
extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
@ -704,7 +700,39 @@ extern "C" esp_err_t nvs_flash_read_security_cfg(const esp_partition_t* partitio
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // ! LINUX_TARGET
|
||||
|
||||
extern "C" esp_err_t nvs_flash_register_security_scheme(nvs_sec_scheme_t *scheme_cfg)
|
||||
{
|
||||
if (scheme_cfg == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
memcpy(&nvs_sec_default_scheme_cfg, scheme_cfg, sizeof(nvs_sec_scheme_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
extern "C" nvs_sec_scheme_t *nvs_flash_get_default_security_scheme(void)
|
||||
{
|
||||
return &nvs_sec_default_scheme_cfg;
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_generate_keys_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (scheme_cfg == nullptr || cfg == nullptr || scheme_cfg->nvs_flash_key_gen == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return (scheme_cfg->nvs_flash_key_gen)(scheme_cfg->scheme_data, cfg);
|
||||
}
|
||||
|
||||
extern "C" esp_err_t nvs_flash_read_security_cfg_v2(nvs_sec_scheme_t *scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (scheme_cfg == nullptr || cfg == nullptr || scheme_cfg->nvs_flash_read_cfg == nullptr) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return (scheme_cfg->nvs_flash_read_cfg)(scheme_cfg->scheme_data, cfg);
|
||||
}
|
||||
|
||||
static nvs_iterator_t create_iterator(nvs::Storage *storage, nvs_type_t type)
|
||||
{
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include "esp_partition.h"
|
||||
#include "nvs_partition_lookup.hpp"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#ifndef LINUX_TARGET
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
#endif // ! LINUX_TARGET
|
||||
|
||||
namespace nvs {
|
||||
|
||||
@ -32,7 +32,7 @@ esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#ifndef LINUX_TARGET
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p)
|
||||
{
|
||||
const esp_partition_t* esp_partition = esp_partition_find_first(
|
||||
@ -61,8 +61,7 @@ esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg,
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
#endif // ! LINUX_TARGET
|
||||
|
||||
} // partition_lookup
|
||||
|
||||
|
@ -11,9 +11,7 @@ namespace partition_lookup {
|
||||
|
||||
esp_err_t lookup_nvs_partition(const char* label, NVSPartition **p);
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t lookup_nvs_encrypted_partition(const char* label, nvs_sec_cfg_t* cfg, NVSPartition **p);
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
} // partition_lookup
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include "nvs_partition_lookup.hpp"
|
||||
#include "nvs_internal.h"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#ifndef LINUX_TARGET
|
||||
#include "nvs_encrypted_partition.hpp"
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
#endif // ! LINUX_TARGET
|
||||
|
||||
namespace nvs {
|
||||
|
||||
@ -100,7 +100,6 @@ esp_err_t NVSPartitionManager::init_custom(Partition *partition, uint32_t baseSe
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#ifdef ESP_PLATFORM
|
||||
esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
@ -140,7 +139,6 @@ esp_err_t NVSPartitionManager::secure_init_partition(const char *part_name, nvs_
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // ESP_PLATFORM
|
||||
#endif // CONFIG_NVS_ENCRYPTION
|
||||
|
||||
esp_err_t NVSPartitionManager::deinit_partition(const char *partition_label)
|
||||
{
|
||||
|
@ -24,9 +24,7 @@ public:
|
||||
|
||||
esp_err_t init_custom(Partition *partition, uint32_t baseSector, uint32_t sectorCount);
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
esp_err_t secure_init_partition(const char *part_name, nvs_sec_cfg_t* cfg);
|
||||
#endif
|
||||
|
||||
esp_err_t deinit_partition(const char *partition_label);
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash bootloader_support spi_flash
|
||||
EMBED_TXTFILES encryption_keys.bin partition_encrypted.bin sample.bin
|
||||
PRIV_REQUIRES cmock test_utils nvs_flash nvs_sec_provider
|
||||
bootloader_support spi_flash
|
||||
EMBED_TXTFILES encryption_keys.bin partition_encrypted.bin
|
||||
partition_encrypted_hmac.bin sample.bin
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
if(CONFIG_NVS_ENCRYPTION)
|
||||
if(CONFIG_NVS_ENCRYPTION OR CONFIG_SOC_HMAC_SUPPORTED)
|
||||
target_link_libraries(${COMPONENT_LIB} PUBLIC idf::mbedtls)
|
||||
endif()
|
||||
|
BIN
components/nvs_flash/test_apps/main/partition_encrypted_hmac.bin
Normal file
BIN
components/nvs_flash/test_apps/main/partition_encrypted_hmac.bin
Normal file
Binary file not shown.
BIN
components/nvs_flash/test_apps/main/partition_plaintext.bin
Normal file
BIN
components/nvs_flash/test_apps/main/partition_plaintext.bin
Normal file
Binary file not shown.
@ -19,13 +19,19 @@
|
||||
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs_sec_provider.h"
|
||||
|
||||
#include "unity.h"
|
||||
#include "memory_checks.h"
|
||||
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
#include "mbedtls/aes.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOC_HMAC_SUPPORTED
|
||||
#include "esp_hmac.h"
|
||||
#endif
|
||||
|
||||
static const char* TAG = "test_nvs";
|
||||
|
||||
TEST_CASE("Partition name no longer than 16 characters", "[nvs]")
|
||||
@ -89,7 +95,58 @@ TEST_CASE("nvs_flash_init_partition_ptr() works correctly", "[nvs]")
|
||||
|
||||
nvs_flash_deinit();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOC_HMAC_SUPPORTED
|
||||
/* TODO: This test does not run in CI as the runner assigned has
|
||||
* flash encryption enabled by default. Enabling flash encryption
|
||||
* 'selects' NVS encryption; a new runner needs to be setup
|
||||
* for testing the HMAC NVS encryption scheme without flash encryption
|
||||
* enabled for this test.
|
||||
*/
|
||||
TEST_CASE("test nvs encryption with HMAC-based scheme without toggling any config options", "[nvs_encr_hmac]")
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
|
||||
nvs_sec_cfg_t cfg = {};
|
||||
nvs_sec_scheme_t *sec_scheme_handle = NULL;
|
||||
|
||||
nvs_sec_config_hmac_t sec_scheme_cfg = {};
|
||||
hmac_key_id_t hmac_key = HMAC_KEY0;
|
||||
sec_scheme_cfg.hmac_key_id = hmac_key;
|
||||
|
||||
TEST_ESP_OK(nvs_sec_provider_register_hmac(&sec_scheme_cfg, &sec_scheme_handle));
|
||||
|
||||
esp_err_t err = nvs_flash_read_security_cfg_v2(sec_scheme_handle, &cfg);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND) {
|
||||
TEST_ESP_OK(nvs_flash_generate_keys_v2(sec_scheme_handle, &cfg));
|
||||
}
|
||||
TEST_ESP_OK(err);
|
||||
}
|
||||
|
||||
TEST_ESP_OK(nvs_flash_secure_init(&cfg));
|
||||
memset(&cfg, 0x00, sizeof(nvs_sec_cfg_t));
|
||||
|
||||
int32_t foo = 0;
|
||||
|
||||
TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_set_i32(handle, "foo", 0x12345678));
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_get_i32(handle, "foo", &foo));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT32(foo, 0x12345678);
|
||||
|
||||
TEST_ESP_OK(nvs_sec_provider_deregister(sec_scheme_handle));
|
||||
|
||||
TEST_ESP_OK(nvs_flash_deinit());
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
}
|
||||
#endif // CONFIG_SOC_HMAC_SUPPORTED
|
||||
#endif // !CONFIG_NVS_ENCRYPTION
|
||||
|
||||
// test could have different output on host tests
|
||||
TEST_CASE("nvs deinit with open handle", "[nvs]")
|
||||
@ -334,29 +391,31 @@ TEST_CASE("check for memory leaks in nvs_set_blob", "[nvs]")
|
||||
#ifdef CONFIG_NVS_ENCRYPTION
|
||||
TEST_CASE("check underlying xts code for 32-byte size sector encryption", "[nvs]")
|
||||
{
|
||||
uint8_t eky_hex[2 * NVS_KEY_SIZE] = { 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
/* Tweak key below*/
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22 };
|
||||
uint8_t eky_hex[2 * NVS_KEY_SIZE] = { /* Encryption key below*/
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
|
||||
/* Tweak key below*/
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22 };
|
||||
|
||||
|
||||
uint8_t ba_hex[16] = { 0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
|
||||
|
||||
uint8_t ptxt_hex[32] = { 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
|
||||
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
|
||||
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
|
||||
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44 };
|
||||
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
|
||||
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
|
||||
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44 };
|
||||
|
||||
|
||||
uint8_t ctxt_hex[32] = { 0xe6,0x22,0x33,0x4f,0x18,0x4b,0xbc,0xe1,
|
||||
0x29,0xa2,0x5b,0x2a,0xc7,0x6b,0x3d,0x92,
|
||||
0xab,0xf9,0x8e,0x22,0xdf,0x5b,0xdd,0x15,
|
||||
0xaf,0x47,0x1f,0x3d,0xb8,0x94,0x6a,0x85 };
|
||||
0x29,0xa2,0x5b,0x2a,0xc7,0x6b,0x3d,0x92,
|
||||
0xab,0xf9,0x8e,0x22,0xdf,0x5b,0xdd,0x15,
|
||||
0xaf,0x47,0x1f,0x3d,0xb8,0x94,0x6a,0x85 };
|
||||
|
||||
mbedtls_aes_xts_context ectx[1];
|
||||
mbedtls_aes_xts_context dctx[1];
|
||||
@ -375,27 +434,34 @@ TEST_CASE("check underlying xts code for 32-byte size sector encryption", "[nvs]
|
||||
TEST_CASE("Check nvs key partition APIs (read and generate keys)", "[nvs]")
|
||||
{
|
||||
nvs_sec_cfg_t cfg, cfg2;
|
||||
|
||||
const esp_partition_t* key_part = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
|
||||
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
if (!esp_flash_encryption_enabled()) {
|
||||
TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_key partition related tests");
|
||||
}
|
||||
|
||||
const esp_partition_t* key_part = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
|
||||
|
||||
TEST_ESP_OK(esp_partition_erase_range(key_part, 0, key_part->size));
|
||||
TEST_ESP_ERR(ESP_ERR_NVS_KEYS_NOT_INITIALIZED, nvs_flash_read_security_cfg(key_part, &cfg));
|
||||
|
||||
TEST_ESP_OK(nvs_flash_generate_keys(key_part, &cfg));
|
||||
|
||||
TEST_ESP_OK(nvs_flash_read_security_cfg(key_part, &cfg2));
|
||||
#elif CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
nvs_sec_scheme_t *scheme_cfg = nvs_flash_get_default_security_scheme();
|
||||
assert(scheme_cfg != NULL);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_generate_keys_v2(scheme_cfg, &cfg));
|
||||
|
||||
TEST_ESP_OK(nvs_flash_read_security_cfg_v2(scheme_cfg, &cfg2));
|
||||
#endif
|
||||
TEST_ASSERT_TRUE(!memcmp(&cfg, &cfg2, sizeof(nvs_sec_cfg_t)));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("test nvs apis with encryption enabled", "[nvs]")
|
||||
{
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
if (!esp_flash_encryption_enabled()) {
|
||||
TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled");
|
||||
}
|
||||
@ -404,19 +470,23 @@ TEST_CASE("test nvs apis with encryption enabled", "[nvs]")
|
||||
|
||||
assert(key_part && "partition table must have an NVS Key partition");
|
||||
|
||||
ESP_ERROR_CHECK(esp_partition_erase_range(key_part, 0, key_part->size));
|
||||
#endif
|
||||
|
||||
const esp_partition_t* nvs_partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
|
||||
assert(nvs_partition && "partition table must have an NVS partition");
|
||||
|
||||
ESP_ERROR_CHECK( esp_partition_erase_range(key_part, 0, key_part->size) );
|
||||
|
||||
bool done = false;
|
||||
|
||||
do {
|
||||
ESP_ERROR_CHECK( esp_partition_erase_range(nvs_partition, 0, nvs_partition->size) );
|
||||
|
||||
nvs_sec_cfg_t cfg;
|
||||
esp_err_t err = nvs_flash_read_security_cfg(key_part, &cfg);
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
ESP_ERROR_CHECK(esp_partition_erase_range(nvs_partition, 0, nvs_partition->size));
|
||||
|
||||
err = nvs_flash_read_security_cfg(key_part, &cfg);
|
||||
|
||||
if(err == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) {
|
||||
uint8_t value[4096] = {[0 ... 4095] = 0xff};
|
||||
@ -430,6 +500,23 @@ TEST_CASE("test nvs apis with encryption enabled", "[nvs]")
|
||||
ESP_ERROR_CHECK(err);
|
||||
done = true;
|
||||
}
|
||||
#elif CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
nvs_sec_scheme_t *scheme_cfg = nvs_flash_get_default_security_scheme();
|
||||
assert(scheme_cfg != NULL);
|
||||
|
||||
err = nvs_flash_read_security_cfg_v2(scheme_cfg, &cfg);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND) {
|
||||
TEST_ESP_OK(nvs_flash_generate_keys_v2(scheme_cfg, &cfg));
|
||||
} else {
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
} else {
|
||||
ESP_ERROR_CHECK(err);
|
||||
done = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_ESP_OK(nvs_flash_secure_init(&cfg));
|
||||
|
||||
nvs_handle_t handle_1;
|
||||
@ -484,45 +571,59 @@ TEST_CASE("test nvs apis with encryption enabled", "[nvs]")
|
||||
|
||||
TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled", "[nvs_part_gen]")
|
||||
{
|
||||
|
||||
if (!esp_flash_encryption_enabled()) {
|
||||
TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled");
|
||||
}
|
||||
|
||||
nvs_handle_t handle;
|
||||
nvs_sec_cfg_t xts_cfg;
|
||||
|
||||
extern const char nvs_key_start[] asm("_binary_encryption_keys_bin_start");
|
||||
extern const char nvs_key_end[] asm("_binary_encryption_keys_bin_end");
|
||||
|
||||
extern const char nvs_data_start[] asm("_binary_partition_encrypted_bin_start");
|
||||
|
||||
extern const char sample_bin_start[] asm("_binary_sample_bin_start");
|
||||
|
||||
const esp_partition_t* key_part = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
const esp_partition_t* nvs_part = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
|
||||
|
||||
assert(key_part && "partition table must have a KEY partition");
|
||||
TEST_ASSERT_TRUE((nvs_key_end - nvs_key_start - 1) == SPI_FLASH_SEC_SIZE);
|
||||
|
||||
assert(nvs_part && "partition table must have an NVS partition");
|
||||
printf("\n nvs_part size:%" PRId32 "\n", nvs_part->size);
|
||||
|
||||
ESP_ERROR_CHECK(esp_partition_erase_range(nvs_part, 0, nvs_part->size));
|
||||
|
||||
extern const char sample_bin_start[] asm("_binary_sample_bin_start");
|
||||
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
if (!esp_flash_encryption_enabled()) {
|
||||
TEST_IGNORE_MESSAGE("flash encryption disabled, skipping nvs_api tests with encryption enabled");
|
||||
}
|
||||
|
||||
extern const char nvs_key_start[] asm("_binary_encryption_keys_bin_start");
|
||||
extern const char nvs_key_end[] asm("_binary_encryption_keys_bin_end");
|
||||
extern const char nvs_data_sch0_start[] asm("_binary_partition_encrypted_bin_start");
|
||||
|
||||
const esp_partition_t* key_part = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL);
|
||||
|
||||
assert(key_part && "partition table must have a KEY partition");
|
||||
TEST_ASSERT_TRUE((nvs_key_end - nvs_key_start - 1) == SPI_FLASH_SEC_SIZE);
|
||||
|
||||
ESP_ERROR_CHECK(esp_partition_erase_range(key_part, 0, key_part->size));
|
||||
ESP_ERROR_CHECK( esp_partition_erase_range(nvs_part, 0, nvs_part->size) );
|
||||
|
||||
for (int i = 0; i < key_part->size; i+= SPI_FLASH_SEC_SIZE) {
|
||||
ESP_ERROR_CHECK( esp_partition_write(key_part, i, nvs_key_start + i, SPI_FLASH_SEC_SIZE) );
|
||||
}
|
||||
|
||||
for (int i = 0; i < nvs_part->size; i+= SPI_FLASH_SEC_SIZE) {
|
||||
ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_start + i, SPI_FLASH_SEC_SIZE) );
|
||||
ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_sch0_start + i, SPI_FLASH_SEC_SIZE) );
|
||||
}
|
||||
|
||||
esp_err_t err = nvs_flash_read_security_cfg(key_part, &xts_cfg);
|
||||
err = nvs_flash_read_security_cfg(key_part, &xts_cfg);
|
||||
#elif CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
extern const char nvs_data_sch1_start[] asm("_binary_partition_encrypted_hmac_bin_start");
|
||||
|
||||
for (int i = 0; i < nvs_part->size; i+= SPI_FLASH_SEC_SIZE) {
|
||||
ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_sch1_start + i, SPI_FLASH_SEC_SIZE) );
|
||||
}
|
||||
|
||||
nvs_sec_scheme_t *scheme_cfg = nvs_flash_get_default_security_scheme();
|
||||
assert(scheme_cfg != NULL);
|
||||
|
||||
err = nvs_flash_read_security_cfg_v2(scheme_cfg, &xts_cfg);
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_secure_init(&xts_cfg));
|
||||
@ -583,4 +684,46 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena
|
||||
TEST_ESP_OK(nvs_flash_deinit());
|
||||
|
||||
}
|
||||
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
TEST_CASE("test nvs encryption with Flash Encryption-based scheme with v2 apis", "[nvs]")
|
||||
{
|
||||
nvs_handle_t handle;
|
||||
|
||||
nvs_sec_cfg_t cfg = {};
|
||||
nvs_sec_scheme_t *sec_scheme_handle = NULL;
|
||||
nvs_sec_config_flash_enc_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_FLASH_ENC_DEFAULT();
|
||||
|
||||
TEST_ESP_OK(nvs_sec_provider_register_flash_enc(&sec_scheme_cfg, &sec_scheme_handle));
|
||||
|
||||
esp_err_t err = nvs_flash_read_security_cfg_v2(sec_scheme_handle, &cfg);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NVS_KEYS_NOT_INITIALIZED) {
|
||||
TEST_ESP_OK(nvs_flash_generate_keys_v2(sec_scheme_handle, &cfg));
|
||||
}
|
||||
TEST_ESP_OK(err);
|
||||
}
|
||||
|
||||
TEST_ESP_OK(nvs_flash_secure_init(&cfg));
|
||||
memset(&cfg, 0x00, sizeof(nvs_sec_cfg_t));
|
||||
|
||||
int32_t foo = 0;
|
||||
|
||||
TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_set_i32(handle, "foo", 0x12345678));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ESP_OK(nvs_open("uninit_ns", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_get_i32(handle, "foo", &foo));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT32(foo, 0x12345678);
|
||||
|
||||
TEST_ESP_OK(nvs_sec_provider_deregister(sec_scheme_handle));
|
||||
|
||||
TEST_ESP_OK(nvs_flash_deinit());
|
||||
TEST_ESP_OK(nvs_flash_erase());
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -4,23 +4,31 @@
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
CONFIGS_NVS_ENCR_FLASH_ENC = [
|
||||
pytest.param('nvs_encr_flash_enc_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('nvs_encr_flash_enc_esp32c3', marks=[pytest.mark.esp32c3]),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.supported_targets
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize('config', ['default'], indirect=True)
|
||||
def test_nvs_flash(dut: IdfDut) -> None:
|
||||
dut.expect_exact('Press ENTER to see the list of tests')
|
||||
dut.write('![nvs_encr_hmac]')
|
||||
dut.expect_unity_test_output(timeout=120)
|
||||
|
||||
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.nvs_encr_hmac
|
||||
@pytest.mark.parametrize('config', ['nvs_encr_hmac_esp32c3'], indirect=True)
|
||||
def test_nvs_flash_encr_hmac(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
CONFIGS_NVS_ENCR_KEYS_FLASH_ENC = [
|
||||
pytest.param('nvs_encr_keys_flash_enc_esp32', marks=[pytest.mark.esp32]),
|
||||
pytest.param('nvs_encr_keys_flash_enc_esp32c3', marks=[pytest.mark.esp32c3]),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('config', CONFIGS_NVS_ENCR_KEYS_FLASH_ENC, indirect=True)
|
||||
@pytest.mark.flash_encryption
|
||||
def test_nvs_flash_encr_keys_flash_enc(dut: IdfDut) -> None:
|
||||
@pytest.mark.parametrize('config', CONFIGS_NVS_ENCR_FLASH_ENC, indirect=True)
|
||||
def test_nvs_flash_encr_flash_enc(dut: IdfDut) -> None:
|
||||
# Erase the nvs_key partition
|
||||
dut.serial.erase_partition('nvs_key')
|
||||
dut.run_all_single_board_cases()
|
||||
|
@ -3,8 +3,8 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
# Partition Table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_nvs_encr_keys_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_nvs_encr_keys_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_nvs_encr_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_nvs_encr_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
|
||||
# Enabling Flash Encryption
|
||||
@ -16,3 +16,7 @@ CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
||||
|
||||
# Enabling NVS Encryption (Flash Encryption-based scheme)
|
||||
CONFIG_NVS_ENCRYPTION=y
|
||||
CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC=y
|
@ -3,8 +3,8 @@ CONFIG_IDF_TARGET="esp32c3"
|
||||
|
||||
# Partition Table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_nvs_encr_keys_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_nvs_encr_keys_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_nvs_encr_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_nvs_encr_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
|
||||
# Enabling Flash Encryption
|
||||
@ -16,3 +16,7 @@ CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
||||
|
||||
# Enabling NVS Encryption (Flash Encryption-based scheme)
|
||||
CONFIG_NVS_ENCRYPTION=y
|
||||
CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC=y
|
@ -0,0 +1,24 @@
|
||||
# Restricting to ESP32C3
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
|
||||
# NOTE: The runner for this test-app has flash-encryption enabled
|
||||
# Partition Table
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_nvs_encr_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_nvs_encr_flash_enc.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
|
||||
# Enabling Flash Encryption
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
||||
|
||||
# Enabling NVS Encryption (HMAC-based scheme)
|
||||
CONFIG_NVS_ENCRYPTION=y
|
||||
CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC=y
|
||||
CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID=0
|
@ -33,7 +33,7 @@ else
|
||||
COMPILER := gcc
|
||||
endif
|
||||
|
||||
CPPFLAGS += -I../private_include -I../include -I../src -I../../esp_rom/include -I../../esp_rom/include/linux -I../../log/include -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../esp_partition/include -I ../../hal/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
|
||||
CPPFLAGS += -I../private_include -I../include -I../src -I../../esp_rom/include -I../../esp_rom/include/linux -I../../log/include -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../esp_partition/include -I ../../hal/include -I ../../xtensa/include -I ../../soc/linux/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
|
||||
CFLAGS += -fprofile-arcs -ftest-coverage -DLINUX_TARGET -DLINUX_HOST_LEGACY_TEST
|
||||
CXXFLAGS += -std=c++11 -Wall -Werror -DLINUX_TARGET -DLINUX_HOST_LEGACY_TEST
|
||||
LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage
|
||||
@ -93,10 +93,14 @@ clean: clean-coverage
|
||||
rm -f ../nvs_partition_generator/partition_single_page.bin
|
||||
rm -f ../nvs_partition_generator/partition_multipage_blob.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_hmac.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keyfile.bin
|
||||
rm -f ../nvs_partition_generator/partition_encrypted_using_keygen_hmac.bin
|
||||
rm -f ../nvs_partition_generator/partition_decrypted.bin
|
||||
rm -f ../nvs_partition_generator/partition_decrypted_hmac.bin
|
||||
rm -f ../nvs_partition_generator/partition_encoded.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition-encrypted.bin
|
||||
rm -f ../nvs_partition_generator/Test-1-partition.bin
|
||||
rm -f ../../../tools/mass_mfg/samples/sample_values_multipage_blob_created.csv
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nvs_partition_manager.hpp"
|
||||
#include "nvs_partition.hpp"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/md.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@ -1567,12 +1568,24 @@ TEST_CASE("test decrypt functionality for encrypted data", "[nvs_part_gen]")
|
||||
status = system("python ../nvs_partition_generator/nvs_partition_gen.py encrypt ../nvs_partition_generator/sample_multipage_blob.csv partition_encrypted.bin 0x5000 --inputkey ../nvs_partition_generator/testdata/sample_encryption_keys.bin --outdir ../nvs_partition_generator");
|
||||
CHECK(status == 0);
|
||||
|
||||
//encrypting data from sample_multipage_blob.csv (hmac-based scheme)
|
||||
status = system("python ../nvs_partition_generator/nvs_partition_gen.py encrypt ../nvs_partition_generator/sample_multipage_blob.csv partition_encrypted_hmac.bin 0x5000 --keygen --key_protect_hmac --kp_hmac_inputkey ../nvs_partition_generator/testdata/sample_hmac_key.bin --outdir ../nvs_partition_generator");
|
||||
CHECK(status == 0);
|
||||
|
||||
//decrypting data from partition_encrypted.bin
|
||||
status = system("python ../nvs_partition_generator/nvs_partition_gen.py decrypt ../nvs_partition_generator/partition_encrypted.bin ../nvs_partition_generator/testdata/sample_encryption_keys.bin ../nvs_partition_generator/partition_decrypted.bin");
|
||||
CHECK(status == 0);
|
||||
|
||||
status = system("diff ../nvs_partition_generator/partition_decrypted.bin ../nvs_partition_generator/partition_encoded.bin");
|
||||
CHECK(status == 0);
|
||||
|
||||
//decrypting data from partition_encrypted_hmac.bin
|
||||
status = system("python ../nvs_partition_generator/nvs_partition_gen.py decrypt ../nvs_partition_generator/partition_encrypted_hmac.bin ../nvs_partition_generator/testdata/sample_encryption_keys_hmac.bin ../nvs_partition_generator/partition_decrypted_hmac.bin");
|
||||
CHECK(status == 0);
|
||||
|
||||
status = system("diff ../nvs_partition_generator/partition_decrypted_hmac.bin ../nvs_partition_generator/partition_encoded.bin");
|
||||
CHECK(status == 0);
|
||||
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
|
||||
@ -1757,6 +1770,201 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena
|
||||
|
||||
}
|
||||
|
||||
static void compute_nvs_keys_with_hmac(nvs_sec_cfg_t *cfg, void *hmac_key)
|
||||
{
|
||||
unsigned char key_bytes[32] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 };
|
||||
if (hmac_key != NULL){
|
||||
memcpy(key_bytes, hmac_key, 32);
|
||||
}
|
||||
|
||||
unsigned char ekey_seed[32], tkey_seed[32];
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(ekey_seed); i+=4) {
|
||||
ekey_seed[i] = 0x5A;
|
||||
ekey_seed[i + 1] = 0x5A;
|
||||
ekey_seed[i + 2] = 0xBE;
|
||||
ekey_seed[i + 3] = 0xAE;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < sizeof(tkey_seed); i+=4) {
|
||||
tkey_seed[i] = 0xA5;
|
||||
tkey_seed[i + 1] = 0xA5;
|
||||
tkey_seed[i + 2] = 0xDE;
|
||||
tkey_seed[i + 3] = 0xCE;
|
||||
}
|
||||
|
||||
const mbedtls_md_type_t alg = MBEDTLS_MD_SHA256;
|
||||
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_init(&ctx);
|
||||
|
||||
const mbedtls_md_info_t *info = mbedtls_md_info_from_type(alg);
|
||||
mbedtls_md_setup(&ctx, info, 1);
|
||||
mbedtls_md_hmac_starts(&ctx, key_bytes, sizeof(key_bytes));
|
||||
|
||||
mbedtls_md_hmac_update(&ctx, ekey_seed, sizeof(ekey_seed));
|
||||
mbedtls_md_hmac_finish(&ctx, cfg->eky);
|
||||
|
||||
mbedtls_md_hmac_reset(&ctx);
|
||||
mbedtls_md_hmac_update(&ctx, tkey_seed, sizeof(tkey_seed));
|
||||
mbedtls_md_hmac_finish(&ctx, cfg->tky);
|
||||
|
||||
assert(memcmp(cfg->eky, cfg->tky, NVS_KEY_SIZE));
|
||||
|
||||
mbedtls_md_free(&ctx);
|
||||
}
|
||||
|
||||
TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using keygen (user-provided HMAC-key)", "[nvs_part_gen]")
|
||||
{
|
||||
int childpid = fork();
|
||||
int status;
|
||||
|
||||
if (childpid == 0) {
|
||||
exit(execlp("cp", " cp",
|
||||
"-rf",
|
||||
"../nvs_partition_generator/testdata",
|
||||
".", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
|
||||
if (childpid == 0) {
|
||||
exit(execlp("rm", " rm",
|
||||
"-rf",
|
||||
"../nvs_partition_generator/keys", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../nvs_partition_generator/nvs_partition_gen.py",
|
||||
"encrypt",
|
||||
"../nvs_partition_generator/sample_multipage_blob.csv",
|
||||
"partition_encrypted_using_keygen_hmac.bin",
|
||||
"0x4000",
|
||||
"--keygen",
|
||||
"--key_protect_hmac",
|
||||
"--kp_hmac_inputkey",
|
||||
"../nvs_partition_generator/testdata/sample_hmac_key.bin",
|
||||
"--outdir",
|
||||
"../nvs_partition_generator", NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpiFlashEmulator emu("../nvs_partition_generator/partition_encrypted_using_keygen_hmac.bin");
|
||||
|
||||
nvs_sec_cfg_t cfg;
|
||||
compute_nvs_keys_with_hmac(&cfg, NULL);
|
||||
|
||||
check_nvs_part_gen_args(&emu, NVS_DEFAULT_PART_NAME, 4, "../nvs_partition_generator/testdata/sample_multipage_blob.bin", true, &cfg);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("test nvs apis for nvs partition generator utility with encryption enabled using keygen (dynamically generated HMAC-key)", "[nvs_part_gen]")
|
||||
{
|
||||
int childpid = fork();
|
||||
int status;
|
||||
|
||||
if (childpid == 0) {
|
||||
exit(execlp("cp", " cp",
|
||||
"-rf",
|
||||
"../nvs_partition_generator/testdata",
|
||||
".", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
|
||||
if (childpid == 0) {
|
||||
exit(execlp("rm", " rm",
|
||||
"-rf",
|
||||
"../nvs_partition_generator/keys", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../nvs_partition_generator/nvs_partition_gen.py",
|
||||
"encrypt",
|
||||
"../nvs_partition_generator/sample_multipage_blob.csv",
|
||||
"partition_encrypted_using_keygen_hmac.bin",
|
||||
"0x4000",
|
||||
"--keygen",
|
||||
"--key_protect_hmac",
|
||||
"--kp_hmac_keygen",
|
||||
"--outdir",
|
||||
"../nvs_partition_generator", NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *file;
|
||||
char *filename;
|
||||
char *files;
|
||||
char *file_ext;
|
||||
char *hmac_key_file;
|
||||
|
||||
dir = opendir("../nvs_partition_generator/keys");
|
||||
while ((file = readdir(dir)) != NULL) {
|
||||
filename = file->d_name;
|
||||
file_ext = NULL;
|
||||
files = strrchr(filename, '.');
|
||||
if (files != NULL) {
|
||||
file_ext = files + 1;
|
||||
if (strncmp(file_ext, "bin", 3) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (strstr(filename, "hmac") != NULL) {
|
||||
hmac_key_file = filename;
|
||||
}
|
||||
}
|
||||
|
||||
std::string hmac_key_path = std::string("../nvs_partition_generator/keys/") + std::string(hmac_key_file);
|
||||
SpiFlashEmulator emu("../nvs_partition_generator/partition_encrypted_using_keygen_hmac.bin");
|
||||
|
||||
char hmac_key_buf[32];
|
||||
FILE *fp;
|
||||
fp = fopen(hmac_key_path.c_str(), "rb");
|
||||
fread(hmac_key_buf, sizeof(hmac_key_buf), 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
nvs_sec_cfg_t cfg;
|
||||
compute_nvs_keys_with_hmac(&cfg, hmac_key_buf);
|
||||
|
||||
check_nvs_part_gen_args(&emu, NVS_DEFAULT_PART_NAME, 4, "../nvs_partition_generator/testdata/sample_multipage_blob.bin", true, &cfg);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using sample inputkey", "[mfg_gen]")
|
||||
{
|
||||
int childpid = fork();
|
||||
@ -1969,6 +2177,221 @@ TEST_CASE("check and read data from partition generated via manufacturing utilit
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using new generated key (user-provided HMAC-key)", "[mfg_gen]")
|
||||
{
|
||||
int childpid = fork();
|
||||
int status;
|
||||
|
||||
if (childpid == 0) {
|
||||
exit(execlp("bash", " bash",
|
||||
"-c",
|
||||
"rm -rf ../../../tools/mass_mfg/host_test | \
|
||||
cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \
|
||||
cp -rf ../nvs_partition_generator/testdata . | \
|
||||
mkdir -p ../../../tools/mass_mfg/host_test", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../../../tools/mass_mfg/mfg_gen.py",
|
||||
"generate",
|
||||
"../../../tools/mass_mfg/samples/sample_config.csv",
|
||||
"../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv",
|
||||
"Test",
|
||||
"0x4000",
|
||||
"--version",
|
||||
"2",
|
||||
"--keygen",
|
||||
"--key_protect_hmac",
|
||||
"--kp_hmac_inputkey",
|
||||
"mfg_testdata/sample_hmac_key.bin",
|
||||
"--outdir",
|
||||
"../../../tools/mass_mfg/host_test",NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../nvs_partition_generator/nvs_partition_gen.py",
|
||||
"encrypt",
|
||||
"../../../tools/mass_mfg/host_test/csv/Test-1.csv",
|
||||
"../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin",
|
||||
"0x4000",
|
||||
"--version",
|
||||
"2",
|
||||
"--keygen",
|
||||
"--key_protect_hmac",
|
||||
"--kp_hmac_inputkey",
|
||||
"mfg_testdata/sample_hmac_key.bin", NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin");
|
||||
|
||||
nvs_sec_cfg_t cfg;
|
||||
compute_nvs_keys_with_hmac(&cfg, NULL);
|
||||
|
||||
check_nvs_part_gen_args_mfg(&emu1, NVS_DEFAULT_PART_NAME, 4, "mfg_testdata/sample_multipage_blob.bin", true, &cfg);
|
||||
|
||||
SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin");
|
||||
|
||||
check_nvs_part_gen_args_mfg(&emu2, NVS_DEFAULT_PART_NAME, 4, "testdata/sample_multipage_blob.bin", true, &cfg);
|
||||
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("bash", " bash",
|
||||
"-c",
|
||||
"rm -rf ../../../tools/mass_mfg/host_test | \
|
||||
rm -rf mfg_testdata | \
|
||||
rm -rf testdata", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("check and read data from partition generated via manufacturing utility with encryption enabled using new generated key (dynamically generated HMAC-key)", "[mfg_gen]")
|
||||
{
|
||||
int childpid = fork();
|
||||
int status;
|
||||
|
||||
if (childpid == 0) {
|
||||
exit(execlp("bash", " bash",
|
||||
"-c",
|
||||
"rm -rf ../../../tools/mass_mfg/host_test | \
|
||||
cp -rf ../../../tools/mass_mfg/testdata mfg_testdata | \
|
||||
cp -rf ../nvs_partition_generator/testdata . | \
|
||||
mkdir -p ../../../tools/mass_mfg/host_test", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../../../tools/mass_mfg/mfg_gen.py",
|
||||
"generate-key",
|
||||
"--outdir",
|
||||
"../../../tools/mass_mfg/host_test",
|
||||
"--key_protect_hmac",
|
||||
"--kp_hmac_keygen",
|
||||
"--kp_hmac_keyfile",
|
||||
"hmac_key_host_test.bin",
|
||||
"--keyfile",
|
||||
"encr_keys_host_test.bin", NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../../../tools/mass_mfg/mfg_gen.py",
|
||||
"generate",
|
||||
"../../../tools/mass_mfg/samples/sample_config.csv",
|
||||
"../../../tools/mass_mfg/samples/sample_values_multipage_blob.csv",
|
||||
"Test",
|
||||
"0x4000",
|
||||
"--outdir",
|
||||
"../../../tools/mass_mfg/host_test",
|
||||
"--version",
|
||||
"2",
|
||||
"--inputkey",
|
||||
"../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin", NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("python", "python",
|
||||
"../nvs_partition_generator/nvs_partition_gen.py",
|
||||
"encrypt",
|
||||
"../../../tools/mass_mfg/host_test/csv/Test-1.csv",
|
||||
"../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin",
|
||||
"0x4000",
|
||||
"--version",
|
||||
"2",
|
||||
"--inputkey",
|
||||
"../../../tools/mass_mfg/host_test/keys/encr_keys_host_test.bin", NULL));
|
||||
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
SpiFlashEmulator emu1("../../../tools/mass_mfg/host_test/bin/Test-1.bin");
|
||||
|
||||
char hmac_key_buf[32];
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("../../../tools/mass_mfg/host_test/keys/hmac_key_host_test.bin", "rb");
|
||||
fread(hmac_key_buf, sizeof(hmac_key_buf), 1, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
nvs_sec_cfg_t cfg;
|
||||
compute_nvs_keys_with_hmac(&cfg, hmac_key_buf);
|
||||
|
||||
check_nvs_part_gen_args_mfg(&emu1, NVS_DEFAULT_PART_NAME, 4, "mfg_testdata/sample_multipage_blob.bin", true, &cfg);
|
||||
|
||||
SpiFlashEmulator emu2("../nvs_partition_generator/Test-1-partition-encrypted-hmac.bin");
|
||||
|
||||
check_nvs_part_gen_args_mfg(&emu2, NVS_DEFAULT_PART_NAME, 4, "testdata/sample_multipage_blob.bin", true, &cfg);
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == 0) {
|
||||
exit(execlp("bash", " bash",
|
||||
"-c",
|
||||
"rm -rf keys | \
|
||||
rm -rf mfg_testdata | \
|
||||
rm -rf testdata | \
|
||||
rm -rf ../../../tools/mass_mfg/host_test", NULL));
|
||||
} else {
|
||||
CHECK(childpid > 0);
|
||||
waitpid(childpid, &status, 0);
|
||||
CHECK(WEXITSTATUS(status) == 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Add new tests above */
|
||||
|
12
components/nvs_sec_provider/CMakeLists.txt
Normal file
12
components/nvs_sec_provider/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
idf_component_register(SRCS "nvs_sec_provider.c"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_REQUIRES bootloader_support efuse esp_partition nvs_flash)
|
||||
|
||||
# NOTE: In a case where only the default NVS partition is to be encrypted
|
||||
# and no custom NVS partitions exist, `nvs_flash_init` is the only API that
|
||||
# needs to be called. No API from the `nvs_sec_provider` component is called
|
||||
# as neither the `nvs_flash` component nor the user app depends on it.
|
||||
# Thus, the symbols from this component are not placed in the .map file and
|
||||
# hence the constructor, which initialises the encryption scheme for the default
|
||||
# NVS partition, never executes. The following is a workaround for the same.
|
||||
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u nvs_sec_provider_include_impl")
|
46
components/nvs_sec_provider/Kconfig
Normal file
46
components/nvs_sec_provider/Kconfig
Normal file
@ -0,0 +1,46 @@
|
||||
menu "NVS Security Provider"
|
||||
visible if NVS_ENCRYPTION
|
||||
|
||||
choice NVS_SEC_KEY_PROTECTION_SCHEME
|
||||
prompt "NVS Encryption: Key Protection Scheme"
|
||||
depends on NVS_ENCRYPTION
|
||||
default NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
help
|
||||
This choice defines the default NVS encryption keys protection scheme;
|
||||
which will be used for the default NVS partition.
|
||||
Users can use the corresponding scheme registration APIs to register other
|
||||
schemes for the default as well as other NVS partitions.
|
||||
|
||||
config NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
bool "Using Flash Encryption"
|
||||
depends on SECURE_FLASH_ENC_ENABLED
|
||||
help
|
||||
Protect the NVS Encryption Keys using Flash Encryption
|
||||
Requires a separate 'nvs_keys' partition (which will be encrypted by flash encryption)
|
||||
for storing the NVS encryption keys
|
||||
|
||||
config NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
bool "Using HMAC peripheral"
|
||||
depends on SOC_HMAC_SUPPORTED
|
||||
help
|
||||
Derive and protect the NVS Encryption Keys using the HMAC peripheral
|
||||
Requires the specified eFuse block (NVS_SEC_HMAC_EFUSE_KEY_ID or the v2 API argument)
|
||||
to be empty or pre-written with a key with the purpose ESP_EFUSE_KEY_PURPOSE_HMAC_UP
|
||||
|
||||
endchoice
|
||||
|
||||
config NVS_SEC_HMAC_EFUSE_KEY_ID
|
||||
int "eFuse key ID storing the HMAC key"
|
||||
depends on NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
range 0 6
|
||||
default 6
|
||||
help
|
||||
eFuse block key ID storing the HMAC key for deriving the NVS encryption keys
|
||||
|
||||
Note: The eFuse block key ID required by the HMAC scheme
|
||||
(CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC) is set using this config when the default
|
||||
NVS partition is initialized with nvs_flash_init(). The eFuse block key ID can
|
||||
also be set at runtime by passing the appropriate value to the NVS security scheme
|
||||
registration APIs.
|
||||
|
||||
endmenu
|
114
components/nvs_sec_provider/include/nvs_sec_provider.h
Normal file
114
components/nvs_sec_provider/include/nvs_sec_provider.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_partition.h"
|
||||
|
||||
#if SOC_HMAC_SUPPORTED
|
||||
#include "esp_hmac.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ESP_ERR_NVS_SEC_BASE 0xF000 /*!< Starting number of error codes */
|
||||
|
||||
#define ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND (ESP_ERR_NVS_SEC_BASE + 0x01) /*!< HMAC Key required to generate the NVS encryption keys not found */
|
||||
#define ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED (ESP_ERR_NVS_SEC_BASE + 0x02) /*!< Provided eFuse block for HMAC key generation is already in use */
|
||||
#define ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED (ESP_ERR_NVS_SEC_BASE + 0x03) /*!< Failed to generate/write the HMAC key to eFuse */
|
||||
#define ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED (ESP_ERR_NVS_SEC_BASE + 0x04) /*!< Failed to derive the NVS encryption keys based on the HMAC-based scheme */
|
||||
|
||||
/**
|
||||
* @brief NVS Encryption Keys Protection Scheme
|
||||
*/
|
||||
typedef enum {
|
||||
NVS_SEC_SCHEME_FLASH_ENC = 0, /*!< Protect NVS encryption keys using Flash Encryption */
|
||||
NVS_SEC_SCHEME_HMAC, /*!< Protect NVS encryption keys using HMAC peripheral */
|
||||
NVS_SEC_SCHEME_MAX
|
||||
} nvs_sec_scheme_id_t;
|
||||
|
||||
/**
|
||||
* @brief Flash encryption-based scheme specific configuration data
|
||||
*/
|
||||
typedef struct {
|
||||
const esp_partition_t *nvs_keys_part; /*!< Partition of subtype `nvs_keys` holding the NVS encryption keys */
|
||||
} nvs_sec_config_flash_enc_t;
|
||||
|
||||
/**
|
||||
* @brief Helper for populating the Flash encryption-based scheme specific configuration data
|
||||
*/
|
||||
#define NVS_SEC_PROVIDER_CFG_FLASH_ENC_DEFAULT() { \
|
||||
.nvs_keys_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, \
|
||||
ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, \
|
||||
NULL), \
|
||||
}
|
||||
|
||||
#if SOC_HMAC_SUPPORTED
|
||||
/**
|
||||
* @brief HMAC-based scheme specific configuration data
|
||||
*/
|
||||
typedef struct {
|
||||
hmac_key_id_t hmac_key_id; /*!< HMAC Key ID used for generating the NVS encryption keys */
|
||||
} nvs_sec_config_hmac_t;
|
||||
|
||||
/**
|
||||
* @brief Helper for populating the HMAC-based scheme specific configuration data
|
||||
*/
|
||||
#define NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT() { \
|
||||
.hmac_key_id = (hmac_key_id_t)(CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID), \
|
||||
}
|
||||
#endif /* SOC_HMAC_SUPPORTED */
|
||||
|
||||
/**
|
||||
* @brief Register the Flash-Encryption based scheme for NVS Encryption
|
||||
*
|
||||
* @param[in] sec_scheme_cfg Security scheme specific configuration data
|
||||
* @param[out] sec_scheme_handle_out Security scheme specific configuration handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, if `sec_scheme_handle_out` was populated successfully with the scheme configuration;
|
||||
* - ESP_ERR_INVALID_ARG, if `scheme_cfg_hmac` is NULL;
|
||||
* - ESP_ERR_NO_MEM, No memory for the scheme-specific handle `sec_scheme_handle_out`
|
||||
* - ESP_ERR_NOT_FOUND, if no `nvs_keys` partition is found
|
||||
*/
|
||||
esp_err_t nvs_sec_provider_register_flash_enc(const nvs_sec_config_flash_enc_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out);
|
||||
|
||||
#if SOC_HMAC_SUPPORTED
|
||||
/**
|
||||
* @brief Register the HMAC-based scheme for NVS Encryption
|
||||
*
|
||||
* @param[in] sec_scheme_cfg Security scheme specific configuration data
|
||||
* @param[out] sec_scheme_handle_out Security scheme specific configuration handle
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK, if `sec_scheme_handle_out` was populated successfully with the scheme configuration;
|
||||
* - ESP_ERR_INVALID_ARG, if `scheme_cfg_hmac` is NULL;
|
||||
* - ESP_ERR_NO_MEM, No memory for the scheme-specific handle `sec_scheme_handle_out`
|
||||
*/
|
||||
esp_err_t nvs_sec_provider_register_hmac(const nvs_sec_config_hmac_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out);
|
||||
#endif /* SOC_HMAC_SUPPORTED */
|
||||
|
||||
/**
|
||||
* @brief Deregister the NVS encryption scheme registered with the given handle
|
||||
*
|
||||
* @param[in] sec_scheme_handle Security scheme specific configuration handle
|
||||
|
||||
* @return
|
||||
* - ESP_OK, if the scheme registered with `sec_scheme_handle` was deregistered successfully
|
||||
* - ESP_ERR_INVALID_ARG, if `sec_scheme_handle` is NULL;
|
||||
*/
|
||||
esp_err_t nvs_sec_provider_deregister(nvs_sec_scheme_t *sec_scheme_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
279
components/nvs_sec_provider/nvs_sec_provider.c
Normal file
279
components/nvs_sec_provider/nvs_sec_provider.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_fault.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs_sec_provider.h"
|
||||
|
||||
#if SOC_HMAC_SUPPORTED
|
||||
#include "bootloader_random.h"
|
||||
#include "esp_random.h"
|
||||
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_chip.h"
|
||||
#endif // SOC_HMAC_SUPPORTED
|
||||
|
||||
static __attribute__((unused)) const char *TAG = "nvs_sec_provider";
|
||||
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
|
||||
static esp_err_t generate_keys_flash_enc(const void* sec_scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (sec_scheme_cfg == NULL || cfg == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_sec_config_flash_enc_t *scheme_cfg_flash_enc = (nvs_sec_config_flash_enc_t *)sec_scheme_cfg;
|
||||
return nvs_flash_generate_keys(scheme_cfg_flash_enc->nvs_keys_part, cfg);
|
||||
}
|
||||
|
||||
static esp_err_t read_security_cfg_flash_enc(const void* sec_scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (sec_scheme_cfg == NULL || cfg == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_sec_config_flash_enc_t *scheme_cfg_flash_enc = (nvs_sec_config_flash_enc_t *)sec_scheme_cfg;
|
||||
return nvs_flash_read_security_cfg(scheme_cfg_flash_enc->nvs_keys_part, cfg);
|
||||
}
|
||||
|
||||
esp_err_t nvs_sec_provider_register_flash_enc(const nvs_sec_config_flash_enc_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out)
|
||||
{
|
||||
if (sec_scheme_cfg == NULL || sec_scheme_handle_out == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_sec_scheme_t *sec_scheme = calloc(1, sizeof(nvs_sec_scheme_t));
|
||||
if (sec_scheme == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
sec_scheme->scheme_id = NVS_SEC_SCHEME_FLASH_ENC;
|
||||
sec_scheme->nvs_flash_key_gen = &generate_keys_flash_enc;
|
||||
sec_scheme->nvs_flash_read_cfg = &read_security_cfg_flash_enc;
|
||||
|
||||
sec_scheme->scheme_data = calloc(1, sizeof(nvs_sec_config_flash_enc_t));
|
||||
if (sec_scheme->scheme_data == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(sec_scheme->scheme_data, (void *)sec_scheme_cfg, sizeof(nvs_sec_config_flash_enc_t));
|
||||
|
||||
esp_err_t err = nvs_flash_register_security_scheme(sec_scheme);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*sec_scheme_handle_out = sec_scheme;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) nvs_sec_provider_register_flash_enc_ctr(void)
|
||||
{
|
||||
ESP_EARLY_LOGI(TAG, "NVS Encryption - Registering Flash encryption-based scheme...");
|
||||
|
||||
nvs_sec_config_flash_enc_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_FLASH_ENC_DEFAULT();
|
||||
nvs_sec_scheme_t *sec_scheme_handle_out = NULL;
|
||||
|
||||
nvs_sec_provider_register_flash_enc(&sec_scheme_cfg, &sec_scheme_handle_out);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if SOC_HMAC_SUPPORTED
|
||||
|
||||
#if CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID > 5
|
||||
#error "NVS Encryption (HMAC): Configured eFuse block (CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID) out of range!"
|
||||
#endif
|
||||
|
||||
static esp_err_t compute_nvs_keys_with_hmac(hmac_key_id_t hmac_key_id, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
uint32_t ekey_seed[8] = {[0 ... 7] = 0xAEBE5A5A};
|
||||
uint32_t tkey_seed[8] = {[0 ... 7] = 0xCEDEA5A5};
|
||||
|
||||
esp_err_t err = esp_hmac_calculate(hmac_key_id, ekey_seed, sizeof(ekey_seed), (uint8_t *)cfg->eky);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to calculate seed HMAC: [0x%02X] (%s)", err, esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
ESP_FAULT_ASSERT(err == ESP_OK);
|
||||
|
||||
err = esp_hmac_calculate(hmac_key_id, tkey_seed, sizeof(tkey_seed), (uint8_t *)cfg->tky);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to calculate seed HMAC: [0x%02X] (%s)", err, esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
ESP_FAULT_ASSERT(err == ESP_OK);
|
||||
|
||||
/* NOTE: If the XTS E-key and T-key are the same, we have a hash collision */
|
||||
ESP_FAULT_ASSERT(memcmp(cfg->eky, cfg->tky, NVS_KEY_SIZE) != 0);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_efuse_block_t convert_key_type(hmac_key_id_t key_id) {
|
||||
return (esp_efuse_block_t)(EFUSE_BLK_KEY0 + (esp_efuse_block_t) key_id);
|
||||
}
|
||||
|
||||
static bool is_hmac_key_burnt_in_efuse(hmac_key_id_t hmac_key_id)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
esp_efuse_block_t hmac_key_blk = convert_key_type(hmac_key_id);
|
||||
|
||||
esp_efuse_purpose_t hmac_efuse_blk_purpose = esp_efuse_get_key_purpose(hmac_key_blk);
|
||||
if (hmac_efuse_blk_purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_UP) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t generate_keys_hmac(const void* scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (cfg == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_sec_config_hmac_t *scheme_cfg_hmac = (nvs_sec_config_hmac_t *)scheme_cfg;
|
||||
|
||||
hmac_key_id_t hmac_key = scheme_cfg_hmac->hmac_key_id;
|
||||
if (hmac_key >= HMAC_KEY_MAX) {
|
||||
ESP_LOGE(TAG, "Invalid HMAC key ID received!");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
if (!is_hmac_key_burnt_in_efuse(hmac_key)) {
|
||||
uint8_t hmac_key_buf[32] = {0};
|
||||
|
||||
bootloader_random_enable();
|
||||
esp_fill_random(hmac_key_buf, sizeof(hmac_key_buf));
|
||||
bootloader_random_disable();
|
||||
|
||||
esp_efuse_block_t hmac_key_blk = convert_key_type(hmac_key);
|
||||
|
||||
err = esp_efuse_write_key(hmac_key_blk, ESP_EFUSE_KEY_PURPOSE_HMAC_UP, hmac_key_buf, sizeof(hmac_key_buf));
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_EFUSE_REPEATED_PROG) {
|
||||
ESP_LOGE(TAG, "Configured eFuse block for HMAC key already-in-use!");
|
||||
return ESP_ERR_NVS_SEC_HMAC_KEY_BLK_ALREADY_USED;
|
||||
}
|
||||
ESP_LOGE(TAG, "Failed to write the HMAC key to eFuse: [0x%02X] (%s)", err, esp_err_to_name(err));
|
||||
return ESP_ERR_NVS_SEC_HMAC_KEY_GENERATION_FAILED;
|
||||
}
|
||||
memset(hmac_key_buf, 0x00, sizeof(hmac_key_buf));
|
||||
} else {
|
||||
ESP_LOGW(TAG, "HMAC Key already present in configured eFuse block, using the same for NVS encryption!");
|
||||
}
|
||||
|
||||
err = compute_nvs_keys_with_hmac(hmac_key, cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to derive the encryption keys using HMAC!");
|
||||
return ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t read_security_cfg_hmac(const void* scheme_cfg, nvs_sec_cfg_t* cfg)
|
||||
{
|
||||
if (cfg == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_sec_config_hmac_t *scheme_cfg_hmac = (nvs_sec_config_hmac_t *)scheme_cfg;
|
||||
|
||||
hmac_key_id_t hmac_key = scheme_cfg_hmac->hmac_key_id;
|
||||
if (hmac_key >= HMAC_KEY_MAX) {
|
||||
ESP_LOGE(TAG, "Invalid HMAC key ID received!");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!is_hmac_key_burnt_in_efuse(hmac_key)) {
|
||||
ESP_LOGE(TAG, "Could not find HMAC key in configured eFuse block!");
|
||||
return ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t err = compute_nvs_keys_with_hmac(hmac_key, cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to derive the encryption keys using HMAC!");
|
||||
return ESP_ERR_NVS_SEC_HMAC_XTS_KEYS_DERIV_FAILED;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t nvs_sec_provider_register_hmac(const nvs_sec_config_hmac_t *sec_scheme_cfg, nvs_sec_scheme_t **sec_scheme_handle_out)
|
||||
{
|
||||
if (sec_scheme_cfg == NULL || sec_scheme_handle_out == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nvs_sec_scheme_t *sec_scheme = calloc(1, sizeof(nvs_sec_scheme_t));
|
||||
if (sec_scheme == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
sec_scheme->scheme_id = NVS_SEC_SCHEME_HMAC;
|
||||
sec_scheme->nvs_flash_key_gen = &generate_keys_hmac;
|
||||
sec_scheme->nvs_flash_read_cfg = &read_security_cfg_hmac;
|
||||
|
||||
sec_scheme->scheme_data = calloc(1, sizeof(nvs_sec_config_hmac_t));
|
||||
if (sec_scheme->scheme_data == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
memcpy(sec_scheme->scheme_data, (void *)sec_scheme_cfg, sizeof(nvs_sec_config_hmac_t));
|
||||
|
||||
esp_err_t err = nvs_flash_register_security_scheme(sec_scheme);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*sec_scheme_handle_out = sec_scheme;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
static void __attribute__((constructor)) nvs_sec_provider_register_hmac_ctr(void)
|
||||
{
|
||||
ESP_EARLY_LOGI(TAG, "NVS Encryption - Registering HMAC-based scheme...");
|
||||
|
||||
nvs_sec_config_hmac_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT();
|
||||
nvs_sec_scheme_t *sec_scheme_handle_out = NULL;
|
||||
|
||||
nvs_sec_provider_register_hmac(&sec_scheme_cfg, &sec_scheme_handle_out);
|
||||
}
|
||||
#endif // CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC
|
||||
|
||||
#endif // SOC_HMAC_SUPPORTED
|
||||
|
||||
esp_err_t nvs_sec_provider_deregister(nvs_sec_scheme_t *sec_scheme_handle)
|
||||
{
|
||||
if (sec_scheme_handle == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (sec_scheme_handle->scheme_data != NULL) {
|
||||
free(sec_scheme_handle->scheme_data);
|
||||
}
|
||||
|
||||
free(sec_scheme_handle);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void nvs_sec_provider_include_impl(void)
|
||||
{
|
||||
// Linker hook, exists for no other purpose
|
||||
}
|
@ -54,7 +54,8 @@ menu "Partition Table"
|
||||
for more information.
|
||||
config PARTITION_TABLE_SINGLE_APP_ENCRYPTED_NVS
|
||||
bool "Single factory app, no OTA, encrypted NVS"
|
||||
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_ENCRYPTION
|
||||
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
|
||||
help
|
||||
This is a variation of the default "Single factory app, no OTA" partition table
|
||||
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
||||
@ -64,7 +65,7 @@ menu "Partition Table"
|
||||
components/partition_table/partitions_singleapp_encr_nvs.csv
|
||||
config PARTITION_TABLE_SINGLE_APP_LARGE_ENC_NVS
|
||||
bool "Single factory app (large), no OTA, encrypted NVS"
|
||||
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_ENCRYPTION
|
||||
depends on !ESP32_COREDUMP_ENABLE_TO_FLASH && NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
help
|
||||
This is a variation of the "Single factory app (large), no OTA" partition table
|
||||
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
||||
@ -74,7 +75,7 @@ menu "Partition Table"
|
||||
components/partition_table/partitions_singleapp_large_encr_nvs.csv
|
||||
config PARTITION_TABLE_TWO_OTA_ENCRYPTED_NVS
|
||||
bool "Factory app, two OTA definitions, encrypted NVS"
|
||||
depends on !ESP_COREDUMP_ENABLE_TO_FLASH && NVS_ENCRYPTION
|
||||
depends on !ESP_COREDUMP_ENABLE_TO_FLASH && NVS_SEC_KEY_PROTECT_USING_FLASH_ENC
|
||||
help
|
||||
This is a variation of the "Factory app, two OTA definitions" partition table
|
||||
that supports encrypted NVS when using flash encryption. See the Flash Encryption section
|
||||
|
@ -124,6 +124,7 @@ ENV_MARKERS = {
|
||||
'ecdsa_efuse': 'Runner with test ECDSA private keys programmed in efuse',
|
||||
'ccs811': 'Runner with CCS811 connected',
|
||||
'ethernet_w5500': 'SPI Ethernet module with two W5500',
|
||||
'nvs_encr_hmac': 'Runner with test HMAC key programmed in efuse',
|
||||
# multi-dut markers
|
||||
'ieee802154': 'ieee802154 related tests should run on ieee802154 runners.',
|
||||
'openthread_br': 'tests should be used for openthread border router.',
|
||||
|
@ -235,6 +235,7 @@ INPUT = \
|
||||
$(PROJECT_PATH)/components/mqtt/esp-mqtt/include/mqtt_client.h \
|
||||
$(PROJECT_PATH)/components/nvs_flash/include/nvs_flash.h \
|
||||
$(PROJECT_PATH)/components/nvs_flash/include/nvs.h \
|
||||
$(PROJECT_PATH)/components/nvs_sec_provider/include/nvs_sec_provider.h \
|
||||
$(PROJECT_PATH)/components/openthread/include/esp_openthread_border_router.h \
|
||||
$(PROJECT_PATH)/components/openthread/include/esp_openthread_lock.h \
|
||||
$(PROJECT_PATH)/components/openthread/include/esp_openthread_netif_glue.h \
|
||||
|
@ -23,6 +23,7 @@ This section contains reference of the high-level storage APIs. They are based o
|
||||
fatfs
|
||||
mass_mfg.rst
|
||||
nvs_flash
|
||||
nvs_encryption
|
||||
nvs_partition_gen.rst
|
||||
nvs_partition_parse.rst
|
||||
sdmmc
|
||||
|
199
docs/en/api-reference/storage/nvs_encryption.rst
Normal file
199
docs/en/api-reference/storage/nvs_encryption.rst
Normal file
@ -0,0 +1,199 @@
|
||||
NVS Encryption
|
||||
==============
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This guide provides an overview of the NVS Encryption feature. NVS encryption helps to achieve secure storage on the device flash memory.
|
||||
|
||||
Data stored in NVS partitions can be encrypted using XTS-AES in the manner similar to the one mentioned in disk encryption standard IEEE P1619. For the purpose of encryption, each entry is treated as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
NVS Encryption can be facilitated by enabling :ref:`CONFIG_NVS_ENCRYPTION` and :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` -> ``CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC`` or ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC`` depending on the scheme to be used.
|
||||
|
||||
|
||||
NVS Encryption: Flash Encryption-based Scheme
|
||||
---------------------------------------------
|
||||
|
||||
In this scheme, the keys required for NVS encryption are stored in yet another partition, which is protected using :doc:`Flash Encryption <../../security/flash-encryption>`. Therefore, enabling :doc:`Flash Encryption <../../security/flash-encryption>` becomes a prerequisite for NVS encryption here.
|
||||
|
||||
The NVS Encryption is enabled by default when :doc:`Flash Encryption <../../security/flash-encryption>` is enabled. This is done because Wi-Fi driver stores credentials (like SSID and passphrase) in the default NVS partition. It is important to encrypt them as default choice if platform level encryption is already enabled.
|
||||
|
||||
For using NVS encryption using this scheme, the partition table must contain the :ref:`nvs_encr_key_partition`. Two partition tables containing the :ref:`nvs_encr_key_partition` are provided for NVS encryption under the partition table option (``menuconfig`` > ``Partition Table``). They can be selected with the project configuration menu (``idf.py menuconfig``). Please refer to the example :example:`security/flash_encryption` for how to configure and use the NVS encryption feature.
|
||||
|
||||
.. _nvs_encr_key_partition:
|
||||
|
||||
NVS Key Partition
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
An application requiring NVS encryption support (using the Flash Encryption-based scheme) needs to be compiled with a key-partition of the type `data` and subtype `key`. This partition should be marked as `encrypted` and its size should be the minimum partition size (4KB). Refer to :doc:`Partition Tables <../../api-guides/partition-tables>` for more details. Two additional partition tables which contain the :ref:`nvs_encr_key_partition` are provided under the partition table option (``menuconfig`` > ``Partition Table``). They can be directly used for NVS encryption. The structure of these partitions is depicted below.
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
+-----------+--------------+-------------+----+
|
||||
| XTS encryption key (32) |
|
||||
+---------------------------------------------+
|
||||
| XTS tweak key (32) |
|
||||
+---------------------------------------------+
|
||||
| CRC32 (4) |
|
||||
+---------------------------------------------+
|
||||
|
||||
The XTS encryption keys in the :ref:`nvs_encr_key_partition` can be generated in one of the following two ways.
|
||||
|
||||
**Generate the keys on {IDF_TARGET_NAME} chip itself**
|
||||
|
||||
* When NVS encryption is enabled the :cpp:func:`nvs_flash_init` API function can be used to initialize the encrypted default NVS partition. The API function internally generates the XTS encryption keys on the ESP chip. The API function finds the first :ref:`nvs_encr_key_partition`.
|
||||
|
||||
* Then the API function automatically generates and stores the NVS keys in that partition by making use of the :cpp:func:`nvs_flash_generate_keys` API function provided by :component_file:`nvs_flash/include/nvs_flash.h`. New keys are generated and stored only when the respective key partition is empty. The same key partition can then be used to read the security configurations for initializing a custom encrypted NVS partition with help of :cpp:func:`nvs_flash_secure_init_partition`.
|
||||
|
||||
* The API functions :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` do not generate the keys internally. When these API functions are used for initializing encrypted NVS partitions, the keys can be generated after startup using the :cpp:func:`nvs_flash_generate_keys` API function provided by ``nvs_flash.h``. The API function will then write those keys onto the key-partition in encrypted form.
|
||||
|
||||
.. note:: Please note that ``nvs_keys`` partition must be completely erased before you start the application in this approach. Otherwise the application may generate :c:macro:`ESP_ERR_NVS_CORRUPT_KEY_PART` error code assuming that ``nvs_keys`` partition is not empty and contains malformatted data. You can use the following command for this:
|
||||
::
|
||||
|
||||
parttool.py --port PORT --partition-table-file=PARTITION_TABLE_FILE --partition-table-offset PARTITION_TABLE_OFFSET erase_partition --partition-type=data --partition-subtype=nvs_keys
|
||||
|
||||
**Use a pre-generated NVS key partition**
|
||||
|
||||
This option will be required by the user when keys in the :ref:`nvs_encr_key_partition` are not generated by the application. The :ref:`nvs_encr_key_partition` containing the XTS encryption keys can be generated with the help of :doc:`NVS Partition Generator Utility</api-reference/storage/nvs_partition_gen>`. Then the user can store the pre generated key partition on the flash with help of the following two commands:
|
||||
|
||||
1. Build and flash the partition table
|
||||
::
|
||||
|
||||
idf.py partition-table partition-table-flash
|
||||
|
||||
2. Store the keys in the :ref:`nvs_encr_key_partition` (on the flash) with the help of :component_file:`parttool.py<partition_table/parttool.py>` (see Partition Tool section in :doc:`partition-tables </api-guides/partition-tables>` for more details)
|
||||
::
|
||||
|
||||
parttool.py --port PORT --partition-table-offset PARTITION_TABLE_OFFSET write_partition --partition-name="name of nvs_key partition" --input NVS_KEY_PARTITION_FILE
|
||||
|
||||
.. note:: If the device is encrypted in flash encryption development mode and you want to renew the NVS key partition, you need to tell :component_file:`parttool.py <partition_table/parttool.py>` to encrypt the NVS key partition and you also need to give it a pointer to the unencrypted partition table in your build directory (build/partition_table) since the partition table on the device is encrypted, too. You can use the following command:
|
||||
::
|
||||
|
||||
parttool.py --esptool-write-args encrypt --port PORT --partition-table-file=PARTITION_TABLE_FILE --partition-table-offset PARTITION_TABLE_OFFSET write_partition --partition-name="name of nvs_key partition" --input NVS_KEY_PARTITION_FILE
|
||||
|
||||
Since the key partition is marked as `encrypted` and :doc:`Flash Encryption <../../security/flash-encryption>` is enabled, the bootloader will encrypt this partition using flash encryption key on the first boot.
|
||||
|
||||
It is possible for an application to use different keys for different NVS partitions and thereby have multiple key-partitions. However, it is a responsibility of the application to provide correct key-partition/keys for the purpose of encryption/decryption.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
NVS Encryption: HMAC peripheral-based Scheme
|
||||
--------------------------------------------
|
||||
|
||||
In this scheme, the XTS keys required for NVS encryption are derived from an HMAC key programmed in eFuse with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`. Since the encryption keys are derived at runtime, they are not stored anywhere in the flash. Thus, this feature does not require a separate :ref:`nvs_encr_key_partition`.
|
||||
|
||||
.. note::
|
||||
|
||||
This scheme enables us to achieve secure storage on {IDF_TARGET_NAME} **without enabling flash encryption**.
|
||||
|
||||
.. important::
|
||||
|
||||
Please take note that this scheme will use one eFuse block for storing the HMAC key required for deriving the encryption keys.
|
||||
|
||||
- When NVS encryption is enabled, the :cpp:func:`nvs_flash_init` API function can be used to initialize the encrypted default NVS partition. The API function first checks whether an HMAC key is present at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID`.
|
||||
|
||||
.. note::
|
||||
|
||||
The valid range for the config :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` is from ``0`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY0`) to ``5`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY5`). By default, the config is set to ``6`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY_MAX`), which will have to configured before building the user application.
|
||||
|
||||
- If no key is found, a key is generated internally and stored at the eFuse block specified at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID`.
|
||||
- If a key is found with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`, the same is used for the derivation of the XTS encryption keys.
|
||||
- If the specified eFuse block is found to be occupied with a key with a purpose other than :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`, an error is thrown.
|
||||
|
||||
- The API :cpp:func:`nvs_flash_init` then automatically generates the NVS keys on demand by using the :cpp:func:`nvs_flash_generate_keys_v2` API function provided by the :component_file:`nvs_flash/include/nvs_flash.h`. The same keys can also be used to read the security configurations (see :cpp:func:`nvs_flash_read_security_cfg_v2`) for initializing a custom encrypted NVS partition with help of :cpp:func:`nvs_flash_secure_init_partition`.
|
||||
|
||||
- The API functions :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` do not generate the keys internally. When these API functions are used for initializing encrypted NVS partitions, the keys can be generated after startup using the :cpp:func:`nvs_flash_generate_keys_v2` API function or take and populate the NVS security configuration structure :cpp:type:`nvs_sec_cfg_t` with :cpp:func:`nvs_flash_read_security_cfg_v2` and feed them into the above APIs.
|
||||
|
||||
.. note:: Users can program their own HMAC key in eFuse block beforehand by using the following command -
|
||||
::
|
||||
|
||||
espefuse.py -p PORT burn_key <BLOCK_KEYN> <hmac_key_file.bin> HMAC_UP
|
||||
|
||||
Encrypted Read/Write
|
||||
--------------------
|
||||
|
||||
The same NVS API functions ``nvs_get_*`` or ``nvs_set_*`` can be used for reading of, and writing to an encrypted nvs partition as well.
|
||||
|
||||
**Encrypt the default NVS partition**
|
||||
|
||||
- To enable encryption for the default NVS partition no additional steps are necessary. When :ref:`CONFIG_NVS_ENCRYPTION` is enabled, the :cpp:func:`nvs_flash_init` API function internally performs some additional steps to enable encryption for the default NVS partition depending on the scheme being used (set by :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME`).
|
||||
|
||||
- For the flash encryption-based scheme, the first :ref:`nvs_encr_key_partition` found is used to generate the encryption keys while for the HMAC one, keys are generated using the HMAC key burnt in eFuse at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` (refer to the API documentation for more details).
|
||||
|
||||
Alternatively, :cpp:func:`nvs_flash_secure_init` API function can also be used to enable encryption for the default NVS partition.
|
||||
|
||||
**Encrypt a custom NVS partition**
|
||||
|
||||
- To enable encryption for a custom NVS partition, :cpp:func:`nvs_flash_secure_init_partition` API function is used instead of :cpp:func:`nvs_flash_init_partition`.
|
||||
|
||||
- When :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` API functions are used, the applications are expected to follow the steps below in order to perform NVS read/write operations with encryption enabled.
|
||||
|
||||
1. Populate the NVS security configuration structure :cpp:type:`nvs_sec_cfg_t`
|
||||
|
||||
* For the Flash Encryption-based scheme -
|
||||
|
||||
- Find key partition and NVS data partition using ``esp_partition_find*`` API functions.
|
||||
- Populate the :cpp:type:`nvs_sec_cfg_t` struct using the :cpp:func:`nvs_flash_read_security_cfg` or :cpp:func:`nvs_flash_generate_keys` API functions.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
* For the HMAC-based scheme -
|
||||
|
||||
- Set the scheme (see :cpp:enum:`nvs_sec_scheme_id_t`) and the scheme-specific data (to :cpp:enum:`hmac_key_id_t`) with the :cpp:type:`nvs_sec_scheme_t` struct and register the HMAC-based scheme with the API :cpp:func:`nvs_sec_provider_register_hmac`.
|
||||
- Populate the :cpp:type:`nvs_sec_cfg_t` struct using the :cpp:func:`nvs_flash_read_security_cfg_v2` or :cpp:func:`nvs_flash_generate_keys_v2` API functions.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
nvs_sec_cfg_t cfg = {};
|
||||
nvs_sec_scheme_t *sec_scheme_handle = NULL;
|
||||
|
||||
nvs_sec_config_hmac_t sec_scheme_cfg = {};
|
||||
hmac_key_id_t hmac_key = HMAC_KEY0;
|
||||
sec_scheme_cfg.hmac_key_id = hmac_key;
|
||||
|
||||
ret = nvs_sec_provider_register_hmac(&sec_scheme_cfg, &sec_scheme_handle);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvs_flash_read_security_cfg_v2(sec_scheme_handle, &cfg);
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_ERR_NVS_SEC_HMAC_KEY_NOT_FOUND) {
|
||||
ret = nvs_flash_generate_keys_v2(&sec_scheme_handle, &cfg);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to generate NVS encr-keys!");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ESP_LOGE(TAG, "Failed to read NVS security cfg!");
|
||||
return ret;
|
||||
}
|
||||
|
||||
2. Initialise NVS flash partition using the :cpp:func:`nvs_flash_secure_init` or :cpp:func:`nvs_flash_secure_init_partition` API functions.
|
||||
3. Open a namespace using the :cpp:func:`nvs_open` or :cpp:func:`nvs_open_from_partition` API functions.
|
||||
4. Perform NVS read/write operations using ``nvs_get_*`` or ``nvs_set_*``.
|
||||
5. Deinitialise an NVS partition using :cpp:func:`nvs_flash_deinit`.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
.. note:: While using the HMAC-based scheme, the above workflow can be used without enabling any of the config options for NVS Encryption - :ref:`CONFIG_NVS_ENCRYPTION`, :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` -> ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC`` and :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` to encrypt the default as well as custom NVS partitions with :cpp:func:`nvs_flash_secure_init` API.
|
||||
|
||||
|
||||
NVS Security Provider
|
||||
---------------------
|
||||
|
||||
The component :component:`nvs_sec_provider` stores all the implementation-specific code for the NVS encryption schemes and would also accomodate any future schemes. This component acts as an interface to the :component:`nvs_flash` component for the handling of encryption keys. :component:`nvs_sec_provider` has a configuration menu of its own, based on which the selected security scheme and the corresponding settings are registered for the :component:`nvs_flash` component.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
This component offers factory functions with which a particular security scheme can be registered without having to worry about the APIs to generate and read the encryption keys (e.g. :cpp:func:`nvs_sec_provider_register_hmac`). Refer to the :example:`security/nvs_encryption_hmac` example for API usage.
|
||||
|
||||
|
||||
API Reference
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/nvs_sec_provider.inc
|
@ -66,7 +66,13 @@ In general, all iterators obtained via :cpp:func:`nvs_entry_find` have to be rel
|
||||
Security, Tampering, and Robustness
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
NVS is not directly compatible with the {IDF_TARGET_NAME} flash encryption system. However, data can still be stored in encrypted form if NVS encryption is used together with {IDF_TARGET_NAME} flash encryption. Please refer to :ref:`nvs_encryption` for more details.
|
||||
.. only:: not SOC_HMAC_SUPPORTED
|
||||
|
||||
NVS is not directly compatible with the {IDF_TARGET_NAME} flash encryption system. However, data can still be stored in encrypted form if NVS encryption is used together with {IDF_TARGET_NAME} flash encryption. Please refer to :doc:`NVS Encryption <nvs_encryption>` for more details.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
NVS is not directly compatible with the {IDF_TARGET_NAME} flash encryption system. However, data can still be stored in encrypted form if NVS encryption is used together with {IDF_TARGET_NAME} flash encryption or with the help of the HMAC peripheral. Please refer to :doc:`NVS Encryption <nvs_encryption>` for more details.
|
||||
|
||||
If NVS encryption is not used, it is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. With NVS encryption enabled, it is not possible to alter or add a key-value pair and get recognized as a valid pair without knowing corresponding NVS encryption keys. However, there is no tamper-resistance against the erase operation.
|
||||
|
||||
@ -78,86 +84,7 @@ The library does try to recover from conditions when flash memory is in an incon
|
||||
NVS Encryption
|
||||
--------------
|
||||
|
||||
Data stored in NVS partitions can be encrypted using XTS-AES in the manner similar to the one mentioned in disk encryption standard IEEE P1619. For the purpose of encryption, each entry is treated as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`. The NVS Encryption can be enabled by enabling :ref:`CONFIG_NVS_ENCRYPTION`. The keys required for NVS encryption are stored in yet another partition, which is protected using :doc:`Flash Encryption <../../security/flash-encryption>`. Therefore, enabling :doc:`Flash Encryption <../../security/flash-encryption>` is a prerequisite for NVS encryption.
|
||||
|
||||
The NVS Encryption is enabled by default when :doc:`Flash Encryption <../../security/flash-encryption>` is enabled. This is done because Wi-Fi driver stores credentials (like SSID and passphrase) in the default NVS partition. It is important to encrypt them as default choice if platform level encryption is already enabled.
|
||||
|
||||
For using NVS encryption, the partition table must contain the :ref:`nvs_key_partition`. Two partition tables containing the :ref:`nvs_key_partition` are provided for NVS encryption under the partition table option (``menuconfig`` > ``Partition Table``). They can be selected with the project configuration menu (``idf.py menuconfig``). Please refer to the example :example:`security/flash_encryption` for how to configure and use NVS encryption feature.
|
||||
|
||||
.. _nvs_key_partition:
|
||||
|
||||
NVS Key Partition
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
An application requiring NVS encryption support needs to be compiled with a key-partition of the type `data` and subtype `key`. This partition should be marked as `encrypted` and its size should be the minimum partition size (4KB). Refer to :doc:`Partition Tables <../../api-guides/partition-tables>` for more details. Two additional partition tables which contain the :ref:`nvs_key_partition` are provided under the partition table option (``menuconfig`` > ``Partition Table``). They can be directly used for :ref:`nvs_encryption`. The structure of these partitions is depicted below.
|
||||
|
||||
.. highlight:: none
|
||||
|
||||
::
|
||||
|
||||
+-----------+--------------+-------------+----+
|
||||
| XTS encryption key (32) |
|
||||
+---------------------------------------------+
|
||||
| XTS tweak key (32) |
|
||||
+---------------------------------------------+
|
||||
| CRC32 (4) |
|
||||
+---------------------------------------------+
|
||||
|
||||
The XTS encryption keys in the :ref:`nvs_key_partition` can be generated in one of the following two ways.
|
||||
|
||||
1. Generate the keys on the ESP chip:
|
||||
|
||||
When NVS encryption is enabled the :cpp:func:`nvs_flash_init` API function can be used to initialize the encrypted default NVS partition. The API function internally generates the XTS encryption keys on the ESP chip. The API function finds the first :ref:`nvs_key_partition`. Then the API function automatically generates and stores the NVS keys in that partition by making use of the :cpp:func:`nvs_flash_generate_keys` API function provided by :component_file:`nvs_flash/include/nvs_flash.h`. New keys are generated and stored only when the respective key partition is empty. The same key partition can then be used to read the security configurations for initializing a custom encrypted NVS partition with help of :cpp:func:`nvs_flash_secure_init_partition`.
|
||||
|
||||
The API functions :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` do not generate the keys internally. When these API functions are used for initializing encrypted NVS partitions, the keys can be generated after startup using the :cpp:func:`nvs_flash_generate_keys` API function provided by ``nvs_flash.h``. The API function will then write those keys onto the key-partition in encrypted form.
|
||||
|
||||
.. note:: Please note that `nvs_keys` partition must be completely erased before you start the application in this approach. Otherwise the application may generate :c:macro:`ESP_ERR_NVS_CORRUPT_KEY_PART` error code assuming that `nvs_keys` partition is not empty and contains malformatted data. You can use the following command for this:
|
||||
::
|
||||
|
||||
parttool.py --port PORT --partition-table-file=PARTITION_TABLE_FILE --partition-table-offset PARTITION_TABLE_OFFSET erase_partition --partition-type=data --partition-subtype=nvs_keys
|
||||
|
||||
2. Use pre-generated key partition:
|
||||
|
||||
This option will be required by the user when keys in the :ref:`nvs_key_partition` are not generated by the application. The :ref:`nvs_key_partition` containing the XTS encryption keys can be generated with the help of :doc:`NVS Partition Generator Utility</api-reference/storage/nvs_partition_gen>`. Then the user can store the pre generated key partition on the flash with help of the following two commands:
|
||||
|
||||
i) Build and flash the partition table
|
||||
::
|
||||
|
||||
idf.py partition-table partition-table-flash
|
||||
|
||||
ii) Store the keys in the :ref:`nvs_key_partition` (on the flash) with the help of :component_file:`parttool.py<partition_table/parttool.py>` (see Partition Tool section in :doc:`partition-tables </api-guides/partition-tables>` for more details)
|
||||
::
|
||||
|
||||
parttool.py --port PORT --partition-table-offset PARTITION_TABLE_OFFSET write_partition --partition-name="name of nvs_key partition" --input NVS_KEY_PARTITION_FILE
|
||||
|
||||
.. note:: If the device is encrypted in flash encryption development mode and you want to renew the NVS key partition, you need to tell :component_file:`parttool.py <partition_table/parttool.py>` to encrypt the NVS key partition and you also need to give it a pointer to the unencrypted partition table in your build directory (build/partition_table) since the partition table on the device is encrypted, too. You can use the following command:
|
||||
::
|
||||
|
||||
parttool.py --esptool-write-args encrypt --port PORT --partition-table-file=PARTITION_TABLE_FILE --partition-table-offset PARTITION_TABLE_OFFSET write_partition --partition-name="name of nvs_key partition" --input NVS_KEY_PARTITION_FILE
|
||||
|
||||
Since the key partition is marked as `encrypted` and :doc:`Flash Encryption <../../security/flash-encryption>` is enabled, the bootloader will encrypt this partition using flash encryption key on the first boot.
|
||||
|
||||
It is possible for an application to use different keys for different NVS partitions and thereby have multiple key-partitions. However, it is a responsibility of the application to provide correct key-partition/keys for the purpose of encryption/decryption.
|
||||
|
||||
Encrypted Read/Write
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The same NVS API functions ``nvs_get_*`` or ``nvs_set_*`` can be used for reading of, and writing to an encrypted nvs partition as well.
|
||||
|
||||
**Encrypt the default NVS partition:**
|
||||
To enable encryption for the default NVS partition no additional steps are necessary. When :ref:`CONFIG_NVS_ENCRYPTION` is enabled, the :cpp:func:`nvs_flash_init` API function internally performs some additional steps using the first :ref:`nvs_key_partition` found to enable encryption for the default NVS partition (refer to the API documentation for more details). Alternatively, :cpp:func:`nvs_flash_secure_init` API function can also be used to enable encryption for the default NVS partition.
|
||||
|
||||
**Encrypt a custom NVS partition:**
|
||||
To enable encryption for a custom NVS partition, :cpp:func:`nvs_flash_secure_init_partition` API function is used instead of :cpp:func:`nvs_flash_init_partition`.
|
||||
|
||||
When :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` API functions are used, the applications are expected to follow the steps below in order to perform NVS read/write operations with encryption enabled.
|
||||
|
||||
1. Find key partition and NVS data partition using ``esp_partition_find*`` API functions.
|
||||
2. Populate the :cpp:type:`nvs_sec_cfg_t` struct using the :cpp:func:`nvs_flash_read_security_cfg` or :cpp:func:`nvs_flash_generate_keys` API functions.
|
||||
3. Initialise NVS flash partition using the :cpp:func:`nvs_flash_secure_init` or :cpp:func:`nvs_flash_secure_init_partition` API functions.
|
||||
4. Open a namespace using the :cpp:func:`nvs_open` or :cpp:func:`nvs_open_from_partition` API functions.
|
||||
5. Perform NVS read/write operations using ``nvs_get_*`` or ``nvs_set_*``.
|
||||
6. Deinitialise an NVS partition using :cpp:func:`nvs_flash_deinit`.
|
||||
Please refer to the :doc:`NVS Encryption <nvs_encryption>` guide for more details.
|
||||
|
||||
NVS Partition Generator Utility
|
||||
-------------------------------
|
||||
|
@ -721,7 +721,7 @@ You can also use the following SPI flash API functions:
|
||||
- :cpp:func:`esp_flash_read` to read raw (encrypted) data which will not be decrypted
|
||||
- :cpp:func:`esp_flash_read_encrypted` to read and decrypt data
|
||||
|
||||
Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted from the perspective of flash encryption. It is up to the library to provide encryption feature if required. Refer to :ref:`NVS Encryption <nvs_encryption>` for more details.
|
||||
Data stored using the Non-Volatile Storage (NVS) API is always stored and read decrypted from the perspective of flash encryption. It is up to the library to provide encryption feature if required. Refer to :doc:`NVS Encryption <../api-reference/storage/nvs_encryption>` for more details.
|
||||
|
||||
|
||||
Writing to Encrypted Flash
|
||||
@ -809,7 +809,7 @@ Key Points About Flash Encryption
|
||||
|
||||
- Flash access is transparent via the flash cache mapping feature of {IDF_TARGET_NAME} - any flash regions which are mapped to the address space will be transparently decrypted when read.
|
||||
|
||||
Some data partitions might need to remain unencrypted for ease of access or might require the use of flash-friendly update algorithms which are ineffective if the data is encrypted. NVS partitions for non-volatile storage cannot be encrypted since the NVS library is not directly compatible with flash encryption. For details, refer to :ref:`NVS Encryption <nvs_encryption>`.
|
||||
Some data partitions might need to remain unencrypted for ease of access or might require the use of flash-friendly update algorithms which are ineffective if the data is encrypted. NVS partitions for non-volatile storage cannot be encrypted since the NVS library is not directly compatible with flash encryption. For details, refer to :doc:`NVS Encryption <../api-reference/storage/nvs_encryption>`.
|
||||
|
||||
- If flash encryption might be used in future, the programmer must keep it in mind and take certain precautions when writing code that :ref:`uses encrypted flash <reading-writing-content>`.
|
||||
|
||||
@ -834,7 +834,7 @@ Flash encryption protects firmware against unauthorised readout and modification
|
||||
- Flash encryption is only as strong as the key. For this reason, we recommend keys are generated on the device during first boot (default behaviour). If generating keys off-device, ensure proper procedure is followed and don't share the same key between all production devices.
|
||||
- Not all data is stored encrypted. If storing data on flash, check if the method you are using (library, API, etc.) supports flash encryption.
|
||||
- Flash encryption does not prevent an attacker from understanding the high-level layout of the flash. This is because the same AES key is used for every pair of adjacent 16 byte AES blocks. When these adjacent 16 byte blocks contain identical content (such as empty or padding areas), these blocks will encrypt to produce matching pairs of encrypted blocks. This may allow an attacker to make high-level comparisons between encrypted devices (i.e. to tell if two devices are probably running the same firmware version).
|
||||
:esp32: - For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain two identical 16 byte sequences. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). :ref:`NVS Encryption <nvs_encryption>` deals with this and is suitable for many uses.
|
||||
:esp32: - For the same reason, an attacker can always tell when a pair of adjacent 16 byte blocks (32 byte aligned) contain two identical 16 byte sequences. Keep this in mind if storing sensitive data on the flash, design your flash storage so this doesn't happen (using a counter byte or some other non-identical value every 16 bytes is sufficient). :doc:`NVS Encryption <../api-reference/storage/nvs_encryption>` deals with this and is suitable for many uses.
|
||||
- Flash encryption alone may not prevent an attacker from modifying the firmware of the device. To prevent unauthorised firmware from running on the device, use flash encryption in combination with :doc:`Secure Boot <secure-boot-v2>`.
|
||||
|
||||
.. _flash-encryption-and-secure-boot:
|
||||
|
@ -205,7 +205,12 @@ Secure storage refers to the application specific data that can be stored in a s
|
||||
|
||||
ESP-IDF provides "NVS (Non-volatile Storage)" management component which allows encrypted data partitions. This feature is tied with the platform :ref:`flash_enc-guide` feature described earlier.
|
||||
|
||||
Please refer to the :ref:`NVS Encryption <nvs_encryption>` for detailed documentation on the working and instructions to enable this feature.
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
This feature can also be used independent of the platform :ref:`flash_enc-guide` feature with the help of the {IDF_TARGET_NAME} HMAC peripheral.
|
||||
|
||||
|
||||
Please refer to the :doc:`NVS Encryption <../api-reference/storage/nvs_encryption>` for detailed documentation on the working and instructions to enable this feature.
|
||||
|
||||
.. important::
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
fatfs
|
||||
mass_mfg.rst
|
||||
nvs_flash
|
||||
nvs_encryption
|
||||
nvs_partition_gen.rst
|
||||
nvs_partition_parse.rst
|
||||
sdmmc
|
||||
|
1
docs/zh_CN/api-reference/storage/nvs_encryption.rst
Normal file
1
docs/zh_CN/api-reference/storage/nvs_encryption.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../../../en/api-reference/storage/nvs_encryption.rst
|
@ -5,3 +5,11 @@ examples/security/flash_encryption:
|
||||
- if: IDF_TARGET in ["esp32s2", "esp32s3", "esp32c6", "esp32h2", "esp32c2"]
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
||||
examples/security/nvs_encryption_hmac:
|
||||
disable:
|
||||
- if: SOC_HMAC_SUPPORTED != 1
|
||||
disable_test:
|
||||
- if: IDF_TARGET not in ["esp32c3"]
|
||||
temporary: true
|
||||
reason: lack of runners
|
||||
|
6
examples/security/nvs_encryption_hmac/CMakeLists.txt
Normal file
6
examples/security/nvs_encryption_hmac/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(nvs_encryption_hmac)
|
81
examples/security/nvs_encryption_hmac/README.md
Normal file
81
examples/security/nvs_encryption_hmac/README.md
Normal file
@ -0,0 +1,81 @@
|
||||
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
# NVS Encryption with HMAC-based encryption key protection scheme
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates NVS encryption using the HMAC peripheral, wherein the encryption keys are derived from the HMAC key burnt in eFuse. Since the derivation of the encryption keys occurs at runtime, they are not stored in the flash. Thus, this feature does not require a separate `nvs_keys` partition and _also does not require flash encryption enabled_.
|
||||
|
||||
## How to use the example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any development board with a supported Espressif SOC chip - possessing a built-in HMAC peripheral (see `Supported Targets` table above).
|
||||
|
||||
### Configure the project
|
||||
|
||||
Before the project configuration and build, be sure to set the correct chip target using `idf.py set-target <chip_name>`.
|
||||
|
||||
Open the project configuration menu (`idf.py menuconfig`).
|
||||
|
||||
#### Configure the eFuse key ID storing the HMAC key
|
||||
|
||||
- Set the eFuse key ID storing the HMAC key at `Component config → NVS Security Provider → eFuse key ID storing the HMAC key`.
|
||||
The HMAC key stored at this key block will be used to generate the encryption keys for the default NVS partition (`nvs`), initialised with `nvs_flash_init()`. Note that the example will fail to build without setting this config option to the correct value (the default value is out of range).
|
||||
|
||||
- Users can program their own HMAC key in the configured block before running the example - refer below snippet. The example checks if the configured block is empty or already programmed with an HMAC key - if empty, a new key is generated at runtime and stored in the block, or else the provided key is used. While burning the key prior to flashing the app, please make sure that the config value is set to the eFuse block holding the HMAC key.
|
||||
|
||||
```shell
|
||||
# Burning the HMAC-key in eFuse block 0 - key ID 0
|
||||
espefuse.py -p PORT burn_key BLOCK_KEY0 hmac_key_file.bin HMAC_UP
|
||||
```
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run the monitor tool to view the serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type `Ctrl-]`.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
### Example Output
|
||||
|
||||
```log
|
||||
I (300) nvs_sec_provider: NVS Encryption - Registering HMAC-based scheme...
|
||||
I (308) app_start: Starting scheduler on CPU0
|
||||
I (313) main_task: Started on CPU0
|
||||
I (313) main_task: Calling app_main()
|
||||
I (313) example: Initialising the default NVS partition
|
||||
I (333) nvs: NVS partition "nvs" is encrypted.
|
||||
I (603) example: Initialising the custom NVS partition
|
||||
I (613) example: NVS partition "custom_nvs" is encrypted.
|
||||
I (623) example: Key: u8_key | Val: 255
|
||||
I (623) example: Key: i8_key | Val: -128
|
||||
I (623) example: Key: u16_key | Val: 65535
|
||||
I (633) example: Key: u32_key | Val: 4294967295
|
||||
I (633) example: Key: i32_key | Val: -2147483648
|
||||
I (643) example: Key: str_key | Val: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Fusce quis risus justo.
|
||||
Suspendisse egestas in nisi sit amet auctor.
|
||||
Pellentesque rhoncus dictum sodales.
|
||||
In justo erat, viverra at interdum eget, interdum vel dui.
|
||||
|
||||
I (663) custom_nvs: 0x3ffc5f5c fe ff ff ff 00 00 00 00 fe ff ff ff ff ff ff ff |................|
|
||||
I (673) custom_nvs: 0x3ffc5f6c ff ff ff ff ff ff ff ff ff ff ff ff 84 2d ba b9 |.............-..|
|
||||
I (683) custom_nvs: 0x3ffc5f7c aa aa aa fa ff ff ff ff ff ff ff ff ff ff ff ff |................|
|
||||
I (693) custom_nvs: 0x3ffc5f8c ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
|
||||
I (703) custom_nvs: 0x3ffc5f9c ca 8b c3 bb 2d c2 33 d6 6b d4 a7 3d 31 0e 9c 36 |....-.3.k..=1..6|
|
||||
I (713) custom_nvs: 0x3ffc5fac 39 7f bc d4 5c 6d f8 98 de 0a 90 50 21 23 ff 04 |9...\m.....P!#..|
|
||||
I (723) custom_nvs: 0x3ffc5fbc ce f9 23 6f 2c d6 07 08 2d 0e d2 f2 a5 af 5a 2e |..#o,...-.....Z.|
|
||||
I (733) custom_nvs: 0x3ffc5fcc c9 61 bd fc 96 fc 12 87 1b 8c cb fb 51 2c ed a2 |.a..........Q,..|
|
||||
...
|
||||
...
|
||||
...
|
||||
I (1133) custom_nvs: 0x3ffc624c ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
|
||||
I (1143) main_task: Returned from app_main()
|
||||
```
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
205
examples/security/nvs_encryption_hmac/main/main.c
Normal file
205
examples/security/nvs_encryption_hmac/main/main.c
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* NVS Encryption with HMAC-based encryption key protection scheme example
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "esp_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_hmac.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs_sec_provider.h"
|
||||
|
||||
#define CUSTOM_NVS_PART_LABEL "custom_nvs"
|
||||
#define CUSTOM_NVS_PART_NAMESPACE "storage"
|
||||
#define CUSTOM_NVS_PART_DUMP_SIZE (512 + 16)
|
||||
|
||||
static const char* str_val = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n"
|
||||
"Fusce quis risus justo.\n"
|
||||
"Suspendisse egestas in nisi sit amet auctor.\n"
|
||||
"Pellentesque rhoncus dictum sodales.\n"
|
||||
"In justo erat, viverra at interdum eget, interdum vel dui.\n";
|
||||
|
||||
static const char* TAG = "example";
|
||||
|
||||
static esp_err_t example_custom_nvs_part_init(const char *label)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
#if defined(CONFIG_NVS_ENCRYPTION) && defined(CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC)
|
||||
nvs_sec_cfg_t cfg = {};
|
||||
nvs_sec_scheme_t *sec_scheme_handle = NULL;
|
||||
|
||||
nvs_sec_config_hmac_t sec_scheme_cfg = NVS_SEC_PROVIDER_CFG_HMAC_DEFAULT();
|
||||
|
||||
ret = nvs_sec_provider_register_hmac(&sec_scheme_cfg, &sec_scheme_handle);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvs_flash_read_security_cfg_v2(sec_scheme_handle, &cfg);
|
||||
if (ret != ESP_OK) {
|
||||
/* We shall not generate keys here as that must have been done in default NVS partition initialization case */
|
||||
ESP_LOGE(TAG, "Failed to read NVS security cfg: [0x%02X] (%s)", ret, esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvs_flash_secure_init_partition(label, &cfg);
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG, "NVS partition \"%s\" is encrypted.", label);
|
||||
}
|
||||
memset(&cfg, 0x00, sizeof(nvs_sec_cfg_t));
|
||||
#else
|
||||
ret = nvs_flash_init_partition(label);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t example_custom_nvs_part_write(const char *label, const char *namespace)
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
// Open
|
||||
err = nvs_open_from_partition(label, namespace, NVS_READWRITE, &my_handle);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Write
|
||||
err = nvs_set_u8(my_handle, "u8_key", UINT8_MAX);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
err = nvs_set_i8(my_handle, "i8_key", INT8_MIN);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
err = nvs_set_u16(my_handle, "u16_key", UINT16_MAX);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
err = nvs_set_u32(my_handle, "u32_key", UINT32_MAX);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
err = nvs_set_i32(my_handle, "i32_key", INT32_MIN);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
err = nvs_set_str(my_handle, "str_key", str_val);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
// Commit
|
||||
err = nvs_commit(my_handle);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
exit:
|
||||
// Close
|
||||
nvs_close(my_handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t example_custom_nvs_part_read(const char *label, const char *namespace)
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = ESP_FAIL;
|
||||
|
||||
// Open
|
||||
err = nvs_open_from_partition(label, namespace, NVS_READWRITE, &my_handle);
|
||||
if (err != ESP_OK) return err;
|
||||
|
||||
// Write
|
||||
uint8_t u8_val = 0;
|
||||
err = nvs_get_u8(my_handle, "u8_key", &u8_val);
|
||||
if (err != ESP_OK) goto exit;
|
||||
ESP_LOGI(TAG, "Key: u8_key | Val: %" PRIu8, u8_val);
|
||||
|
||||
int8_t i8_val = 0;
|
||||
err = nvs_get_i8(my_handle, "i8_key", &i8_val);
|
||||
if (err != ESP_OK) goto exit;
|
||||
ESP_LOGI(TAG, "Key: i8_key | Val: %" PRIi8, i8_val);
|
||||
|
||||
uint16_t u16_val = 0;
|
||||
err = nvs_get_u16(my_handle, "u16_key", &u16_val);
|
||||
if (err != ESP_OK) goto exit;
|
||||
ESP_LOGI(TAG, "Key: u16_key | Val: %" PRIu16, u16_val);
|
||||
|
||||
uint32_t u32_val = 0;
|
||||
err = nvs_get_u32(my_handle, "u32_key", &u32_val);
|
||||
if (err != ESP_OK) goto exit;
|
||||
ESP_LOGI(TAG, "Key: u32_key | Val: %" PRIu32, u32_val);
|
||||
|
||||
int32_t i32_val = 0;
|
||||
err = nvs_get_i32(my_handle, "i32_key", &i32_val);
|
||||
if (err != ESP_OK) goto exit;
|
||||
ESP_LOGI(TAG, "Key: i32_key | Val: %" PRIi32, i32_val);
|
||||
|
||||
size_t str_val_len = 0;
|
||||
err = nvs_get_str(my_handle, "str_key", NULL, &str_val_len);
|
||||
if (err != ESP_OK) goto exit;
|
||||
|
||||
char* str_key_val = malloc(str_val_len);
|
||||
assert(str_val);
|
||||
|
||||
err = nvs_get_str(my_handle, "str_key", str_key_val, &str_val_len);
|
||||
if (err != ESP_OK) goto cleanup;
|
||||
ESP_LOGI(TAG, "Key: str_key | Val: %s", str_key_val);
|
||||
|
||||
cleanup:
|
||||
free(str_key_val);
|
||||
exit:
|
||||
// Close
|
||||
nvs_close(my_handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
void dump_custom_nvs_partition(const char *label, size_t len)
|
||||
{
|
||||
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, label);
|
||||
assert(partition);
|
||||
|
||||
uint8_t *read_data = calloc(len, sizeof(uint8_t));
|
||||
assert(read_data != NULL);
|
||||
|
||||
ESP_ERROR_CHECK(esp_partition_read(partition, 0, read_data, len));
|
||||
ESP_LOG_BUFFER_HEXDUMP(label, read_data, len, ESP_LOG_INFO);
|
||||
|
||||
free(read_data);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialising the default NVS partition");
|
||||
|
||||
/* Initialising the default NVS partition */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* Erasing the custom NVS partition */
|
||||
ESP_ERROR_CHECK(nvs_flash_erase_partition(CUSTOM_NVS_PART_LABEL));
|
||||
|
||||
ESP_LOGI(TAG, "Initialising the custom NVS partition");
|
||||
/* Initialize the custom NVS partition with encryption enabled */
|
||||
esp_err_t ret = example_custom_nvs_part_init(CUSTOM_NVS_PART_LABEL);
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase_partition(CUSTOM_NVS_PART_LABEL));
|
||||
ret = example_custom_nvs_part_init(CUSTOM_NVS_PART_LABEL);
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = example_custom_nvs_part_write(CUSTOM_NVS_PART_LABEL, CUSTOM_NVS_PART_NAMESPACE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write NVS partition (%s | %s): %s", CUSTOM_NVS_PART_LABEL, CUSTOM_NVS_PART_NAMESPACE, esp_err_to_name(ret));
|
||||
};
|
||||
|
||||
ret = example_custom_nvs_part_read(CUSTOM_NVS_PART_LABEL, CUSTOM_NVS_PART_NAMESPACE);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read NVS partition (%s | %s): %s", CUSTOM_NVS_PART_LABEL, CUSTOM_NVS_PART_NAMESPACE, esp_err_to_name(ret));
|
||||
};
|
||||
|
||||
dump_custom_nvs_partition(CUSTOM_NVS_PART_LABEL, CUSTOM_NVS_PART_DUMP_SIZE);
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, , 24K,
|
||||
factory, app, factory, , 1M,
|
||||
custom_nvs, data, nvs, , 24K,
|
|
@ -0,0 +1,45 @@
|
||||
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import logging
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.dut import IdfDut
|
||||
|
||||
STR_KEY_VAL = ['Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
'Fusce quis risus justo.',
|
||||
'Suspendisse egestas in nisi sit amet auctor.',
|
||||
'Pellentesque rhoncus dictum sodales.',
|
||||
'In justo erat, viverra at interdum eget, interdum vel dui.']
|
||||
|
||||
ENCR_TEXT_ARR = ['fe ff ff ff 00 00 00 00 fe ff ff ff ff ff ff ff',
|
||||
'ca 8b c3 bb 2d c2 33 d6 6b d4 a7 3d 31 0e 9c 36',
|
||||
'bd c1 2a 10 87 44 5e 1c 4b 2c 7c 5d ac 97 48 63']
|
||||
|
||||
|
||||
@pytest.mark.esp32c3
|
||||
@pytest.mark.nvs_encr_hmac
|
||||
@pytest.mark.parametrize('config', ['nvs_encr_hmac'], indirect=True)
|
||||
def test_nvs_flash_encr_keys_hmac(dut: IdfDut) -> None:
|
||||
# Logging example binary details
|
||||
binary_file = os.path.join(dut.app.binary_path, 'nvs_encryption_hmac.bin')
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
logging.info('nvs_encryption_hmac_bin_size : {}KB'.format(bin_size // 1024))
|
||||
|
||||
# Start test and verify serial output
|
||||
dut.expect('NVS partition "nvs" is encrypted.', timeout=30)
|
||||
dut.expect('NVS partition "custom_nvs" is encrypted', timeout=30)
|
||||
|
||||
dut.expect('Key: u8_key | Val: 255', timeout=30)
|
||||
dut.expect('Key: i8_key | Val: -128', timeout=30)
|
||||
dut.expect('Key: u16_key | Val: 65535', timeout=30)
|
||||
dut.expect('Key: u32_key | Val: 4294967295', timeout=30)
|
||||
dut.expect('Key: i32_key | Val: -2147483648', timeout=30)
|
||||
|
||||
for string in STR_KEY_VAL:
|
||||
dut.expect(string, timeout=30)
|
||||
|
||||
for encr_txt in ENCR_TEXT_ARR:
|
||||
dut.expect(encr_txt, timeout=30)
|
||||
|
||||
dut.expect('Returned from app_main()', timeout=30)
|
@ -0,0 +1,16 @@
|
||||
# Partition Table
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
|
||||
# NOTE: The runner for this example has flash-encryption enabled
|
||||
# Flash Encryption
|
||||
CONFIG_SECURE_FLASH_ENC_ENABLED=y
|
||||
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y
|
||||
CONFIG_SECURE_BOOT_ALLOW_JTAG=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y
|
||||
CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y
|
||||
CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y
|
||||
|
||||
# NVS Encryption
|
||||
CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID=0
|
7
examples/security/nvs_encryption_hmac/sdkconfig.defaults
Normal file
7
examples/security/nvs_encryption_hmac/sdkconfig.defaults
Normal file
@ -0,0 +1,7 @@
|
||||
# This example uses an extra partition to demonstrate encrypted/non-encrypted reads/writes.
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
|
||||
|
||||
CONFIG_NVS_ENCRYPTION=y
|
||||
CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC=y
|
@ -716,7 +716,6 @@ components/mqtt/host_test/mocks/include/freertos/portmacro.h
|
||||
components/mqtt/host_test/mocks/include/machine/endian.h
|
||||
components/mqtt/host_test/mocks/include/sys/queue.h
|
||||
components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp
|
||||
components/nvs_flash/include/nvs_flash.h
|
||||
components/nvs_flash/include/nvs_handle.hpp
|
||||
components/nvs_flash/src/nvs_cxx_api.cpp
|
||||
components/nvs_flash/src/nvs_encrypted_partition.hpp
|
||||
|
@ -11,14 +11,15 @@ This utility is designed to create instances of factory NVS partition images on
|
||||
Please note that this utility only creates manufacturing binary images which then need to be flashed onto your devices using:
|
||||
|
||||
- `esptool.py`_
|
||||
- `Flash Download tool <https://www.espressif.com/en/support/download/other-tools?keys=flash+download+tools>`_ (available on Windows only).Just download it, unzip, and follow the instructions inside the *doc* folder.
|
||||
- `Flash Download tool <https://www.espressif.com/en/support/download/other-tools?keys=flash+download+tools>`_ (available on Windows only)
|
||||
- Download and unzip it, and follow the instructions inside the *doc* folder.
|
||||
- Direct flash programming using custom production tools.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
**This utility is dependent on esp-idf's NVS partition utility.**
|
||||
**This utility is dependent on ESP-IDF's NVS Partition Generator Utility.**
|
||||
|
||||
* Operating System requirements:
|
||||
- Linux / MacOS / Windows (standard distributions)
|
||||
@ -30,7 +31,7 @@ Prerequisites
|
||||
|
||||
Before using this utility, please make sure that:
|
||||
- The path to Python is added to the PATH environment variable.
|
||||
- You have installed the packages from `requirement.txt`, the file in the root of the esp-idf directory.
|
||||
- You have installed the packages from `requirement.txt`, the file in the root of the ESP-IDF directory.
|
||||
|
||||
|
||||
Workflow
|
||||
@ -66,7 +67,7 @@ The data in the configuration file has the following format (the `REPEAT` tag is
|
||||
Each line should have three parameters: ``key,type,encoding``, separated by a comma.
|
||||
If the ``REPEAT`` tag is present, the value corresponding to this key in the master value CSV file will be the same for all devices.
|
||||
|
||||
*Please refer to README of the NVS Partition Generator utility for detailed description of each parameter.*
|
||||
*Please refer to README of the NVS Partition Generator Utility for detailed description of each parameter.*
|
||||
|
||||
Below is a sample example of such a configuration file::
|
||||
|
||||
@ -134,31 +135,32 @@ Running the utility
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
+-----+------------+----------------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+============+======================================================================+
|
||||
| 1 | -h, --help | show this help message and exit |
|
||||
+-----+------------+----------------------------------------------------------------------+
|
||||
+-----+------------------------+----------------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+========================+======================================================================+
|
||||
| 1 | ``-h`` / ``--help`` | Show the help message and exit |
|
||||
+-----+------------------------+----------------------------------------------------------------------+
|
||||
|
||||
**Commands**:
|
||||
|
||||
Run mfg_gen.py {command} -h for additional help
|
||||
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+==============+====================================================================+
|
||||
| 1 | generate | Generate NVS partition |
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
| 2 | generate-key | Generate keys for encryption |
|
||||
+-----+--------------+--------------------------------------------------------------------+
|
||||
+-----+------------------+--------------------------------------------------------------------+
|
||||
| No. | Parameter | Description |
|
||||
+=====+==================+====================================================================+
|
||||
| 1 | ``generate`` | Generate NVS partition |
|
||||
+-----+------------------+--------------------------------------------------------------------+
|
||||
| 2 | ``generate-key`` | Generate keys for encryption |
|
||||
+-----+------------------+--------------------------------------------------------------------+
|
||||
|
||||
**To generate factory images for each device (Default):**
|
||||
|
||||
**Usage**::
|
||||
|
||||
python mfg_gen.py generate [-h] [--fileid FILEID] [--version {1,2}] [--keygen]
|
||||
[--keyfile KEYFILE] [--inputkey INPUTKEY]
|
||||
[--outdir OUTDIR]
|
||||
[--inputkey INPUTKEY] [--outdir OUTDIR]
|
||||
[--key_protect_hmac] [--kp_hmac_keygen]
|
||||
[--kp_hmac_keyfile KP_HMAC_KEYFILE] [--kp_hmac_inputkey KP_HMAC_INPUTKEY]
|
||||
conf values prefix size
|
||||
|
||||
**Positional Arguments**:
|
||||
@ -166,38 +168,47 @@ Running the utility
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+==============+======================================================================+
|
||||
| conf | Path to configuration csv file to parse |
|
||||
| ``conf`` | Path to configuration csv file to parse |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| values | Path to values csv file to parse |
|
||||
| ``values`` | Path to values csv file to parse |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| prefix | Unique name for each output filename prefix |
|
||||
+-----+--------------+----------------------------------------------------------------+
|
||||
| size | Size of NVS partition in bytes |
|
||||
| | (must be multiple of 4096) |
|
||||
| ``prefix`` | Unique name for each output filename prefix |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
| ``size`` | Size of NVS partition in bytes (must be multiple of 4096) |
|
||||
+--------------+----------------------------------------------------------------------+
|
||||
|
||||
**Optional Arguments**:
|
||||
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=====================+====================================================================+
|
||||
| -h, --help | show this help message and exit |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --fileid FILEID | Unique file identifier(any key in values file) |
|
||||
| | for each filename suffix (Default: numeric value(1,2,3...) |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --version {1,2} | Set multipage blob version. |
|
||||
| | Version 1 - Multipage blob support disabled. |
|
||||
| | Version 2 - Multipage blob support enabled. |
|
||||
| | Default: Version 2 |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --keygen | Generates key for encrypting NVS partition |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --inputkey INPUTKEY | File having key for encrypting NVS partition |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
| --outdir OUTDIR | Output directory to store files created |
|
||||
| | (Default: current directory) |
|
||||
+---------------------+--------------------------------------------------------------------+
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=============================================+===============================================================================+
|
||||
| ``-h`` / ``--help`` | Show the help message and exit |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--fileid FILEID`` | Unique file identifier (any key in values file) |
|
||||
| | for each filename suffix (Default: numeric value(1,2,3...)) |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--version {1,2}`` | Set multipage blob version. (Default: Version 2) |
|
||||
| | |
|
||||
| | Version 1 - Multipage blob support disabled. |
|
||||
| | |
|
||||
| | Version 2 - Multipage blob support enabled. |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--keygen`` | Generates key for encrypting NVS partition |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--inputkey INPUTKEY`` | File having key for encrypting NVS partition |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--outdir OUTDIR`` | Output directory to store files created (Default: current directory) |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--key_protect_hmac`` | If set, the NVS encryption key protection scheme based on HMAC |
|
||||
| | peripheral is used; else the default scheme based on Flash Encryption |
|
||||
| | is used |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keygen`` | Generate the HMAC key for HMAC-based encryption scheme |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keyfile KP_HMAC_KEYFILE`` | Path to output HMAC key file |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_inputkey KP_HMAC_INPUTKEY`` | File having the HMAC key for generating the NVS encryption keys |
|
||||
+---------------------------------------------+-------------------------------------------------------------------------------+
|
||||
|
||||
You can run the utility to generate factory images for each device using the command below. A sample CSV file is provided with the utility::
|
||||
|
||||
@ -213,7 +224,21 @@ You can run the utility to encrypt factory images for each device using the comm
|
||||
|
||||
python mfg_gen.py generate samples/sample_config.csv samples/sample_values_singlepage_blob.csv Sample 0x3000 --keygen
|
||||
|
||||
.. note:: Encryption key of the following format ``<outdir>/keys/keys-<prefix>-<fileid>.bin`` is created. This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_key_partition` for more details.
|
||||
.. note:: Encryption key of the following format ``<outdir>/keys/keys-<prefix>-<fileid>.bin`` is created. This newly created file having encryption keys in ``keys/`` directory is compatible with NVS key-partition structure. Refer to :ref:`nvs_encr_key_partition` for more details.
|
||||
|
||||
- To generate an encrypted image using the HMAC-based scheme, the above command can be used alongwith some additional parameters.
|
||||
|
||||
- Encrypt by allowing the utility to generate encryption keys and the HMAC-key::
|
||||
|
||||
python mfg_gen.py generate samples/sample_config.csv samples/sample_values_singlepage_blob.csv Sample 0x3000 --keygen --key_protect_hmac --kp_hmac_keygen
|
||||
|
||||
.. note:: Encryption key of the format ``<outdir>/keys/keys-<timestamp>.bin`` and HMAC key of the format ``<outdir>/keys/hmac-keys-<timestamp>.bin`` are created.
|
||||
|
||||
- Encrypt by allowing the utility to generate encryption keys with user-provided HMAC-key::
|
||||
|
||||
python mfg_gen.py generate samples/sample_config.csv samples/sample_values_singlepage_blob.csv Sample 0x3000 --keygen --key_protect_hmac --kp_hmac_inputkey testdata/sample_hmac_key.bin
|
||||
|
||||
.. note:: You can provide the custom filename for the HMAC key as well as the encryption key as a parameter.
|
||||
|
||||
- Encrypt by providing the encryption keys as input binary file::
|
||||
|
||||
@ -225,16 +250,25 @@ You can run the utility to encrypt factory images for each device using the comm
|
||||
python mfg_gen.py generate-key [-h] [--keyfile KEYFILE] [--outdir OUTDIR]
|
||||
|
||||
**Optional Arguments**:
|
||||
+--------------------+----------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+====================+======================================================================+
|
||||
| -h, --help | show this help message and exit |
|
||||
+--------------------+----------------------------------------------------------------------+
|
||||
| --keyfile KEYFILE | Path to output encryption keys file |
|
||||
+--------------------+----------------------------------------------------------------------+
|
||||
| --outdir OUTDIR | Output directory to store files created. |
|
||||
| | (Default: current directory) |
|
||||
+--------------------+----------------------------------------------------------------------+
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| Parameter | Description |
|
||||
+=============================================+===================================================================================+
|
||||
| ``-h`` / ``--help`` | Show the help message and exit |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--keyfile KEYFILE`` | Path to output encryption keys file |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--outdir OUTDIR`` | Output directory to store files created. (Default: current directory) |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--key_protect_hmac`` | If set, the NVS encryption key protection scheme based on HMAC |
|
||||
| | peripheral is used; else the default scheme based on Flash Encryption |
|
||||
| | is used |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keygen`` | Generate the HMAC key for HMAC-based encryption scheme |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_keyfile KP_HMAC_KEYFILE`` | Path to output HMAC key file |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
| ``--kp_hmac_inputkey KP_HMAC_INPUTKEY`` | File having the HMAC key for generating the NVS encryption keys |
|
||||
+---------------------------------------------+-----------------------------------------------------------------------------------+
|
||||
|
||||
You can run the utility to generate only encryption keys using the command below::
|
||||
|
||||
@ -242,6 +276,20 @@ You can run the utility to generate only encryption keys using the command below
|
||||
|
||||
.. note:: Encryption key of the following format ``<outdir>/keys/keys-<timestamp>.bin`` is created. Timestamp format is: ``%m-%d_%H-%M``. To provide custom target filename use the --keyfile argument.
|
||||
|
||||
For generating encryption key for the HMAC-based scheme, the following commands can be used:
|
||||
|
||||
- Generate the HMAC key and the NVS encryption keys::
|
||||
|
||||
python mfg_gen.py generate-key --key_protect_hmac --kp_hmac_keygen
|
||||
|
||||
.. note:: Encryption key of the format ``<outdir>/keys/keys-<timestamp>.bin`` and HMAC key of the format ``<outdir>/keys/hmac-keys-<timestamp>.bin`` are created.
|
||||
|
||||
- Generate the NVS encryption keys, given the HMAC-key::
|
||||
|
||||
python mfg_gen.py generate-key --key_protect_hmac --kp_hmac_inputkey testdata/sample_hmac_key.bin
|
||||
|
||||
.. note:: You can provide the custom filename for the HMAC key as well as the encryption key as a parameter.
|
||||
|
||||
Generated encryption key binary file can further be used to encrypt factory images created on the per device basis.
|
||||
|
||||
The default numeric value: 1,2,3... of the ``fileid`` argument corresponds to each line bearing device instance values in the master value CSV file.
|
||||
|
@ -420,7 +420,6 @@ def main():
|
||||
\nDefault: Version 2 ''')
|
||||
parser_gen.add_argument('--keygen',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Generates key for encrypting NVS partition')
|
||||
parser_gen.add_argument('--keyfile',
|
||||
default=None,
|
||||
@ -432,6 +431,20 @@ def main():
|
||||
default=os.getcwd(),
|
||||
help='Output directory to store files created\
|
||||
\n(Default: current directory)')
|
||||
parser_gen.add_argument('--key_protect_hmac',
|
||||
action='store_true',
|
||||
help='''If set, the NVS encryption key protection scheme based on HMAC\
|
||||
\nperipheral is used; else the default scheme based on Flash Encryption\
|
||||
\nis used''')
|
||||
parser_gen.add_argument('--kp_hmac_keygen',
|
||||
action='store_true',
|
||||
help='Generate the HMAC key for HMAC-based encryption scheme')
|
||||
parser_gen.add_argument('--kp_hmac_keyfile',
|
||||
default=None,
|
||||
help='Path to output HMAC key file')
|
||||
parser_gen.add_argument('--kp_hmac_inputkey',
|
||||
default=None,
|
||||
help='File having the HMAC key for generating the NVS encryption keys')
|
||||
parser_gen.add_argument('--input',
|
||||
default=None,
|
||||
help=argparse.SUPPRESS)
|
||||
@ -449,6 +462,20 @@ def main():
|
||||
default=os.getcwd(),
|
||||
help='Output directory to store files created.\
|
||||
\n(Default: current directory)')
|
||||
parser_gen_key.add_argument('--key_protect_hmac',
|
||||
action='store_true',
|
||||
help='''If set, the NVS encryption key protection scheme based on HMAC\
|
||||
\nperipheral is used; else the default scheme based on Flash Encryption\
|
||||
\nis used''')
|
||||
parser_gen_key.add_argument('--kp_hmac_keygen',
|
||||
action='store_true',
|
||||
help='Generate the HMAC key for HMAC-based encryption scheme')
|
||||
parser_gen_key.add_argument('--kp_hmac_keyfile',
|
||||
default=None,
|
||||
help='Path to output HMAC key file')
|
||||
parser_gen_key.add_argument('--kp_hmac_inputkey',
|
||||
default=None,
|
||||
help='File having the HMAC key for generating the NVS encryption keys')
|
||||
|
||||
args = parser.parse_args()
|
||||
args.func(args)
|
||||
|
1
tools/mass_mfg/testdata/sample_encryption_keys_hmac.bin
vendored
Normal file
1
tools/mass_mfg/testdata/sample_encryption_keys_hmac.bin
vendored
Normal file
@ -0,0 +1 @@
|
||||
˙i‰äúý-ŚłŞWCđ?›Š,…‡‡(2F‚ŕŕSŤ˝śŽ+§Q7vŚ<"ŰKŕVÚř«üšĎô:o“<1D>s¬“ÚW /˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙
|
2
tools/mass_mfg/testdata/sample_hmac_key.bin
vendored
Normal file
2
tools/mass_mfg/testdata/sample_hmac_key.bin
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user