crypto: SHA and AES accelerator bring up for S2

Brings up, fixes and enables AES and SHA hardware acceleration.

Closes IDF-714
Closes IDF-716
This commit is contained in:
Marius Vikhammer 2020-01-16 14:31:10 +08:00
parent 59381b60c0
commit 37369a8a57
32 changed files with 3687 additions and 1550 deletions

View file

@ -74,14 +74,15 @@ target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/mbedtls_debug.c"
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c"
"${COMPONENT_DIR}/port/esp_mem.c"
"${COMPONENT_DIR}/port/esp_sha.c"
"${COMPONENT_DIR}/port/esp_sha1.c"
"${COMPONENT_DIR}/port/esp_sha256.c"
"${COMPONENT_DIR}/port/esp_sha512.c"
"${COMPONENT_DIR}/port/esp_timing.c"
"${COMPONENT_DIR}/port/esp_sha.c"
"${COMPONENT_DIR}/port/esp_aes_xts.c"
"${COMPONENT_DIR}/port/${idf_target}/esp_bignum.c"
"${COMPONENT_DIR}/port/${idf_target}/aes.c"
"${COMPONENT_DIR}/port/${idf_target}/sha.c")
"${COMPONENT_DIR}/port/${idf_target}/sha.c"
"${COMPONENT_DIR}/port/${idf_target}/esp_sha1.c"
"${COMPONENT_DIR}/port/${idf_target}/esp_sha256.c"
"${COMPONENT_DIR}/port/${idf_target}/esp_sha512.c")
foreach(target ${mbedtls_targets})
target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h")

View file

@ -189,13 +189,33 @@ menu "mbedTLS"
config MBEDTLS_HARDWARE_AES
bool "Enable hardware AES acceleration"
default y
depends on !IDF_TARGET_ESP32S2
help
Enable hardware accelerated AES encryption & decryption.
Note that if the ESP32 CPU is running at 240MHz, hardware AES does not
offer any speed boost over software AES.
config MBEDTLS_AES_USE_INTERRUPT
bool "Use interrupt for long AES operations"
depends on MBEDTLS_HARDWARE_AES
default y
help
Use an interrupt to coordinate long AES operations.
This allows other code to run on the CPU while an AES operation is pending.
Otherwise the CPU busy-waits.
config MBEDTLS_HARDWARE_GCM
bool "Enable partially hardware accelerated GCM"
#depends on IDF_TARGET_ESP32S2 && MBEDTLS_HARDWARE_AES
depends on 0
default n
help
Enable partially hardware accelerated GCM.
Due to hardware limitations, hardware acceleration currently does not
offer any speed boost over software GCM with hardware accelerated AES operations.
config MBEDTLS_HARDWARE_MPI
bool "Enable hardware MPI (bignum) acceleration"
default y
@ -211,11 +231,10 @@ menu "mbedTLS"
config MBEDTLS_HARDWARE_SHA
bool "Enable hardware SHA acceleration"
default y
depends on !IDF_TARGET_ESP32S2
help
Enable hardware accelerated SHA1, SHA256, SHA384 & SHA512 in mbedTLS.
Due to a hardware limitation, hardware acceleration is only
Due to a hardware limitation, on the ESP32 hardware acceleration is only
guaranteed if SHA digests are calculated one at a time. If more
than one SHA digest is calculated at the same time, one will
be calculated fully in hardware and the rest will be calculated

View file

