Skip to content

Commit

Permalink
nvs_flash: Add support for nvs encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
sagb2015 committed Sep 24, 2018
1 parent 4d50427 commit 48fccbf
Show file tree
Hide file tree
Showing 43 changed files with 1,902 additions and 171 deletions.
3 changes: 3 additions & 0 deletions components/bootloader_support/src/bootloader_utility.c
Expand Up @@ -133,6 +133,9 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs)
case PART_SUBTYPE_DATA_WIFI:
partition_usage = "WiFi data";
break;
case PART_SUBTYPE_DATA_NVS_KEYS:
partition_usage = "NVS keys";
break;
default:
partition_usage = "Unknown data";
break;
Expand Down
3 changes: 2 additions & 1 deletion components/bootloader_support/src/flash_encrypt.c
Expand Up @@ -286,7 +286,8 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit
&partition->pos,
&data_ignored);
should_encrypt = (err == ESP_OK);
} else if (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA) {
} else if ((partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_OTA)
|| (partition->type == PART_TYPE_DATA && partition->subtype == PART_SUBTYPE_DATA_NVS_KEYS)) {
/* check if we have ota data partition and the partition should be encrypted unconditionally */
should_encrypt = true;
}
Expand Down
21 changes: 21 additions & 0 deletions components/esp32/esp_err_to_name.c
Expand Up @@ -165,6 +165,27 @@ static const esp_err_msg_t esp_err_msg_table[] = {
ERR_TBL_IT(ESP_ERR_NVS_NEW_VERSION_FOUND), /* 4368 0x1110 NVS partition contains data in new format
and cannot be recognized by this version of
code */
# endif
# ifdef ESP_ERR_NVS_XTS_ENCR_FAILED
ERR_TBL_IT(ESP_ERR_NVS_XTS_ENCR_FAILED), /* 4369 0x1111 XTS encryption failed while writing NVS entry */
# endif
# ifdef ESP_ERR_NVS_XTS_DECR_FAILED
ERR_TBL_IT(ESP_ERR_NVS_XTS_DECR_FAILED), /* 4370 0x1112 XTS decryption failed while reading NVS entry */
# endif
# ifdef ESP_ERR_NVS_XTS_CFG_FAILED
ERR_TBL_IT(ESP_ERR_NVS_XTS_CFG_FAILED), /* 4371 0x1113 XTS configuration setting failed */
# endif
# ifdef ESP_ERR_NVS_XTS_CFG_NOT_FOUND
ERR_TBL_IT(ESP_ERR_NVS_XTS_CFG_NOT_FOUND), /* 4372 0x1114 XTS configuration not found */
# endif
# ifdef ESP_ERR_NVS_ENCR_NOT_SUPPORTED
ERR_TBL_IT(ESP_ERR_NVS_ENCR_NOT_SUPPORTED), /* 4373 0x1115 NVS encryption is not supported in this version */
# endif
# ifdef ESP_ERR_NVS_KEYS_NOT_INITIALIZED
ERR_TBL_IT(ESP_ERR_NVS_KEYS_NOT_INITIALIZED), /* 4374 0x1116 NVS key partition is uninitialized */
# endif
# ifdef ESP_ERR_NVS_CORRUPT_KEY_PART
ERR_TBL_IT(ESP_ERR_NVS_CORRUPT_KEY_PART), /* 4375 0x1117 NVS key partition is corrupt */
# endif
// components/ulp/include/esp32/ulp.h
# ifdef ESP_ERR_ULP_BASE
Expand Down
245 changes: 245 additions & 0 deletions components/esp32/hwcrypto/aes.c
Expand Up @@ -88,6 +88,8 @@ void esp_aes_free( esp_aes_context *ctx )
bzero( ctx, sizeof( esp_aes_context ) );
}



/*
* AES key schedule (same for encryption or decryption, as hardware handles schedule)
*
Expand Down Expand Up @@ -385,3 +387,246 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx,

return 0;
}

/* Below XTS implementation is copied aes.c of mbedtls library.
* When MBEDTLS_AES_ALT is defined mbedtls expects alternate
* definition of XTS functions to be available. Even if this
* could have been avoided, it is done for consistency reason.
*/

void esp_aes_xts_init( esp_aes_xts_context *ctx )
{
esp_aes_init( &ctx->crypt );
esp_aes_init( &ctx->tweak );
}

void esp_aes_xts_free( esp_aes_xts_context *ctx )
{
esp_aes_free( &ctx->crypt );
esp_aes_free( &ctx->tweak );
}

