# Secure Storage

## Overview

The TEE Secure Storage service provides persistent storage for securely storing sensitive data, such as cryptographic keys, cloud credentials, or other general-purpose information. It uses a dedicated flash partition of type `data` and subtype `nvs`. The TEE ensures both confidentiality and integrity of the stored data.

TEE Secure Storage adopts the Non-Volatile Storage Library partition format and uses the HMAC peripheral-based XTS-AES encryption scheme, as detailed here. The AES encryption keys are derived from an HMAC key programmed in eFuse with the purpose `esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`. Please note that the TEE Secure storage does not support the NVS Flash Encryption-based scheme.

Important

- One eFuse block is required to store the HMAC key used for deriving the NVS encryption keys. This key is exclusive to the TEE and CANNOT be used by the REE for any purpose.

- The HMAC key must be programmed into eFuse before firmware execution, as TEE Secure Storage does not support generating it on-device. If no valid key with the required purpose is found in the configured eFuse block, an error will be raised at runtime.

Additionally, the secure storage provides interfaces for performing the following cryptographic services from the TEE using securely stored key material:

> 1. Message signing and public key retrieval using the `ecdsa_secp256r1` and `ecdsa_secp192r1` algorithms

> 2. Authenticated encryption and decryption using the `aes256_gcm` algorithm

Note

As per the current implementation, the TEE Secure Storage partition must have the label `secure_storage`.

## Internals

Each data object consisting of the type, associated metadata flags (e.g., `WRITE_ONCE`), and the actual payload is encapsulated in a structured format and stored as a variable-length NVS blob in the secure storage partition.

Note

As per the current implementation, all data objects in the TEE Secure Storage are to be stored in the `tee_sec_stg_ns` namespace.

Currently, TEE secure storage supports storing the following cryptographic keys:

> 1. `ecdsa_secp256r1` and `ecdsa_secp192r1` curve key-pairs, including private and public key components

> 2. `aes256` keys, including the key and initialization vector (IV)

All assets related to TEE secure storage are protected by the APM peripheral and are inaccessible to the REE application. Any direct access attempts will result in a system fault. Future updates are planned to add support for additional key types and general-purpose data storage.

The TEE Secure Storage feature supports two modes for determining how the NVS encryption keys are derived (see CONFIG_SECURE_TEE_SEC_STG_MODE):

> - Development Mode: Encryption keys are embedded (constant for all instances) in the ESP-TEE firmware.

> - Release Mode: Encryption keys are derived via the HMAC peripheral using a key stored in eFuse, specified by CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID.

> Note

> - The valid range for CONFIG_SECURE_TEE_SEC_STG_EFUSE_HMAC_KEY_ID is from `0` (`hmac_key_id_t::HMAC_KEY0`) to `5` (`hmac_key_id_t::HMAC_KEY5`). By default, this config is set to `-1` and must be configured before building the TEE application.

> - The following commands can be used to generate and program the HMAC key into the required eFuse block:

>       # Generate a random 32-byte HMAC key
>       openssl rand -out hmac_key_file.bin 32

>       # Program the HMAC key into the eFuse block
>       idf.py -p PORT efuse-burn-key <BLOCK_KEY0-5> hmac_key_file.bin HMAC_UP

## Tools

The NVS Partition Generator Utility tool can be used to generate binary images compatible with the NVS format for use with TEE Secure Storage. Since TEE Secure Storage stores data objects using a custom structured format, an additional step is required to convert input data into this format prior to image generation and encryption.

To support this process, the esp_tee_sec_stg_keygen.py script is provided for generating secure key blobs corresponding to the various supported cryptographic algorithms. These key blobs are then referenced in the input CSV file (format described here) and passed to the NVS Partition Generator utility to produce an encrypted images suitable for TEE Secure Storage.

Refer the detailed steps given here on generating key blobs and encrypted NVS partition images for TEE Secure Storage.

## Application Example

The tee_secure_storage example demonstrates how to generate ECDSA key pairs and AES-256 keys in the TEE secure storage and use them for signing messages and encrypting/decrypting data.

## API Reference

Note

To use the TEE Secure Storage APIs in your project, ensure that the tee_sec_storage component is listed as a local dependency in the component manager manifest file idf_component.yml. Refer to the tee_secure_storage example for guidance.

### Header File

- components/esp_tee/subproject/components/tee_sec_storage/include/esp_tee_sec_storage.h

### Functions

esp_err_t esp_tee_sec_storage_clear_key(const char *key_id)

  Clear a key from secure storage.

  Parameters:

    key_id -- Key identifier string

  Returns:

    esp_err_t ESP_OK on success, appropriate error code otherwise.