@ -508,247 +508,4 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx,
esp_aes_release_hardware();
return( ret );
}
/* 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( esp_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( esp_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( esp_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 );
}
}

File diff suppressed because it is too large Load diff

View file

@ -223,8 +223,8 @@ static inline void start_op(uint32_t op_reg)
*/
static inline void wait_op_complete(uint32_t op_reg)
{
while(DPORT_REG_READ(RSA_QUERY_INTERRUPT_REG) != 1)
{ }
while (DPORT_REG_READ(RSA_QUERY_INTERRUPT_REG) != 1)
{ }
/* clear the interrupt */
DPORT_REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1);
@ -258,7 +258,7 @@ int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
esp_mpi_acquire_hardware();
DPORT_REG_WRITE(RSA_LENGTH_REG, (num_words-1));
DPORT_REG_WRITE(RSA_LENGTH_REG, (num_words - 1));
DPORT_REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime);
/* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */
@ -404,17 +404,17 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
size_t num_words = MAX(x_words, y_words);
size_t z_words = x_words + y_words;
/* Short-circuit eval if either argument is 0 or 1.
/* Short-circuit eval if either argument is 0 or 1.
This is needed as the mpi modular division
argument will sometimes call in here when one
argument is too large for the hardware unit, but the other
argument is zero or one.
This is needed as the mpi modular division
argument will sometimes call in here when one
argument is too large for the hardware unit, but the other
argument is zero or one.
This leaks some timing information, although overall there is a
lot less timing variation than a software MPI approach.
This leaks some timing information, although overall there is a
lot less timing variation than a software MPI approach.
*/
if (x_bits == 0 || y_bits== 0) {
if (x_bits == 0 || y_bits == 0) {
mbedtls_mpi_lset(Z, 0);
return 0;
}
@ -449,7 +449,7 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
} else {
/* Still too long for the hardware unit... */
mbedtls_mpi_grow(Z, z_words);
if(y_words > x_words) {
if (y_words > x_words) {
return mpi_mult_mpi_overlong(Z, X, Y, y_words, z_words);
} else {
return mpi_mult_mpi_overlong(Z, Y, X, x_words, z_words);
@ -468,7 +468,7 @@ int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi
*/
DPORT_REG_WRITE(RSA_M_DASH_REG, 0);
DPORT_REG_WRITE(RSA_LENGTH_REG, (num_words*2 - 1));
DPORT_REG_WRITE(RSA_LENGTH_REG, (num_words * 2 - 1));
start_op(RSA_MULT_START_REG);
wait_op_complete(RSA_MULT_START_REG);

View file

@ -0,0 +1,255 @@
/*
* SHA-1 implementation with hardware ESP32 support added.
* Uses mbedTLS software implementation for failover when concurrent
* SHA operations are in use.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE LTD
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
*/
/*
* The SHA-1 standard was published by NIST in 1993.
*
* http://www.itl.nist.gov/fipspubs/fip180-1.htm
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA1_C) && defined(MBEDTLS_SHA1_ALT)
#include "mbedtls/sha1.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#include "esp32s2/sha.h"
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n )
{
volatile unsigned char *p = (unsigned char *)v; while ( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
}
#endif
void mbedtls_sha1_init( mbedtls_sha1_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_sha1_context ) );
}
void mbedtls_sha1_free( mbedtls_sha1_context *ctx )
{
if ( ctx == NULL ) {
return;
}
mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) );
}
void mbedtls_sha1_clone( mbedtls_sha1_context *dst,
const mbedtls_sha1_context *src )
{
memcpy(dst, src, sizeof(mbedtls_sha1_context));
}
/*
* SHA-1 context setup
*/
int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
memset( ctx, 0, sizeof( mbedtls_sha1_context ) );
ctx->mode = SHA1;
return 0;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_starts( mbedtls_sha1_context *ctx )
{
mbedtls_sha1_starts_ret( ctx );
}
#endif
static int esp_internal_sha1_dma_process(mbedtls_sha1_context *ctx,
const uint8_t *data, size_t len,
uint8_t *buf, size_t buf_len)
{
return esp_sha_dma(SHA1, data, len, buf, buf_len, ctx->first_block);
}
int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] )
{
int ret;
esp_sha_acquire_hardware();
ret = esp_sha_dma(ctx->mode, data, 64, 0, 0, ctx->first_block);
esp_sha_release_hardware();
return ret;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_process( mbedtls_sha1_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_sha1_process( ctx, data );
}
#endif
int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen )
{
int ret;
size_t fill;
uint32_t left, len, local_len = 0;
if ( !ilen || (input == NULL)) {
return 0;
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if ( ctx->total[0] < (uint32_t) ilen ) {
ctx->total[1]++;
}
if ( left && ilen >= fill ) {
memcpy( (void *) (ctx->buffer + left), input, fill );
input += fill;
ilen -= fill;
left = 0;
local_len = 64;
}
len = (ilen / 64) * 64;
if ( len || local_len) {
esp_sha_acquire_hardware();
if (ctx->sha_state == ESP_SHA1_STATE_INIT) {
ctx->first_block = true;
ctx->sha_state = ESP_SHA1_STATE_IN_PROCESS;
} else if (ctx->sha_state == ESP_SHA1_STATE_IN_PROCESS) {
ctx->first_block = false;
esp_sha_write_digest_state(SHA1, ctx->state);
}
ret = esp_internal_sha1_dma_process(ctx, input, len, ctx->buffer, local_len);
esp_sha_read_digest_state(SHA1, ctx->state);
esp_sha_release_hardware();
if (ret != 0) {
return ret;
}
}
if ( ilen > 0 ) {
memcpy( (void *) (ctx->buffer + left), input + len, ilen - len );
}
return 0;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_update( mbedtls_sha1_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_sha1_update_ret( ctx, input, ilen );
}
#endif
static const unsigned char sha1_padding[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-1 final digest
*/
int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, unsigned char output[20] )
{
int ret;
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_BE( high, msglen, 0 );
PUT_UINT32_BE( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
if ( ( ret = mbedtls_sha1_update_ret( ctx, sha1_padding, padn ) ) != 0 ) {
return ret;
}
if ( ( ret = mbedtls_sha1_update_ret( ctx, msglen, 8 ) ) != 0 ) {
return ret;
}
memcpy(output, ctx->state, 20);
return ret;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha1_finish( mbedtls_sha1_context *ctx,
unsigned char output[20] )
{
mbedtls_sha1_finish_ret( ctx, output );
}
#endif
#endif /* MBEDTLS_SHA1_C && MBEDTLS_SHA1_ALT */

View file

@ -0,0 +1,267 @@
/*
* SHA-256 implementation with hardware ESP32 support added.
* Uses mbedTLS software implementation for failover when concurrent
* SHA operations are in use.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE LTD
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
*/
/*
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_SHA256_ALT)
#include "mbedtls/sha256.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#include "esp32s2/sha.h"
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n )
{
volatile unsigned char *p = v; while ( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
do { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
} while( 0 )
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
do { \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
} while( 0 )
#endif
void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
{
if ( ctx == NULL ) {
return;
}
mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src )
{
*dst = *src;
}
/*
* SHA-256 context setup
*/
int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 )
{
memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
if ( is224 ) {
ctx->mode = SHA2_224;
} else {
ctx->mode = SHA2_256;
}
return 0;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx,
int is224 )
{
mbedtls_sha256_starts_ret( ctx, is224 );
}
#endif
int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] )
{
int ret;
esp_sha_acquire_hardware();
ret = esp_sha_dma(ctx->mode, data, 64, 0, 0, ctx->first_block);
esp_sha_release_hardware();
return ret;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_process( mbedtls_sha256_context *ctx,
const unsigned char data[64] )
{
mbedtls_internal_sha256_process( ctx, data );
}
#endif
/*
* SHA-256 process buffer
*/
int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, const unsigned char *input,
size_t ilen )
{
int ret = 0;
size_t fill;
uint32_t left, len, local_len = 0;
if ( ilen == 0 ) {
return 0;
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if ( ctx->total[0] < (uint32_t) ilen ) {
ctx->total[1]++;
}
/* Check if any data pending from previous call to this API */
if ( left && ilen >= fill ) {
memcpy( (void *) (ctx->buffer + left), input, fill );
input += fill;
ilen -= fill;
left = 0;
local_len = 64;
}
len = (ilen / 64) * 64;
if ( len || local_len) {
esp_sha_acquire_hardware();
if (ctx->sha_state == ESP_SHA256_STATE_INIT) {
ctx->first_block = true;
ctx->sha_state = ESP_SHA256_STATE_IN_PROCESS;
} else if (ctx->sha_state == ESP_SHA256_STATE_IN_PROCESS) {
ctx->first_block = false;
esp_sha_write_digest_state(ctx->mode, ctx->state);
}
ret = esp_sha_dma(ctx->mode, input, len, ctx->buffer, local_len, ctx->first_block);
esp_sha_read_digest_state(ctx->mode, ctx->state);
esp_sha_release_hardware();
if (ret != 0) {
return ret;
}
}
if ( ilen > 0 ) {
memcpy( (void *) (ctx->buffer + left), input + len, ilen - len );
}
return 0;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_update( mbedtls_sha256_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_sha256_update_ret( ctx, input, ilen );
}
#endif
static const unsigned char sha256_padding[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-256 final digest
*/
int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, unsigned char output[32] )
{
int ret;
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_BE( high, msglen, 0 );
PUT_UINT32_BE( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
if ( ( ret = mbedtls_sha256_update_ret( ctx, sha256_padding, padn ) ) != 0 ) {
return ret;
}
if ( ( ret = mbedtls_sha256_update_ret( ctx, msglen, 8 ) ) != 0 ) {
return ret;
}
memcpy(output, ctx->state, 32);
return ret;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx,
unsigned char output[32] )
{
mbedtls_sha256_finish_ret( ctx, output );
}
#endif
#endif /* MBEDTLS_SHA256_C && MBEDTLS_SHA256_ALT */

View file

@ -0,0 +1,317 @@
/*
* SHA-512 implementation with hardware ESP32 support added.
* Uses mbedTLS software implementation for failover when concurrent
* SHA operations are in use.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE LTD
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
*/
/*
* The SHA-512 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_SHA512_ALT)
#include "mbedtls/sha512.h"
#if defined(_MSC_VER) || defined(__WATCOMC__)
#define UL64(x) x##ui64
#else
#define UL64(x) x##ULL
#endif
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#include "esp32s2/sha.h"
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n )
{
volatile unsigned char *p = v; while ( n-- ) *p++ = 0;
}
/*
* 64-bit integer manipulation macros (big endian)
*/
#ifndef PUT_UINT64_BE
#define PUT_UINT64_BE(n,b,i) \
{ \
(b)[(i) ] = (unsigned char) ( (n) >> 56 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \
(b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \
(b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 7] = (unsigned char) ( (n) ); \
}
#endif /* PUT_UINT64_BE */
void esp_sha512_set_mode(mbedtls_sha512_context *ctx, esp_sha_type type)
{
switch (type) {
case SHA2_384:
case SHA2_512224:
case SHA2_512256:
case SHA2_512T:
ctx->mode = type;
break;
default:
ctx->mode = SHA2_512;
break;
}
}
/* For SHA512/t mode the intial hash value will depend on t */
void esp_sha512_set_t( mbedtls_sha512_context *ctx, uint16_t t_val)
{
ctx->t_val = t_val;
}
void mbedtls_sha512_init( mbedtls_sha512_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_sha512_context ) );
}
void mbedtls_sha512_free( mbedtls_sha512_context *ctx )
{
if ( ctx == NULL ) {
return;
}
mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) );
}
void mbedtls_sha512_clone( mbedtls_sha512_context *dst,
const mbedtls_sha512_context *src )
{
memcpy(dst, src, sizeof(mbedtls_sha512_context));
}
/*
* SHA-512 context setup
*/
int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 )
{
mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) );
if ( is384 ) {
ctx->mode = SHA2_384;
} else {
ctx->mode = SHA2_512;
}
return 0;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_starts( mbedtls_sha512_context *ctx,
int is384 )
{
mbedtls_sha512_starts_ret( ctx, is384 );
}
#endif
static int esp_internal_sha512_dma_process(mbedtls_sha512_context *ctx,
const uint8_t *data, size_t len,
uint8_t *buf, size_t buf_len)
{
return esp_sha_dma(ctx->mode, data, len, buf, buf_len, ctx->first_block);
}
int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] )
{
int ret;
esp_sha_acquire_hardware();
ret = esp_internal_sha512_dma_process(ctx, data, 128, 0, 0);
esp_sha_release_hardware();
return ret;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_process( mbedtls_sha512_context *ctx,
const unsigned char data[128] )
{
mbedtls_internal_sha512_process( ctx, data );
}
#endif
/*
* SHA-512 process buffer
*/
int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, const unsigned char *input,
size_t ilen )
{
int ret;
size_t fill;
unsigned int left, len, local_len = 0;
if ( ilen == 0 ) {
return 0;
}
left = (unsigned int) (ctx->total[0] & 0x7F);
fill = 128 - left;
ctx->total[0] += (uint64_t) ilen;
if ( ctx->total[0] < (uint64_t) ilen ) {
ctx->total[1]++;
}
if ( left && ilen >= fill ) {
memcpy( (void *) (ctx->buffer + left), input, fill );
input += fill;
ilen -= fill;
left = 0;
local_len = 128;
}
len = (ilen / 128) * 128;
if ( len || local_len) {
esp_sha_acquire_hardware();
if (ctx->sha_state == ESP_SHA512_STATE_INIT) {
if (ctx->mode == SHA2_512T) {
esp_sha_512_t_init_hash(ctx->t_val);
ctx->first_block = false;
} else {
ctx->first_block = true;
}
ctx->sha_state = ESP_SHA512_STATE_IN_PROCESS;
} else if (ctx->sha_state == ESP_SHA512_STATE_IN_PROCESS) {
ctx->first_block = false;
esp_sha_write_digest_state(ctx->mode, ctx->state);
}
ret = esp_internal_sha512_dma_process(ctx, input, len, ctx->buffer, local_len);
esp_sha_read_digest_state(ctx->mode, ctx->state);
esp_sha_release_hardware();
if (ret != 0) {
return ret;
}
}
if ( ilen > 0 ) {
memcpy( (void *) (ctx->buffer + left), input + len, ilen - len );
}
return 0;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_update( mbedtls_sha512_context *ctx,
const unsigned char *input,
size_t ilen )
{
mbedtls_sha512_update_ret( ctx, input, ilen );
}
#endif
static const unsigned char sha512_padding[128] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-512 final digest
*/
int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, unsigned char output[64] )
{
int ret;
size_t last, padn;
uint64_t high, low;
unsigned char msglen[16];
high = ( ctx->total[0] >> 61 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT64_BE( high, msglen, 0 );
PUT_UINT64_BE( low, msglen, 8 );
last = (size_t)( ctx->total[0] & 0x7F );
padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last );
if ( ( ret = mbedtls_sha512_update_ret( ctx, sha512_padding, padn ) ) != 0 ) {
return ret;
}
if ( ( ret = mbedtls_sha512_update_ret( ctx, msglen, 16 ) ) != 0 ) {
return ret;
}
if (ctx->mode == SHA2_384) {
memcpy(output, ctx->state, 48);
} else {
memcpy(output, ctx->state, 64);
}
return ret;
}
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
void mbedtls_sha512_finish( mbedtls_sha512_context *ctx,
unsigned char output[64] )
{
mbedtls_sha512_finish_ret( ctx, output );
}
#endif
#endif /* MBEDTLS_SHA512_C && MBEDTLS_SHA512_ALT */

View file