static int esp_aes_xts_decode_keys( const unsigned char *key,
unsigned int keybits,
const unsigned char **key1,
unsigned int *key1bits,
const unsigned char **key2,
unsigned int *key2bits )
{
const unsigned int half_keybits = keybits / 2;
const unsigned int half_keybytes = half_keybits / 8;

switch( keybits )
{
case 256: break;
case 512: break;
default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH );
}

*key1bits = half_keybits;
*key2bits = half_keybits;
*key1 = &key[0];
*key2 = &key[half_keybytes];

return 0;
}

int esp_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits)
{
int ret;
const unsigned char *key1, *key2;
unsigned int key1bits, key2bits;

ret = esp_aes_xts_decode_keys( key, keybits, &key1, &key1bits,
&key2, &key2bits );
if( ret != 0 )
return( ret );

/* Set the tweak key. Always set tweak key for the encryption mode. */
ret = esp_aes_setkey( &ctx->tweak, key2, key2bits );
if( ret != 0 )
return( ret );

/* Set crypt key for encryption. */
return esp_aes_setkey( &ctx->crypt, key1, key1bits );
}

int esp_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits)
{
int ret;
const unsigned char *key1, *key2;
unsigned int key1bits, key2bits;

ret = esp_aes_xts_decode_keys( key, keybits, &key1, &key1bits,
&key2, &key2bits );
if( ret != 0 )
return( ret );

/* Set the tweak key. Always set tweak key for encryption. */
ret = esp_aes_setkey( &ctx->tweak, key2, key2bits );
if( ret != 0 )
return( ret );

/* Set crypt key for decryption. */
return esp_aes_setkey( &ctx->crypt, key1, key1bits );
}

/* Endianess with 64 bits values */
#ifndef GET_UINT64_LE
#define GET_UINT64_LE(n,b,i) \
{ \
(n) = ( (uint64_t) (b)[(i) + 7] << 56 ) \
| ( (uint64_t) (b)[(i) + 6] << 48 ) \
| ( (uint64_t) (b)[(i) + 5] << 40 ) \
| ( (uint64_t) (b)[(i) + 4] << 32 ) \
| ( (uint64_t) (b)[(i) + 3] << 24 ) \
| ( (uint64_t) (b)[(i) + 2] << 16 ) \
| ( (uint64_t) (b)[(i) + 1] << 8 ) \
| ( (uint64_t) (b)[(i) ] ); \
}
#endif