esp_err_t esp_tee_sec_storage_gen_key(const esp_tee_sec_storage_key_cfg_t *cfg)

  Generate a unique key and store it in the secure storage.

  Parameters:

    cfg -- Pointer to the key configuration

  Returns:

    esp_err_t ESP_OK on success, appropriate error code otherwise.

esp_err_t esp_tee_sec_storage_ecdsa_sign(const esp_tee_sec_storage_key_cfg_t *cfg, const uint8_t *hash, size_t hlen, esp_tee_sec_storage_ecdsa_sign_t *out_sign)

  Generate and return the signature for the specified message digest using the key pair located in the secure storage.

  Parameters:

    - cfg -- [in] Pointer to the key configuration

    - hash -- [in] Message digest

    - hlen -- [in] Digest length

    - out_sign -- [out] Output context holding the signature

  Returns:

    esp_err_t ESP_OK on success, appropriate error code otherwise.

esp_err_t esp_tee_sec_storage_ecdsa_get_pubkey(const esp_tee_sec_storage_key_cfg_t *cfg, esp_tee_sec_storage_ecdsa_pubkey_t *out_pubkey)

  Return the public key from secure storage.

  Parameters:

    - cfg -- [in] Pointer to the key configuration

    - out_pubkey -- [out] Output context holding the public key

  Returns:

    esp_err_t ESP_OK on success, appropriate error code otherwise.

esp_err_t esp_tee_sec_storage_aead_encrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, uint8_t *tag, size_t tag_len, uint8_t *output)

  Perform encryption using AES256-GCM with the key from secure storage.

  Parameters:

    - ctx -- [in] Pointer to the AEAD operation context

    - tag -- [out] Pointer to the authentication tag buffer

    - tag_len -- [in] Length of the authentication tag

    - output -- [out] Pointer to the output data buffer

  Returns:

    esp_err_t ESP_OK on success, appropriate error code otherwise.

esp_err_t esp_tee_sec_storage_aead_decrypt(const esp_tee_sec_storage_aead_ctx_t *ctx, const uint8_t *tag, size_t tag_len, uint8_t *output)

  Perform decryption using AES256-GCM with the key from secure storage.

  Parameters:

    - ctx -- [in] Pointer to the AEAD operation context

    - tag -- [in] Pointer to the authentication tag buffer

    - tag_len -- [in] Length of the authentication tag

    - output -- [out] Pointer to the output data buffer

  Returns:

    esp_err_t ESP_OK on success, appropriate error code otherwise.

### Structures

struct esp_tee_sec_storage_key_cfg_t

  Configuration structure for key generation/import.

  Public Members

  const char *id

    Unique identifier for the key

  esp_tee_sec_storage_type_t type

    Type of key (AES256, ECDSA_SECP256R1, etc.)

  uint32_t flags

    Key flags (e.g. WRITE_ONCE)

struct esp_tee_sec_storage_aead_ctx_t

  Context structure for AES-GCM AEAD encryption/decryption operations.

  Public Members

  const char *key_id

    Identifier of the key to use

  const uint8_t *aad

    Additional authenticated data

  size_t aad_len

    Length of additional authenticated data

  const uint8_t *input

    Input data buffer

  size_t input_len

    Length of input data

struct esp_tee_sec_storage_ecdsa_pubkey_t

  Structure holding the X and Y components of the ECDSA public key.

  Public Members

  uint8_t pub_x[MAX_ECDSA_SUPPORTED_KEY_LEN]

    X component

  uint8_t pub_y[MAX_ECDSA_SUPPORTED_KEY_LEN]

    Y component

struct esp_tee_sec_storage_ecdsa_sign_t

  Structure holding the R and S components of the ECDSA signature.

  Public Members

  uint8_t sign_r[MAX_ECDSA_SUPPORTED_KEY_LEN]

    R component

  uint8_t sign_s[MAX_ECDSA_SUPPORTED_KEY_LEN]

    S component

### Macros

MAX_ECDSA_SUPPORTED_KEY_LEN

  Maximum supported size for the ECDSA key

MAX_AES_SUPPORTED_KEY_LEN

  Maximum supported size for the AES key

SEC_STORAGE_FLAG_NONE

  No flags

SEC_STORAGE_FLAG_WRITE_ONCE

  Data can only be written once

### Enumerations

enum esp_tee_sec_storage_type_t

  Enum to represent the type of key stored in the secure storage.

  Values:

  enumerator ESP_SEC_STG_KEY_AES256
  enumerator ESP_SEC_STG_KEY_ECDSA_SECP256R1
  enumerator ESP_SEC_STG_KEY_ECDSA_SECP192R1
  enumerator ESP_SEC_STG_TYPE_MAX

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.