@ -3,7 +3,7 @@
* based on mbedTLS FIPS-197 compliant version.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -28,34 +28,38 @@
#include <string.h>
#include <stdio.h>
#include <sys/lock.h>
#include <assert.h>
#include "soc/soc.h"
#include "esp32s2/crypto_dma.h"
#include "esp32s2/sha.h"
#include "soc/crypto_dma_reg.h"
#include "esp_log.h"
#include "esp32s2/rom/ets_sys.h"
#include "soc/dport_reg.h"
#include "soc/hwcrypto_reg.h"
#include "esp32s2/rom/lldesc.h"
#include "esp32s2/rom/cache.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "soc/periph_defs.h"
#include "soc/cache_memory.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
/* Single lock for SHA engine
#include "esp32s2/sha.h"
#include "esp32s2/crypto_dma.h"
#include "esp32s2/rom/lldesc.h"
#include "soc/periph_defs.h"
#include "soc/crypto_dma_reg.h"
#include "driver/periph_ctrl.h"
#include "sys/param.h"
/* Max amount of bytes in a single DMA operation is 4095,
for SHA this means that the biggest safe amount of bytes is
31 blocks of 128 bytes = 3968
*/
#define SHA_DMA_MAX_BYTES 3968
/* Lock for SHA engine */
static _lock_t s_sha_lock;
/* Enable if want to use SHA interrupt */
//#define CONFIG_MBEDTLS_SHA_USE_INTERRUPT
#if defined(CONFIG_MBEDTLS_SHA_USE_INTERRUPT)
static SemaphoreHandle_t op_complete_sem;
#endif
const static char *TAG = "esp-sha";
/* Return block size (in bytes) for a given SHA type */
inline static size_t block_length(esp_sha_type type)
@ -96,190 +100,265 @@ inline static size_t state_length(esp_sha_type type)
}
}
/* This API was designed for ESP32, which has seperate
engines for SHA1,256,512. ESP32C has a single engine.
*/
static void esp_sha_lock_engine_inner(void);
bool esp_sha_try_lock_engine(esp_sha_type sha_type)
{
if (_lock_try_acquire(&s_sha_lock) != 0) {
/* SHA engine is already in use */
return false;
} else {
esp_sha_lock_engine_inner();
return true;
}
}
void esp_sha_lock_engine(esp_sha_type sha_type)
{
_lock_acquire(&s_sha_lock);
esp_sha_lock_engine_inner();
}
/* Enable SHA block and then lock it */
static void esp_sha_lock_engine_inner(void)
/* Enable SHA peripheral and then lock it */
void esp_sha_acquire_hardware()
{
/* Need to lock DMA since it is shared with AES block */
portENTER_CRITICAL(&crypto_dma_spinlock);
_lock_acquire(&crypto_dma_lock);
_lock_acquire(&s_sha_lock);
REG_SET_BIT(DPORT_PERIP_CLK_EN1_REG, DPORT_CRYPTO_SHA_CLK_EN | DPORT_CRYPTO_DMA_CLK_EN);
REG_CLR_BIT(DPORT_PERIP_RST_EN1_REG, DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_HMAC_RST |
DPORT_CRYPTO_DMA_RST | DPORT_CRYPTO_DS_RST);
/* Enable SHA and DMA hardware */
periph_module_enable(PERIPH_SHA_DMA_MODULE);
/* DMA for SHA */
REG_WRITE(CRYPTO_DMA_AES_SHA_SELECT_REG, 1);
}
/* Disable SHA block and then unlock it */
void esp_sha_unlock_engine(esp_sha_type sha_type)
/* Disable SHA peripheral block and then release it */
void esp_sha_release_hardware()
{
REG_WRITE(CRYPTO_DMA_AES_SHA_SELECT_REG, 0);
REG_SET_BIT(DPORT_PERIP_RST_EN1_REG, DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DMA_RST |
DPORT_CRYPTO_DS_RST);
REG_CLR_BIT(DPORT_PERIP_CLK_EN1_REG, DPORT_CRYPTO_SHA_CLK_EN | DPORT_CRYPTO_DMA_CLK_EN);
portEXIT_CRITICAL(&crypto_dma_spinlock);
/* Disable SHA and DMA hardware */
periph_module_disable(PERIPH_SHA_DMA_MODULE);
/* Need to lock DMA since it is shared with AES block */
_lock_release(&s_sha_lock);
_lock_release(&crypto_dma_lock);
}
#if defined (CONFIG_MBEDTLS_SHA_USE_INTERRUPT)
static IRAM_ATTR void esp_sha_dma_isr(void *arg)
/* Busy wait until SHA is idle */
static void esp_sha_wait_idle(void)
{
BaseType_t higher_woken;
REG_WRITE(SHA_CLEAR_IRQ_REG, 1);
xSemaphoreGiveFromISR(op_complete_sem, &higher_woken);
if (higher_woken) {
portYIELD_FROM_ISR();
while (DPORT_REG_READ(SHA_BUSY_REG) != 0) {
}
}
#endif
/* Check if SHA operation completed */
static int esp_sha_dma_complete(void)
void esp_sha_write_digest_state(esp_sha_type sha_type, void *digest_state)
{
#if defined (CONFIG_MBEDTLS_SHA_USE_INTERRUPT)
if (!xSemaphoreTake(op_complete_sem, 2000 / portTICK_PERIOD_MS)) {
ESP_LOGE("SHA", "Timed out waiting for completion of SHA Interrupt");
return -1;
uint32_t *digest_state_words = (uint32_t *)digest_state;
uint32_t *reg_addr_buf = (uint32_t *)(SHA_H_BASE);
for (int i = 0; i < state_length(sha_type) / 4; i++) {
REG_WRITE(&reg_addr_buf[i], digest_state_words[i]);
}
#else
esp_sha_wait_idle();
#endif
return 0;
}
/* Wait until SHA is busy */
void esp_sha_wait_idle(void)
{
while (DPORT_REG_READ(SHA_BUSY_REG) != 0) { }
}
/* Read the SHA digest from hardware */
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
{
uint32_t *digest_state_words = (uint32_t *)digest_state;
int word_len = state_length(sha_type) / 4;
esp_dport_access_read_buffer(digest_state_words, SHA_H_BASE, word_len);
/* Fault injection check: verify SHA engine actually ran,
state is not all zeroes.
*/
for (int i = 0; i < word_len; i++) {
if (digest_state_words[i] != 0) {
return;
}
}
abort(); // SHA peripheral returned all zero state, probably due to fault injection
}
/* The initial hash value for SHA512/t is generated according to the
algorithm described in the TRM, chapter SHA-Accelerator
*/
int esp_sha_512_t_init_hash(uint16_t t)
{
uint32_t t_string = 0;
uint8_t t0, t1, t2, t_len;
if (t == 384) {
ESP_LOGE(TAG, "Invalid t for SHA512/t, t = %u,cannot be 384", t);
return -1;
}
if (t <= 9) {
t_string = (uint32_t)((1 << 23) | ((0x30 + t) << 24));
t_len = 0x48;
} else if (t <= 99) {
t0 = t % 10;
t1 = (t / 10) % 10;
t_string = (uint32_t)((1 << 15) | ((0x30 + t0) << 16) |
(((0x30 + t1) << 24)));
t_len = 0x50;
} else if (t <= 512) {
t0 = t % 10;
t1 = (t / 10) % 10;
t2 = t / 100;
t_string = (uint32_t)((1 << 7) | ((0x30 + t0) << 8) |
(((0x30 + t1) << 16) + ((0x30 + t2) << 24)));
t_len = 0x58;
} else {
ESP_LOGE(TAG, "Invalid t for SHA512/t, t = %u, must equal or less than 512", t);
return -1;
}
REG_WRITE(SHA_T_LENGTH_REG, t_len);
REG_WRITE(SHA_T_STRING_REG, t_string);
REG_WRITE(SHA_MODE_REG, SHA2_512T);
REG_WRITE(SHA_START_REG, 1);
esp_sha_wait_idle();
memcpy(digest_state, (void *)SHA_H_BASE, state_length(sha_type));
return 0;
}
/* Internally calls DMA API for single block */
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block)
{
esp_sha_dma(sha_type, data_block, block_length(sha_type), is_first_block);
}
/* Performs SHA on multiple blocks at a time */
int esp_sha_dma(esp_sha_type sha_type, const void *data_block, uint32_t ilen, bool is_first_block)
static int esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
const void *buf, uint32_t buf_len, bool is_first_block);
/* Performs SHA on multiple blocks at a time using DMA
splits up into smaller operations for inputs that exceed a single DMA list
*/
int esp_sha_dma(esp_sha_type sha_type, const void *input, uint32_t ilen,
const void *buf, uint32_t buf_len, bool is_first_block)
{
size_t blk_len = 0;
const uint8_t *local_buf = data_block;
int ret = 0;
volatile lldesc_t dma_descr;
const void *dma_input;
unsigned char *non_icache_input = NULL;
unsigned char *non_icache_buf = NULL;
int dma_op_num = ( ilen / (SHA_DMA_MAX_BYTES + 1) ) + 1;
if (ilen == 0) {
return ret;
if (buf_len > 128) {
ESP_LOGE(TAG, "SHA DMA buf_len cannot exceed max size for a single block");
return -1;
}
blk_len = block_length(sha_type);
REG_WRITE(SHA_MODE_REG, sha_type);
if ((sha_type == SHA2_512T) && (is_first_block == true)) {
REG_WRITE(SHA_START_REG, 1);
}
REG_WRITE(SHA_BLOCK_NUM_REG, (ilen / blk_len));
if ((sha_type == SHA2_512T) && (is_first_block == true)) {
esp_sha_wait_idle();
is_first_block = false;
}
bzero( (void *)&dma_descr, sizeof( dma_descr ) );
/* DMA descriptor for Memory to DMA-AES transfer */
dma_descr.length = ilen;
dma_descr.size = ilen;
dma_descr.owner = 1;
dma_descr.eof = 1;
dma_descr.buf = local_buf;
dma_descr.sosf = 0;
dma_descr.empty = 0;
#if (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
if ((unsigned int)data_block >= SOC_EXTRAM_DATA_LOW && (unsigned int)data_block <= SOC_EXTRAM_DATA_HIGH) {
if (esp_ptr_external_ram(input) || esp_ptr_external_ram(buf)) {
Cache_WriteBack_All();
}
#endif
/* DMA cannot access memory in the iCache range, copy data to temporary buffers before transfer */
if (!esp_ptr_dma_ext_capable(input) && !esp_ptr_dma_capable(input)) {
non_icache_input = malloc(sizeof(unsigned char) * MIN(ilen, SHA_DMA_MAX_BYTES));
if (non_icache_input == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory");
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
}
if (!esp_ptr_dma_ext_capable(buf) && !esp_ptr_dma_capable(buf)) {
non_icache_buf = malloc(sizeof(unsigned char) * buf_len);
if (non_icache_buf == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory");
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
memcpy(non_icache_buf, buf, buf_len);
buf = non_icache_buf;
}
/* The max amount of blocks in a single hardware operation is 2^6 - 1 = 63
Thus we only do a single DMA input list + dma buf list,
which is max 3968/64 + 64/64 = 63 blocks */
for (int i = 0; i < dma_op_num; i++) {
int dma_chunk_len = MIN(ilen, SHA_DMA_MAX_BYTES);
/* Input depends on if it's a temp alloc buffer or supplied by user */
if (non_icache_input != NULL) {
memcpy(non_icache_input, input, dma_chunk_len);
dma_input = non_icache_input;
} else {
dma_input = input;
}
ret = esp_sha_dma_process(sha_type, dma_input, dma_chunk_len, buf, buf_len, is_first_block);
if (ret != 0) {
return ret;
}
is_first_block = false;
ilen -= dma_chunk_len;
input += dma_chunk_len;
// Only append buf to the first operation
buf_len = 0;
}
cleanup:
free(non_icache_input);
free(non_icache_buf);
return ret;
}
static void esp_sha_dma_init(lldesc_t *input)
{
/* Reset DMA */
SET_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST);
CLEAR_PERI_REG_MASK(CRYPTO_DMA_CONF0_REG, CONF0_REG_AHBM_RST | CONF0_REG_OUT_RST | CONF0_REG_AHBM_FIFO_RST);
/* Set descriptors */
CLEAR_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_ADDR);
SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, ((uint32_t)(&dma_descr))&OUT_LINK_REG_OUTLINK_ADDR);
SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, ((uint32_t)(input))&OUT_LINK_REG_OUTLINK_ADDR);
/* Start transfer */
SET_PERI_REG_MASK(CRYPTO_DMA_OUT_LINK_REG, OUT_LINK_REG_OUTLINK_START);
}
#if defined (CONFIG_MBEDTLS_SHA_USE_INTERRUPT)
REG_WRITE(SHA_CLEAR_IRQ_REG, 1);
if (op_complete_sem == NULL) {
op_complete_sem = xSemaphoreCreateBinary();
esp_intr_alloc(ETS_SHA_INTR_SOURCE, 0, esp_sha_dma_isr, 0, 0);
/* Performs SHA on multiple blocks at a time */
static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen,
const void *buf, uint32_t buf_len, bool is_first_block)
{
size_t blk_len = 0;
int ret = 0;
lldesc_t dma_descr_input = {};
lldesc_t dma_descr_buf = {};
lldesc_t *dma_descr_head;
blk_len = block_length(sha_type);
REG_WRITE(SHA_MODE_REG, sha_type);
REG_WRITE(SHA_BLOCK_NUM_REG, ((ilen + buf_len) / blk_len));
/* DMA descriptor for Memory to DMA-SHA transfer */
if (ilen) {
dma_descr_input.length = ilen;
dma_descr_input.size = ilen;
dma_descr_input.owner = 1;
dma_descr_input.eof = 1;
dma_descr_input.buf = input;
dma_descr_head = &dma_descr_input;
}
/* Check after input to overide head if there is any buf*/
if (buf_len) {
dma_descr_buf.length = buf_len;
dma_descr_buf.size = buf_len;
dma_descr_buf.owner = 1;
dma_descr_buf.eof = 1;
dma_descr_buf.buf = buf;
dma_descr_head = &dma_descr_buf;
}
REG_WRITE(SHA_INT_ENA_REG, 1);
#endif
/* Link DMA lists */
if (buf_len && ilen) {
dma_descr_buf.eof = 0;
dma_descr_buf.empty = (uint32_t)(&dma_descr_input);
}
esp_sha_dma_init(dma_descr_head);
/* Start hashing */
if (is_first_block) {
REG_WRITE(SHA_DMA_START_REG, 1);
} else {
REG_WRITE(SHA_DMA_CONTINUE_REG, 1);
}
ret = esp_sha_dma_complete();
#if (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC)
if ((unsigned int)data_block >= SOC_EXTRAM_DATA_LOW && (unsigned int)data_block <= SOC_EXTRAM_DATA_HIGH) {
Cache_Invalidate_DCache_All();
}
#endif
esp_sha_wait_idle();
return ret;
}
void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, unsigned char *output)
{
SHA_CTX ctx;
esp_sha_lock_engine(sha_type);
ets_sha_init(&ctx, sha_type);
ets_sha_starts(&ctx, 0);
ets_sha_update(&ctx, input, ilen, false);
ets_sha_finish(&ctx, output);
esp_sha_unlock_engine(sha_type);
}