#ifndef PUT_UINT64_LE
#define PUT_UINT64_LE(n,b,i) \
{ \
(b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \
(b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \
(b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \
(b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \
(b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) ] = (unsigned char) ( (n) ); \
}
#endif

typedef unsigned char esp_be128[16];

/*
* GF(2^128) multiplication function
*
* This function multiplies a field element by x in the polynomial field
* representation. It uses 64-bit word operations to gain speed but compensates
* for machine endianess and hence works correctly on both big and little
* endian machines.
*/
static void esp_gf128mul_x_ble( unsigned char r[16],
const unsigned char x[16] )
{
uint64_t a, b, ra, rb;

GET_UINT64_LE( a, x, 0 );
GET_UINT64_LE( b, x, 8 );

ra = ( a << 1 ) ^ 0x0087 >> ( 8 - ( ( b >> 63 ) << 3 ) );
rb = ( a >> 63 ) | ( b << 1 );

PUT_UINT64_LE( ra, r, 0 );
PUT_UINT64_LE( rb, r, 8 );
}

/*
* AES-XTS buffer encryption/decryption
*/
int esp_aes_crypt_xts( mbedtls_aes_xts_context *ctx,
int mode,
size_t length,
const unsigned char data_unit[16],
const unsigned char *input,
unsigned char *output )
{
int ret;
size_t blocks = length / 16;
size_t leftover = length % 16;
unsigned char tweak[16];
unsigned char prev_tweak[16];
unsigned char tmp[16];

/* Sectors must be at least 16 bytes. */
if( length < 16 )
return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;

/* NIST SP 80-38E disallows data units larger than 2**20 blocks. */
if( length > ( 1 << 20 ) * 16 )
return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;

/* Compute the tweak. */
ret = esp_aes_crypt_ecb( &ctx->tweak, MBEDTLS_AES_ENCRYPT,
data_unit, tweak );
if( ret != 0 )
return( ret );

while( blocks-- )
{
size_t i;

if( leftover && ( mode == MBEDTLS_AES_DECRYPT ) && blocks == 0 )
{
/* We are on the last block in a decrypt operation that has
* leftover bytes, so we need to use the next tweak for this block,
* and this tweak for the lefover bytes. Save the current tweak for
* the leftovers and then update the current tweak for use on this,
* the last full block. */
memcpy( prev_tweak, tweak, sizeof( tweak ) );
esp_gf128mul_x_ble( tweak, tweak );
}

for( i = 0; i < 16; i++ )
tmp[i] = input[i] ^ tweak[i];

ret = esp_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp );
if( ret != 0 )
return( ret );

for( i = 0; i < 16; i++ )
output[i] = tmp[i] ^ tweak[i];

/* Update the tweak for the next block. */
esp_gf128mul_x_ble( tweak, tweak );

output += 16;
input += 16;
}

if( leftover )
{
/* If we are on the leftover bytes in a decrypt operation, we need to
* use the previous tweak for these bytes (as saved in prev_tweak). */
unsigned char *t = mode == MBEDTLS_AES_DECRYPT ? prev_tweak : tweak;

/* We are now on the final part of the data unit, which doesn't divide
* evenly by 16. It's time for ciphertext stealing. */
size_t i;
unsigned char *prev_output = output - 16;

/* Copy ciphertext bytes from the previous block to our output for each
* byte of cyphertext we won't steal. At the same time, copy the
* remainder of the input for this final round (since the loop bounds
* are the same). */
for( i = 0; i < leftover; i++ )
{
output[i] = prev_output[i];
tmp[i] = input[i] ^ t[i];
}

/* Copy ciphertext bytes from the previous block for input in this
* round. */
for( ; i < 16; i++ )
tmp[i] = prev_output[i] ^ t[i];

ret = esp_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp );
if( ret != 0 )
return ret;

/* Write the result back to the previous block, overriding the previous
* output we copied. */
for( i = 0; i < 16; i++ )
prev_output[i] = tmp[i] ^ t[i];
}

return( 0 );
}
1 change: 1 addition & 0 deletions components/esp32/include/esp_flash_data_types.h
Expand Up @@ -60,6 +60,7 @@ typedef struct {
#define PART_SUBTYPE_DATA_OTA 0x00
#define PART_SUBTYPE_DATA_RF 0x01
#define PART_SUBTYPE_DATA_WIFI 0x02
#define PART_SUBTYPE_DATA_NVS_KEYS 0x04

#define PART_TYPE_END 0xff
#define PART_SUBTYPE_END 0xff
Expand Down
66 changes: 66 additions & 0 deletions components/esp32/include/hwcrypto/aes.h
Expand Up @@ -51,6 +51,19 @@ typedef struct {
uint8_t key[32];
} esp_aes_context;


/**
* \brief The AES XTS context-type definition.
*/
typedef struct
{
esp_aes_context crypt; /*!< The AES context to use for AES block
encryption or decryption. */
esp_aes_context tweak; /*!< The AES context used for tweak
computation. */
} esp_aes_xts_context;


/**
* \brief Lock access to AES hardware unit
*
Expand Down Expand Up @@ -86,6 +99,23 @@ void esp_aes_init( esp_aes_context *ctx );
*/
void esp_aes_free( esp_aes_context *ctx );

/**
* \brief This function initializes the specified AES XTS context.
*
* It must be the first API called before using
* the context.
*
* \param ctx The AES XTS context to initialize.
*/
void esp_aes_xts_init( esp_aes_xts_context *ctx );

/**
* \brief This function releases and clears the specified AES XTS context.
*
* \param ctx The AES XTS context to clear.
*/
void esp_aes_xts_free( esp_aes_xts_context *ctx );

/**
* \brief AES set key schedule (encryption or decryption)
*
Expand Down Expand Up @@ -233,6 +263,42 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx,
const unsigned char *input,
unsigned char *output );

/**
* \brief This function prepares an XTS context for encryption and
* sets the encryption key.
*
* \param ctx The AES XTS context to which the key should be bound.
* \param key The encryption key. This is comprised of the XTS key1
* concatenated with the XTS key2.
* \param keybits The size of \p key passed in bits. Valid options are:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits );

/**
* \brief This function prepares an XTS context for decryption and
* sets the decryption key.
*
* \param ctx The AES XTS context to which the key should be bound.
* \param key The decryption key. This is comprised of the XTS key1
* concatenated with the XTS key2.
* \param keybits The size of \p key passed in bits. Valid options are:
* <ul><li>256 bits (each of key1 and key2 is a 128-bit key)</li>
* <li>512 bits (each of key1 and key2 is a 256-bit key)</li></ul>
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure.
*/
int esp_aes_xts_setkey_dec( esp_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits );


/**
* \brief Internal AES block encryption function
Expand Down

0 comments on commit 48fccbf

Please sign in to comment.