View file

@ -0,0 +1,288 @@
/**
* \brief AES block cipher, ESP32-S2 hardware accelerated version
* Based on mbedTLS FIPS-197 compliant version.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
*/
/*
* The AES block cipher was designed by Vincent Rijmen and Joan Daemen.
*
* http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/
/* 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.
*/
#include <stdio.h>
#include <string.h>
#include <sys/lock.h>
#include "mbedtls/aes.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/aes.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/aes.h"
#endif
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( esp_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( esp_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
/*
* 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( esp_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 );
}

View file

@ -26,7 +26,6 @@
#include <mbedtls/sha512.h>
#if CONFIG_IDF_TARGET_ESP32
void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, unsigned char *output)
{
int ret;
@ -83,4 +82,3 @@ void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, uns
}
}
#endif

View file

@ -3,7 +3,7 @@
* Based on mbedTLS FIPS-197 compliant version.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd
* Additions Copyright (C) 2016-20, Espressif Systems (Shanghai) PTE Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -38,6 +38,7 @@ extern "C" {
#define ERR_ESP_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define ERR_ESP_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
/**
* \brief AES context structure
*
@ -52,11 +53,11 @@ typedef struct {
uint8_t key[32];
} esp_aes_context;
/**
* \brief The AES XTS context-type definition.
*/
typedef struct
{
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
@ -312,8 +313,8 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx,
* \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 );
const unsigned char *key,
unsigned int keybits );
/**
* \brief Internal AES block encryption function
@ -325,8 +326,8 @@ int esp_aes_xts_setkey_enc( esp_aes_xts_context *ctx,
* \param output Output (ciphertext) block
*/
int esp_aes_xts_setkey_dec( esp_aes_xts_context *ctx,
const unsigned char *key,
unsigned int keybits );
const unsigned char *key,
unsigned int keybits );
/**

View file

@ -31,8 +31,8 @@ extern "C" {
/* Since crypto DMA is shared between DMA-AES and SHA blocks
* Needs to be taken by respective blocks before using Crypto DMA
*/
extern portMUX_TYPE crypto_dma_spinlock;
extern _lock_t crypto_dma_lock;
#ifdef __cplusplus
}
#endif

View file

@ -3,7 +3,7 @@
* Based on mbedTLS FIPS-197 compliant version.
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd
* Additions Copyright (C) 2019-2020, Espressif Systems (Shanghai) PTE Ltd
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -30,27 +30,39 @@
extern "C" {
#endif
#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */
#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function.*/
#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */
#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function.*/
typedef enum {
ESP_AES_GCM_STATE_INIT,
ESP_AES_GCM_STATE_UPDATE,
ESP_AES_GCM_STATE_FINISH
} esp_aes_gcm_state;
/**
* \brief The GCM context structure.
*/
typedef struct {
uint8_t H[16]; /*!< H */
uint8_t S[16];
uint8_t J0[16];
uint8_t ori_j0[16];
const uint8_t *iv;
size_t iv_len; /*!< The length of IV. */
uint64_t aad_len; /*!< The total length of the additional data. */
uint64_t aad_len; /*!< The total length of the additional data. */
size_t data_len;
int mode;
const unsigned char *aad; /*!< The additional data. */
esp_aes_context aes_ctx;
}
esp_aes_gcm_context;
esp_aes_context aes_ctx;
esp_aes_gcm_state gcm_state;
} esp_gcm_context;
/**
* \brief This function initializes the specified GCM context
*
* \param ctx The GCM context to initialize.
*/
void esp_aes_gcm_init( esp_aes_gcm_context *ctx);
void esp_aes_gcm_init( esp_gcm_context *ctx);
/**
* \brief This function associates a GCM context with a
@ -67,7 +79,7 @@ void esp_aes_gcm_init( esp_aes_gcm_context *ctx);
* \return \c 0 on success.
* \return A cipher-specific error code on failure.
*/
int esp_aes_gcm_setkey( esp_aes_gcm_context *ctx,
int esp_aes_gcm_setkey( esp_gcm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits );
@ -88,12 +100,12 @@ int esp_aes_gcm_setkey( esp_aes_gcm_context *ctx,
*
* \return \c 0 on success.
*/
int esp_aes_gcm_starts( esp_aes_gcm_context *ctx,
int mode,
const unsigned char *iv,
size_t iv_len,
const unsigned char *aad,
size_t aad_len );
int esp_aes_gcm_starts( esp_gcm_context *ctx,
int mode,
const unsigned char *iv,
size_t iv_len,
const unsigned char *aad,
size_t aad_len );
/**
* \brief This function feeds an input buffer into an ongoing GCM
@ -116,7 +128,7 @@ int esp_aes_gcm_starts( esp_aes_gcm_context *ctx,
* \return \c 0 on success.
* \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure.
*/
int esp_aes_gcm_update( esp_aes_gcm_context *ctx,
int esp_aes_gcm_update( esp_gcm_context *ctx,
size_t length,
const unsigned char *input,
unsigned char *output );
@ -135,16 +147,16 @@ int esp_aes_gcm_update( esp_aes_gcm_context *ctx,
* \return \c 0 on success.
* \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure.
*/
int esp_aes_gcm_finish( esp_aes_gcm_context *ctx,
unsigned char *tag,
size_t tag_len );
int esp_aes_gcm_finish( esp_gcm_context *ctx,
unsigned char *tag,
size_t tag_len );
/**
* \brief This function clears a GCM context
*
* \param ctx The GCM context to clear.
*/
void esp_aes_gcm_free( esp_aes_gcm_context *ctx);
void esp_aes_gcm_free( esp_gcm_context *ctx);
/**
* \brief This function performs GCM encryption or decryption of a buffer.
@ -170,17 +182,17 @@ void esp_aes_gcm_free( esp_aes_gcm_context *ctx);
*
* \return \c 0 on success.
*/
int esp_aes_gcm_crypt_and_tag( esp_aes_gcm_context *ctx,
int mode,
size_t length,
const unsigned char *iv,
size_t iv_len,
const unsigned char *add,
size_t add_len,
const unsigned char *input,
unsigned char *output,
size_t tag_len,
unsigned char *tag );
int esp_aes_gcm_crypt_and_tag( esp_gcm_context *ctx,
int mode,
size_t length,
const unsigned char *iv,
size_t iv_len,
const unsigned char *add,
size_t add_len,
const unsigned char *input,
unsigned char *output,
size_t tag_len,
unsigned char *tag );
/**
@ -206,16 +218,16 @@ int esp_aes_gcm_crypt_and_tag( esp_aes_gcm_context *ctx,
* \return 0 if successful and authenticated.
* \return #MBEDTLS_ERR_GCM_AUTH_FAILED if the tag does not match.
*/
int esp_aes_gcm_auth_decrypt( esp_aes_gcm_context *ctx,
size_t length,
const unsigned char *iv,
size_t iv_len,
const unsigned char *add,
size_t add_len,
const unsigned char *tag,
size_t tag_len,
const unsigned char *input,
unsigned char *output );
int esp_aes_gcm_auth_decrypt( esp_gcm_context *ctx,
size_t length,
const unsigned char *iv,
size_t iv_len,
const unsigned char *add,
size_t add_len,
const unsigned char *tag,
size_t tag_len,
const unsigned char *input,
unsigned char *output );
#ifdef __cplusplus
}

View file

@ -1,4 +1,4 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// Copyright 2019-2020 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.
@ -16,9 +16,8 @@
#define _ESP_SHA_H_
#include "esp32s2/rom/sha.h"
#include "esp_types.h"
/** @brief Low-level support functions for the hardware SHA engine
/** @brief Low-level support functions for the hardware SHA engine using DMA
*
* @note If you're looking for a SHA API to use, try mbedtls component
* mbedtls/shaXX.h. That API supports hardware acceleration.
@ -28,15 +27,8 @@
*
* Some technical details about the hardware SHA engine:
*
* - SHA accelerator engine calculates one digest at a time, per SHA
* algorithm type. It initialises and maintains the digest state
* internally. It is possible to read out an in-progress SHA digest
* state, but it is not possible to restore a SHA digest state
* into the engine.
*
* - The memory block SHA_TEXT_BASE is shared between all SHA digest
* engines, so all engines must be idle before this memory block is
* modified.
* - The crypto DMA is shared between the SHA and AES engine, it is not
* possible for them to run calcalutions in parallel.
*
*/
@ -50,17 +42,11 @@ typedef SHA_TYPE esp_sha_type;
/** @brief Calculate SHA1 or SHA2 sum of some data, using hardware SHA engine
*
* @note For more versatile SHA calculations, where data doesn't need
* to be passed all at once, try the mbedTLS mbedtls/shaX.h APIs. The
* hardware-accelerated mbedTLS implementation is also faster when
* hashing large amounts of data.
* to be passed all at once, try the mbedTLS mbedtls/shaX.h APIs.
*
* @note It is not necessary to lock any SHA hardware before calling
* this function, thread safety is managed internally.
*
* @note If a TLS connection is open then this function may block
* indefinitely waiting for a SHA engine to become available. Use the
* mbedTLS SHA API to avoid this problem.
*
* @param sha_type SHA algorithm to use.
*
* @param input Input data buffer.
@ -73,157 +59,106 @@ typedef SHA_TYPE esp_sha_type;
*/
void esp_sha(esp_sha_type sha_type, const unsigned char *input, size_t ilen, unsigned char *output);
/* @brief Begin to execute a single SHA block operation
/** @brief Execute SHA block operation using DMA
*
* @note This is a piece of a SHA algorithm, rather than an entire SHA
* algorithm.
*
* @note Call esp_sha_try_lock_engine() before calling this
* function. Do not call esp_sha_lock_memory_block() beforehand, this
* is done inside the function.
* @note Call esp_sha_aquire_hardware() before calling this
* function.
*
* @param sha_type SHA algorithm to use.
*
* @param data_block Pointer to block of data. Block size is
* determined by algorithm (SHA1/SHA2_256 = 64 bytes,
* SHA2_384/SHA2_512 = 128 bytes)
*
* @param is_first_block If this parameter is true, the SHA state will
* be initialised (with the initial state of the given SHA algorithm)
* before the block is calculated. If false, the existing state of the
* SHA engine will be used.
*
* @return As a performance optimisation, this function returns before
* the SHA block operation is complete. Both this function and
* esp_sha_read_state() will automatically wait for any previous
* operation to complete before they begin. If using the SHA registers
* directly in another way, call esp_sha_wait_idle() after calling this
* function but before accessing the SHA registers.
*/
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block);
/* @brief Begin to execute SHA block operation using DMA
*
* @note This is a piece of a SHA algorithm, rather than an entire SHA
* algorithm.
*
* @note Call esp_sha_try_lock_engine() before calling this
* function. Do not call esp_sha_lock_memory_block() beforehand, this
* is done inside the function.
*
* @param sha_type SHA algorithm to use.
*
* @param data_block Pointer to block of data. Block size is
* @param input Pointer to the input data. Block size is
* determined by algorithm (SHA1/SHA2_256 = 64 bytes,
* SHA2_384/SHA2_512 = 128 bytes)
*
* @param ilen length of input data should be multiple of block length.
*
* @param buf Pointer to blocks of data that will be prepended
* to data_block before hashing. Useful when there is two sources of
* data that need to be efficiently calculated in a single SHA DMA
* operation.
*
* @param buf_len length of buf data should be multiple of block length.
* Should not be longer than the maximum amount of bytes in a single block
* (128 bytes)
*
* @param is_first_block If this parameter is true, the SHA state will
* be initialised (with the initial state of the given SHA algorithm)
* before the block is calculated. If false, the existing state of the
* SHA engine will be used.
*
* @param t The number of bits for the SHA512/t hash function, with
* output truncated to t bits. Used for calculating the inital hash.
* t is any positive integer between 1 and 512, except 384.
*
* @return 0 if successful
*/
int esp_sha_dma(esp_sha_type sha_type, const void *data_block, uint32_t ilen, bool is_first_block);
int esp_sha_dma(esp_sha_type sha_type, const void *input, uint32_t ilen,
const void *buf, uint32_t buf_len, bool is_first_block);
/** @brief Read out the current state of the SHA digest loaded in the engine.
/**
* @brief Read out the current state of the SHA digest
*
* @note This is a piece of a SHA algorithm, rather than an entire SHA algorithm.
*
* @note Call esp_sha_try_lock_engine() before calling this
* function. Do not call esp_sha_lock_memory_block() beforehand, this
* is done inside the function.
* @note Call esp_sha_aquire_hardware() before calling this
* function.
*
* If the SHA suffix padding block has been executed already, the
* value that is read is the SHA digest (in big endian
* format). Otherwise, the value that is read is an interim SHA state.
*
* @note If sha_type is SHA2_384, only 48 bytes of state will be read.
* This is enough for the final SHA2_384 digest, but if you want the
* interim SHA-384 state (to continue digesting) then pass SHA2_512 instead.
* value that is read is the SHA digest.
* Otherwise, the value that is read is an interim SHA state.
*
* @param sha_type SHA algorithm in use.
*
* @param state Pointer to a memory buffer to hold the SHA state. Size
* is 20 bytes (SHA1), 32 bytes (SHA2_256), 48 bytes (SHA2_384) or 64 bytes (SHA2_512).
*
* @param digest_state Pointer to a memory buffer to hold the SHA state. Size
* is 20 bytes (SHA1), 32 bytes (SHA2_256), or 64 bytes (SHA2_384, SHA2_512).
*/
void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state);
/**
* @brief Obtain exclusive access to a particular SHA engine
* @brief Set the current state of the SHA digest
*
* @param sha_type Type of SHA engine to use.
* @note Call esp_sha_aquire_hardware() before calling this
* function.
*
* Blocks until engine is available. Note: Can block indefinitely
* while a TLS connection is open, suggest using
* esp_sha_try_lock_engine() and failing over to software SHA.
* When resuming a
*
* @param sha_type SHA algorithm in use.
* @param digest_state
*/
void esp_sha_lock_engine(esp_sha_type sha_type);
void esp_sha_write_digest_state(esp_sha_type sha_type, void *digest_state);
/**
* @brief Try and obtain exclusive access to a particular SHA engine
*
* @param sha_type Type of SHA engine to use.
*
* @return Returns true if the SHA engine is locked for exclusive
* use. Call esp_sha_unlock_sha_engine() when done. Returns false if
* the SHA engine is already in use, caller should use software SHA
* algorithm for this digest.
* @brief Enables the SHA and crypto DMA peripheral and takes the
* locks for both of them.
*/
bool esp_sha_try_lock_engine(esp_sha_type sha_type);
void esp_sha_acquire_hardware(void);
/**
* @brief Unlock an engine previously locked with esp_sha_lock_engine() or esp_sha_try_lock_engine()
*
* @param sha_type Type of engine to release.
* @brief Disables the SHA and crypto DMA peripheral and releases the
* locks.
*/
void esp_sha_unlock_engine(esp_sha_type sha_type);
void esp_sha_release_hardware(void);
/*
*/
/**
* @brief Acquire exclusive access to the SHA shared memory block at SHA_TEXT_BASE
* @brief Sets the initial hash value for SHA512/t.
*
* This memory block is shared across all the SHA algorithm types.
* @note Is generated according to the algorithm described in the TRM,
* chapter SHA-Accelerator
*
* Caller should have already locked a SHA engine before calling this function.
* @note The engine must be locked until the value is used for an operation
* or read out. Else you risk another operation overwriting it.
*
* Note that it is possible to obtain exclusive access to the memory block even
* while it is in use by the SHA engine. Caller should use esp_sha_wait_idle()
* to ensure the SHA engine is not reading from the memory block in hardware.
* @param t
*
* @note You do not need to lock the memory block before calling esp_sha_block() or esp_sha_read_digest_state(), these functions handle memory block locking internally.
*
* Call esp_sha_unlock_memory_block() when done.
* @return 0 if successful
*/
void esp_sha_lock_memory_block(void);
/**
* @brief Release exclusive access to the SHA register memory block at SHA_TEXT_BASE
*
* Caller should have already locked a SHA engine before calling this function.
*
* Call following esp_sha_lock_memory_block().
*/
void esp_sha_unlock_memory_block(void);
/** @brief Wait for the SHA engine to finish any current operation
*
* @note This function does not ensure exclusive access to any SHA
* engine. Caller should use esp_sha_try_lock_engine() and
* esp_sha_lock_memory_block() as required.
*
* @note Functions declared in this header file wait for SHA engine
* completion automatically, so you don't need to use this API for
* these. However if accessing SHA registers directly, you will need
* to call this before accessing SHA registers if using the
* esp_sha_block() function.
*
* @note This function busy-waits, so wastes CPU resources.
* Best to delay calling until you are about to need it.
*
*/
void esp_sha_wait_idle(void);
int esp_sha_512_t_init_hash(uint16_t t);
#ifdef __cplusplus
}

View file

@ -0,0 +1,55 @@
/**
* \file gcm_alt.h
*
* \brief AES block cipher
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
*
*/
#ifndef GCM_ALT_H
#define GCM_ALT_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MBEDTLS_GCM_ALT)
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/gcm.h"
typedef esp_gcm_context mbedtls_gcm_context;
#define mbedtls_gcm_init esp_aes_gcm_init
#define mbedtls_gcm_free esp_aes_gcm_free
#define mbedtls_gcm_setkey esp_aes_gcm_setkey
#define mbedtls_gcm_starts esp_aes_gcm_starts
#define mbedtls_gcm_update esp_aes_gcm_update
#define mbedtls_gcm_finish esp_aes_gcm_finish
#define mbedtls_gcm_auth_decrypt esp_aes_gcm_auth_decrypt
#define mbedtls_gcm_crypt_and_tag esp_aes_gcm_crypt_and_tag
#endif // CONFIG_IDF_TARGET_ESP32S2
#endif /* MBEDTLS_GCM_ALT */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -118,6 +118,12 @@
#undef MBEDTLS_AES_ALT
#endif
#ifdef CONFIG_MBEDTLS_HARDWARE_GCM
#define MBEDTLS_GCM_ALT
#else
#undef MBEDTLS_GCM_ALT
#endif
/* MBEDTLS_SHAxx_ALT to enable hardware SHA support
with software fallback.
*/

View file

@ -29,6 +29,30 @@ extern "C" {
#if defined(MBEDTLS_SHA1_ALT)
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/sha.h"
typedef enum {
ESP_SHA1_STATE_INIT,
ESP_SHA1_STATE_IN_PROCESS
} esp_sha1_state;
/**
* \brief SHA-1 context structure
*/
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[5]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
int first_block; /*!< if first then true else false */
esp_sha_type mode;
esp_sha1_state sha_state;
} mbedtls_sha1_context;
#endif //CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32
typedef enum {
ESP_MBEDTLS_SHA1_UNUSED, /* first block hasn't been processed yet */
ESP_MBEDTLS_SHA1_HARDWARE, /* using hardware SHA engine */
@ -38,8 +62,7 @@ typedef enum {
/**
* \brief SHA-1 context structure
*/
typedef struct
{
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[5]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
@ -47,6 +70,8 @@ typedef struct
}
mbedtls_sha1_context;
#endif //CONFIG_IDF_TARGET_ESP32
#endif
#ifdef __cplusplus

View file

@ -29,6 +29,33 @@ extern "C" {
#if defined(MBEDTLS_SHA256_ALT)
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/sha.h"
typedef enum {
ESP_SHA256_STATE_INIT,
ESP_SHA256_STATE_IN_PROCESS
} esp_sha256_state;
/**
* \brief SHA-256 context structure
*/
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[8]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
int first_block; /*!< if first then true, else false */
esp_sha_type mode;
esp_sha256_state sha_state;
}
mbedtls_sha256_context;
#endif //CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32
typedef enum {
ESP_MBEDTLS_SHA256_UNUSED, /* first block hasn't been processed yet */
ESP_MBEDTLS_SHA256_HARDWARE, /* using hardware SHA engine */
@ -38,8 +65,7 @@ typedef enum {
/**
* \brief SHA-256 context structure
*/
typedef struct
{
typedef struct {
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[8]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
@ -48,6 +74,8 @@ typedef struct
}
mbedtls_sha256_context;
#endif //CONFIG_IDF_TARGET_ESP32
#endif
#ifdef __cplusplus

View file

@ -23,12 +23,51 @@
#ifndef _SHA512_ALT_H_
#define _SHA512_ALT_H_
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MBEDTLS_SHA512_ALT)
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/sha.h"
typedef enum {
ESP_SHA512_STATE_INIT,
ESP_SHA512_STATE_IN_PROCESS
} esp_sha512_state;
/**
* \brief SHA-512 context structure
*/
typedef struct {
uint64_t total[2]; /*!< number of bytes processed */
uint64_t state[8]; /*!< intermediate digest state */
unsigned char buffer[128]; /*!< data block being processed */
int first_block;
esp_sha_type mode;
uint32_t t_val; /*!< t_val for 512/t mode */
esp_sha512_state sha_state;
} mbedtls_sha512_context;
/**
* @brief Sets the specfic algorithm for SHA512
*
* @param ctx The mbedtls sha512 context
*
* @param type The mode, used for setting SHA2_512224 and SHA2_512256:
*
*/
void esp_sha512_set_mode(mbedtls_sha512_context *ctx, esp_sha_type type);
/* For SHA512/t mode the intial hash value will depend on t */
void esp_sha512_set_t( mbedtls_sha512_context *ctx, uint16_t t_val);
#endif //CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32
typedef enum {
ESP_MBEDTLS_SHA512_UNUSED, /* first block hasn't been processed yet */
ESP_MBEDTLS_SHA512_HARDWARE, /* using hardware SHA engine */
@ -38,8 +77,7 @@ typedef enum {
/**
* \brief SHA-512 context structure
*/
typedef struct
{
typedef struct {
uint64_t total[2]; /*!< number of bytes processed */
uint64_t state[8]; /*!< intermediate digest state */
unsigned char buffer[128]; /*!< data block being processed */
@ -48,6 +86,8 @@ typedef struct
}
mbedtls_sha512_context;
#endif //CONFIG_IDF_TARGET_ESP32
#endif
#ifdef __cplusplus

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
#include <stdbool.h>
#include <esp_system.h>
#include "mbedtls/aes.h"
#include "mbedtls/gcm.h"
#include "unity.h"
#include "sdkconfig.h"
#include "esp_timer.h"
@ -14,7 +15,7 @@
TEST_CASE("mbedtls AES performance", "[aes]")
{
const unsigned CALLS = 256;
const unsigned CALL_SZ = 32*1024;
const unsigned CALL_SZ = 32 * 1024;
mbedtls_aes_context ctx;
int64_t start, end;
uint8_t iv[16];
@ -24,7 +25,7 @@ TEST_CASE("mbedtls AES performance", "[aes]")
memset(key, 0x44, 16);
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buf);
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 128);
@ -63,9 +64,65 @@ TEST_CASE("mbedtls AES performance", "[aes]")
float mb_sec = (CALL_SZ * CALLS) / usecs;
printf("Encryption rate %.3fMB/sec\n", mb_sec);
#ifdef CONFIG_MBEDTLS_HARDWARE_AES
// Don't put a hard limit on software AES performance (software is approx 2.3MB/sec on Release config)
// Don't put a hard limit on software AES performance
TEST_PERFORMANCE_GREATER_THAN(AES_CBC_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec);
#endif
}
TEST_CASE("mbedtls AES GCM performance", "[aes]")
{
const unsigned CALLS = 1;
const unsigned CALL_SZ = 32 * 1024;
mbedtls_gcm_context ctx;
int64_t start, end;
unsigned char tag_buf[16];
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
uint8_t iv[16];
uint8_t key[16];
memset(iv, 0xEE, 16);
memset(key, 0x44, 16);
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buf);
mbedtls_gcm_init(&ctx);
mbedtls_gcm_setkey( &ctx, cipher, key, 128);
start = esp_timer_get_time();
for (int c = 0; c < CALLS; c++) {
memset(buf, 0xAA, CALL_SZ);
mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_AES_ENCRYPT, CALL_SZ, iv, sizeof(iv), NULL, 0, buf, buf, 16, tag_buf);
}
end = esp_timer_get_time();
/* Sanity check: make sure the last ciphertext block matches
what we expect to see.
Last block produced via this Python:
import os, binascii
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
key = b'\x44' * 16
iv = b'\xee' * 16
cipher = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend())
encryptor = cipher.encryptor()
ct = encryptor.update(b'\xaa' * 1 * 32 * 1024) + encryptor.finalize()
print(binascii.hexlify(ct[-16:]))
*/
const uint8_t expected_last_block[] = {
0x7d, 0x3d, 0x16, 0x84, 0xd0, 0xb4, 0x38, 0x30,
0xd1, 0x24, 0x6f, 0x7e, 0x9a, 0x9c, 0x81, 0x58,
};
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16, 16);
free(buf);
float usecs = end - start;
// bytes/usec = MB/sec
float mb_sec = (CALL_SZ * CALLS) / usecs;
printf("GCM encryption rate %.3fMB/sec\n", mb_sec);
}

View file

@ -14,6 +14,7 @@
#include "unity.h"
#include "sdkconfig.h"
#include "test_apb_dport_access.h"
#include "sodium/utils.h"
TEST_CASE("mbedtls SHA self-tests", "[mbedtls]")
{
@ -21,19 +22,19 @@ TEST_CASE("mbedtls SHA self-tests", "[mbedtls]")
TEST_ASSERT_FALSE_MESSAGE(mbedtls_sha1_self_test(1), "SHA1 self-tests should pass.");
TEST_ASSERT_FALSE_MESSAGE(mbedtls_sha256_self_test(1), "SHA256 self-tests should pass.");
TEST_ASSERT_FALSE_MESSAGE(mbedtls_sha512_self_test(1), "SHA512 self-tests should pass.");
TEST_ASSERT_FALSE_MESSAGE(mbedtls_sha512_self_test(1), "SHA512 self-tests should pass.");
verify_apb_access_loop();
}
static const unsigned char *one_hundred_as = (unsigned char *)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
static const unsigned char *one_hundred_bs = (unsigned char *)
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
static const uint8_t sha256_thousand_as[32] = {
0x41, 0xed, 0xec, 0xe4, 0x2d, 0x63, 0xe8, 0xd9, 0xbf, 0x51, 0x5a, 0x9b, 0xa6, 0x93, 0x2e, 0x1c,
0x20, 0xcb, 0xc9, 0xf5, 0xa5, 0xd1, 0x34, 0x64, 0x5a, 0xdb, 0x5d, 0xb1, 0xb9, 0x73, 0x7e, 0xa3 };
0x20, 0xcb, 0xc9, 0xf5, 0xa5, 0xd1, 0x34, 0x64, 0x5a, 0xdb, 0x5d, 0xb1, 0xb9, 0x73, 0x7e, 0xa3
};
static const uint8_t sha256_thousand_bs[32] = {
0xf6, 0xf1, 0x18, 0xe1, 0x20, 0xe5, 0x2b, 0xe0, 0xbd, 0x0c, 0xfd, 0xf2, 0x79, 0x4c, 0xd1, 0x2c, 0x07, 0x68, 0x6c, 0xc8, 0x71, 0x23, 0x5a, 0xc2, 0xf1, 0x14, 0x59, 0x37, 0x8e, 0x6d, 0x23, 0x5b
@ -49,7 +50,9 @@ static const uint8_t sha384_thousand_bs[48] = {
static const uint8_t sha1_thousand_as[20] = {
0x29, 0x1e, 0x9a, 0x6c, 0x66, 0x99, 0x49, 0x49, 0xb5, 0x7b, 0xa5,
0xe6, 0x50, 0x36, 0x1e, 0x98, 0xfc, 0x36, 0xb1, 0xba };
0xe6, 0x50, 0x36, 0x1e, 0x98, 0xfc, 0x36, 0xb1, 0xba
};
TEST_CASE("mbedtls SHA interleaving", "[mbedtls]")
{
@ -129,8 +132,8 @@ TEST_CASE("mbedtls SHA multithreading", "[mbedtls]")
xTaskCreate(tskRunSHA256Test, "SHA256Task1", SHA_TASK_STACK_SIZE, NULL, 3, NULL);
xTaskCreate(tskRunSHA256Test, "SHA256Task2", SHA_TASK_STACK_SIZE, NULL, 3, NULL);
for(int i = 0; i < 4; i++) {
if(!xSemaphoreTake(done_sem, 10000/portTICK_PERIOD_MS)) {
for (int i = 0; i < 4; i++) {
if (!xSemaphoreTake(done_sem, 10000 / portTICK_PERIOD_MS)) {
TEST_FAIL_MESSAGE("done_sem not released by test task");
}
}
@ -140,31 +143,30 @@ TEST_CASE("mbedtls SHA multithreading", "[mbedtls]")
void tskRunSHASelftests(void *param)
{
for (int i = 0; i < 5; i++) {
if(mbedtls_sha1_self_test(1)) {
if (mbedtls_sha1_self_test(1)) {
printf("SHA1 self-tests failed.\n");
while(1) {}
while (1) {}
}
if(mbedtls_sha256_self_test(1)) {
if (mbedtls_sha256_self_test(1)) {
printf("SHA256 self-tests failed.\n");
while(1) {}
while (1) {}
}
if(mbedtls_sha512_self_test(1)) {
if (mbedtls_sha512_self_test(1)) {
printf("SHA512 self-tests failed.\n");
while(1) {}
while (1) {}
}
if(mbedtls_sha512_self_test(1)) {
if (mbedtls_sha512_self_test(1)) {
printf("SHA512 self-tests failed.\n");
while(1) {}
while (1) {}
}
}
xSemaphoreGive(done_sem);
vTaskDelete(NULL);
}
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
TEST_CASE("mbedtls SHA self-tests multithreaded", "[mbedtls]")
{
done_sem = xSemaphoreCreateCounting(2, 0);
@ -173,14 +175,13 @@ TEST_CASE("mbedtls SHA self-tests multithreaded", "[mbedtls]")
const int TIMEOUT_MS = 40000;
for(int i = 0; i < 2; i++) {
if(!xSemaphoreTake(done_sem, TIMEOUT_MS/portTICK_PERIOD_MS)) {
for (int i = 0; i < 2; i++) {
if (!xSemaphoreTake(done_sem, TIMEOUT_MS / portTICK_PERIOD_MS)) {
TEST_FAIL_MESSAGE("done_sem not released by test task");
}
}
vSemaphoreDelete(done_sem);
}
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
TEST_CASE("mbedtls SHA512 clone", "[mbedtls]")
{
@ -207,10 +208,11 @@ TEST_CASE("mbedtls SHA512 clone", "[mbedtls]")
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_thousand_bs, sha512, 64, "SHA512 cloned calculation");
}
TEST_CASE("mbedtls SHA384 clone", "[mbedtls]")
TEST_CASE("mbedtls SHA384 clone", "[mbedtls][")
{
mbedtls_sha512_context ctx;
mbedtls_sha512_context clone;
unsigned char sha384[48];
mbedtls_sha512_init(&ctx);
@ -220,12 +222,12 @@ TEST_CASE("mbedtls SHA384 clone", "[mbedtls]")
}
mbedtls_sha512_clone(&clone, &ctx);
for (int i = 0; i < 5; i++) {
TEST_ASSERT_EQUAL(0, mbedtls_sha512_update_ret(&ctx, one_hundred_bs, 100));
TEST_ASSERT_EQUAL(0, mbedtls_sha512_update_ret(&clone, one_hundred_bs, 100));
}
TEST_ASSERT_EQUAL(0, mbedtls_sha512_finish_ret(&ctx, sha384));
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha384_thousand_bs, sha384, 48, "SHA512 original calculation");
TEST_ASSERT_EQUAL(0, mbedtls_sha512_finish_ret(&clone, sha384));
@ -258,7 +260,6 @@ TEST_CASE("mbedtls SHA256 clone", "[mbedtls]")
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, sha256, 32, "SHA256 cloned calculation");
}
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2)
typedef struct {
mbedtls_sha256_context ctx;
uint8_t result[32];
@ -279,8 +280,8 @@ static void tskFinaliseSha(void *v_param)
vTaskDelete(NULL);
}
// No concurrent SHA sessions in esp32s2, only has one engine
TEST_CASE("mbedtls SHA session passed between tasks" , "[mbedtls]")
TEST_CASE("mbedtls SHA session passed between tasks", "[mbedtls]")
{
finalise_sha_param_t param = { 0 };
@ -303,4 +304,130 @@ TEST_CASE("mbedtls SHA session passed between tasks" , "[mbedtls]")
TEST_ASSERT_EQUAL(0, param.ret);
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha256_thousand_as, param.result, 32, "SHA256 result from other task");
}
#endif
/* ESP32 do not have SHA512/t functions */
#if !DISABLED_FOR_TARGETS(ESP32)
/* Function are not implemented in SW */
#ifdef CONFIG_MBEDTLS_HARDWARE_SHA
/*
* FIPS-180-2 test vectors
*/
static unsigned char sha512T_test_buf[2][113] = {
{ "abc" },
{
"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
}
};
static const size_t sha512T_test_buflen[2] = {
3, 112
};
static const esp_sha_type sha512T_algo[4] = {
SHA2_512224, SHA2_512256, SHA2_512T, SHA2_512T
};
static const size_t sha512T_t_len[4] = { 224, 256, 224, 256 };
static const unsigned char sha512_test_sum[4][32] = {
/* SHA512-224 */
{
0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54,
0xda, 0xae, 0x75, 0x30, 0x46, 0x08, 0x42, 0xe2,
0x0e, 0x37, 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4,
0x3e, 0x89, 0x24, 0xaa
},
{
0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23,
0x30, 0x81, 0x92, 0x64, 0x0b, 0x0c, 0x45, 0x33,
0x35, 0xd6, 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72,
0x68, 0x67, 0x4a, 0xf9
},
/* SHA512-256 */
{
0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9,
0x9b, 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab,
0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46,
0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23
},
{
0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8,
0x40, 0xda, 0x39, 0x88, 0x12, 0x1d, 0x31, 0xbe,
0x65, 0xcb, 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14,
0x6f, 0xea, 0xc8, 0x61, 0xe1, 0x9b, 0x56, 0x3a
}
/* For SHA512_T testing we use t=224 & t=256
* so the hash digest should be same as above
*/
};
/* This will run total of 8 test cases, 2 for each of the below MODE
* SHA512/224, SHA512/256, SHA512/t with t=224 & SHA512/t with t=256
*
* Test is disabled for ESP32 as there is no hardware for SHA512/t
*/
TEST_CASE("mbedtls SHA512/t", "[mbedtls]")
{
mbedtls_sha512_context sha512_ctx;
unsigned char sha512[64], k;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 2; j++) {
k = i * 2 + j;
mbedtls_sha512_init(&sha512_ctx);
TEST_ASSERT_EQUAL(0, mbedtls_sha512_starts_ret(&sha512_ctx, false));
esp_sha512_set_mode(&sha512_ctx, sha512T_algo[i]);
if (i > 1) {
k = (i - 2) * 2 + j;
esp_sha512_set_t(&sha512_ctx, sha512T_t_len[i]);
}
TEST_ASSERT_EQUAL(0, mbedtls_sha512_update_ret(&sha512_ctx, sha512T_test_buf[j], sha512T_test_buflen[j]));
TEST_ASSERT_EQUAL(0, mbedtls_sha512_finish_ret(&sha512_ctx, sha512));
TEST_ASSERT_EQUAL_MEMORY_MESSAGE(sha512_test_sum[k], sha512, sha512T_t_len[i] / 8, "SHA512t calculation");
}
}
}
#ifdef CONFIG_SPIRAM
TEST_CASE("mbedtls SHA256 PSRAM DMA", "[mbedtls]")
{
const unsigned CALLS = 256;
const unsigned CALL_SZ = 16 * 1024;
mbedtls_sha256_context sha256_ctx;
unsigned char sha256[32];
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_SPIRAM);
TEST_ASSERT(esp_ptr_external_ram(buf));
memset(buf, 0x54, CALL_SZ);
mbedtls_sha256_init(&sha256_ctx);
TEST_ASSERT_EQUAL(0, mbedtls_sha256_starts_ret(&sha256_ctx, false));
for (int c = 0; c < CALLS; c++) {
TEST_ASSERT_EQUAL(0, mbedtls_sha256_update_ret(&sha256_ctx, buf, CALL_SZ));
}
TEST_ASSERT_EQUAL(0, mbedtls_sha256_finish_ret(&sha256_ctx, sha256));
free(buf);
mbedtls_sha256_free(&sha256_ctx);
/* Check the result. Reference value can be calculated using:
* dd if=/dev/zero bs=$((16*1024)) count=256 | tr '\000' '\124' | sha256sum
*/
const char *expected_hash = "8d031167bd706ac337e07aa9129c34ae4ae792d0a79a2c70e7f012102e8adc3d";
char hash_str[sizeof(sha256) * 2 + 1];
sodium_bin2hex(hash_str, sizeof(hash_str), sha256, sizeof(sha256));
TEST_ASSERT_EQUAL_STRING(expected_hash, hash_str);
}
#endif //CONFIG_SPIRAM
#endif //CONFIG_MBEDTLS_HARDWARE_SHA
#endif //!DISABLED_FOR_TARGETS(ESP32S2)

View file

@ -14,13 +14,13 @@
TEST_CASE("mbedtls SHA performance", "[aes]")
{
const unsigned CALLS = 256;
const unsigned CALL_SZ = 16*1024;
const unsigned CALL_SZ = 16 * 1024;
mbedtls_sha256_context sha256_ctx;
int64_t start, end;
unsigned char sha256[32];
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT|MALLOC_CAP_INTERNAL);
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buf);
memset(buf, 0x55, CALL_SZ);
@ -39,7 +39,7 @@ TEST_CASE("mbedtls SHA performance", "[aes]")
/* Check the result. Reference value can be calculated using:
* dd if=/dev/zero bs=$((16*1024)) count=256 | tr '\000' '\125' | sha256sum
*/
const char* expected_hash = "c88df2638fb9699abaad05780fa5e0fdb6058f477069040eac8bed3231286275";
const char *expected_hash = "c88df2638fb9699abaad05780fa5e0fdb6058f477069040eac8bed3231286275";
char hash_str[sizeof(sha256) * 2 + 1];
sodium_bin2hex(hash_str, sizeof(hash_str), sha256, sizeof(sha256));
@ -49,7 +49,7 @@ TEST_CASE("mbedtls SHA performance", "[aes]")
// bytes/usec = MB/sec
float mb_sec = (CALL_SZ * CALLS) / usecs;
printf("SHA256 rate %.3fMB/sec\n", mb_sec);
#ifdef CONFIG_MBEDTLS_HARDWARE
#ifdef CONFIG_MBEDTLS_HARDWARE_SHA
// Don't put a hard limit on software SHA performance
TEST_PERFORMANCE_GREATER_THAN(SHA256_THROUGHPUT_MBSEC, "%.3fMB/sec", mb_sec);
#endif

View file

@ -145,6 +145,15 @@ inline static bool IRAM_ATTR esp_ptr_dma_capable(const void *p)
return (intptr_t)p >= SOC_DMA_LOW && (intptr_t)p < SOC_DMA_HIGH;
}
inline static bool IRAM_ATTR esp_ptr_dma_ext_capable(const void *p)
{
#if CONFIG_IDF_TARGET_ESP32S2
return (intptr_t)p >= SOC_DMA_EXT_LOW && (intptr_t)p < SOC_DMA_EXT_HIGH;
#else
return false;
#endif
}
inline static bool IRAM_ATTR esp_ptr_word_aligned(const void *p)
{
return ((intptr_t)p) % 4 == 0;

View file

@ -69,24 +69,6 @@
#define SHA_H_BASE ((DR_REG_SHA_BASE) + 0x40)
#define SHA_TEXT_BASE ((DR_REG_SHA_BASE) + 0x80)
/* AES Block operation modes */
#define AES_BLOCK_MODE_ECB 0
#define AES_BLOCK_MODE_CBC 1
#define AES_BLOCK_MODE_OFB 2
#define AES_BLOCK_MODE_CTR 3
#define AES_BLOCK_MODE_CFB8 4
#define AES_BLOCK_MODE_CFB128 5
#define AES_BLOCK_MODE_GCM 6
/* AES Block operation modes (used with DMA) */
#define AES_BLOCK_MODE_ECB 0
#define AES_BLOCK_MODE_CBC 1
#define AES_BLOCK_MODE_OFB 2
#define AES_BLOCK_MODE_CTR 3
#define AES_BLOCK_MODE_CFB8 4
#define AES_BLOCK_MODE_CFB128 5
#define AES_BLOCK_MODE_GCM 6
/* AES acceleration registers */
#define AES_MODE_REG ((DR_REG_AES_BASE) + 0x40)
#define AES_ENDIAN_REG ((DR_REG_AES_BASE) + 0x44)

View file

@ -48,6 +48,12 @@ typedef enum {
PERIPH_WIFI_MODULE,
PERIPH_WIFI_BT_COMMON_MODULE,
PERIPH_SYSTIMER_MODULE,
PERIPH_AES_MODULE,
PERIPH_SHA_MODULE,
PERIPH_RSA_MODULE,
PERIPH_CRYPTO_DMA_MODULE, //this DMA is shared between AES and SHA
PERIPH_AES_DMA_MODULE,
PERIPH_SHA_DMA_MODULE,
} periph_module_t;
typedef enum {

View file

@ -270,10 +270,14 @@
#define SOC_DIRAM_DRAM_LOW 0x3FFB0000
#define SOC_DIRAM_DRAM_HIGH 0x40000000
// Region of memory accessible via DMA. See esp_ptr_dma_capable().
// Region of memory accessible via DMA in internal memory. See esp_ptr_dma_capable().
#define SOC_DMA_LOW 0x3FFB0000
#define SOC_DMA_HIGH 0x40000000
// Region of memory accessible via DMA in external memory. See esp_ptr_dma_ext_capable().
#define SOC_DMA_EXT_LOW 0x3F500000
#define SOC_DMA_EXT_HIGH 0x3FF80000
// Region of memory that is byte-accessible. See esp_ptr_byte_accessible().
#define SOC_BYTE_ACCESSIBLE_LOW 0x3FF9E000
#define SOC_BYTE_ACCESSIBLE_HIGH 0x40000000

View file

@ -84,6 +84,18 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return DPORT_WIFI_CLK_WIFI_BT_COMMON_M;
case PERIPH_SYSTIMER_MODULE:
return DPORT_SYSTIMER_CLK_EN;
case PERIPH_AES_MODULE:
return DPORT_CRYPTO_AES_CLK_EN;
case PERIPH_SHA_MODULE:
return DPORT_CRYPTO_SHA_CLK_EN;
case PERIPH_RSA_MODULE:
return DPORT_CRYPTO_RSA_CLK_EN;
case PERIPH_CRYPTO_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN;
case PERIPH_SHA_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_SHA_CLK_EN;
case PERIPH_AES_DMA_MODULE:
return DPORT_CRYPTO_DMA_CLK_EN | DPORT_CRYPTO_AES_CLK_EN;
default:
return 0;
}
@ -144,6 +156,49 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return DPORT_CAN_RST;
case PERIPH_SYSTIMER_MODULE:
return DPORT_SYSTIMER_RST;
case PERIPH_AES_MODULE:
if (enable == true) {
// Clear reset on digital signature, otherwise AES unit is held in reset also.
return (DPORT_CRYPTO_AES_RST | DPORT_CRYPTO_DS_RST);
} else {
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
return DPORT_CRYPTO_AES_RST;
}
case PERIPH_SHA_MODULE:
if (enable == true) {
// Clear reset on digital signature and HMAC, otherwise SHA is held in reset
return (DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DS_RST | DPORT_CRYPTO_HMAC_RST);
} else {
// Don't assert reset on secure boot, otherwise AES is held in reset
return DPORT_CRYPTO_SHA_RST;
}
case PERIPH_RSA_MODULE:
if (enable == true) {
// Also clear reset on digital signature, otherwise RSA is held in reset
return (DPORT_CRYPTO_RSA_RST | DPORT_CRYPTO_DS_RST);
} else {
// Don't reset digital signature unit, as this resets AES also
return DPORT_CRYPTO_RSA_RST;
}
case PERIPH_CRYPTO_DMA_MODULE:
return DPORT_CRYPTO_DMA_RST;
case PERIPH_AES_DMA_MODULE:
if (enable == true) {
// Clear reset on digital signature, otherwise AES unit is held in reset also.
return (DPORT_CRYPTO_AES_RST | DPORT_CRYPTO_DS_RST | DPORT_CRYPTO_DMA_RST);
} else {
//Don't return other units to reset, as this pulls reset on RSA & SHA units, respectively.
return (DPORT_CRYPTO_AES_RST | DPORT_CRYPTO_DMA_RST);
}
case PERIPH_SHA_DMA_MODULE:
if (enable == true) {
// Clear reset on digital signature and HMAC, otherwise SHA is held in reset
return (DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DS_RST | DPORT_CRYPTO_HMAC_RST | DPORT_CRYPTO_DMA_RST);
} else {
// Don't assert reset on secure boot, otherwise AES is held in reset
return (DPORT_CRYPTO_SHA_RST | DPORT_CRYPTO_DMA_RST);
}
default:
return 0;
}
@ -156,6 +211,13 @@ static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph)
case PERIPH_WIFI_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_WIFI_CLK_EN_REG;
case PERIPH_AES_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_RSA_MODULE:
case PERIPH_CRYPTO_DMA_MODULE:
case PERIPH_AES_DMA_MODULE:
case PERIPH_SHA_DMA_MODULE:
return DPORT_PERIP_CLK_EN1_REG;
default:
return DPORT_PERIP_CLK_EN_REG;
}
@ -168,6 +230,13 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
case PERIPH_WIFI_MODULE:
case PERIPH_WIFI_BT_COMMON_MODULE:
return DPORT_CORE_RST_EN_REG;
case PERIPH_AES_MODULE:
case PERIPH_SHA_MODULE:
case PERIPH_RSA_MODULE:
case PERIPH_CRYPTO_DMA_MODULE:
case PERIPH_AES_DMA_MODULE:
case PERIPH_SHA_DMA_MODULE:
return DPORT_PERIP_RST_EN1_REG;
default:
return DPORT_PERIP_RST_EN_REG;
}