mbedtls: Added ECC hardware accelerator support on ESP32C2

ESP32C2 has a ECC hardware accelerator capable of performing point
multiplication and point verification with a significant performance
boost
This commit is contained in:
Sachin Parekh 2022-01-05 22:55:28 +05:30 committed by BOT
parent bc1d35a14e
commit 32a6550e87
8 changed files with 509 additions and 0 deletions

View File

@ -182,6 +182,11 @@ if(CONFIG_MBEDTLS_HARDWARE_GCM)
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/aes/esp_aes_gcm.c")
endif()
if(CONFIG_MBEDTLS_HARDWARE_ECC)
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/ecc/esp_ecc.c"
"${COMPONENT_DIR}/port/ecc/ecc_alt.c")
endif()
if(CONFIG_MBEDTLS_ROM_MD5)
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/md/esp_md.c")
endif()

View File

@ -414,6 +414,22 @@ menu "mbedTLS"
SHA hardware acceleration is faster than software in some situations but
slower in others. You should benchmark to find the best setting for you.
config MBEDTLS_HARDWARE_ECC
bool "Enable hardware ECC acceleration"
default y
depends on SOC_ECC_SUPPORTED
help
Enable hardware accelerated ECC point multiplication and point verification for points
on curve SECP192R1 and SECP256R1 in mbedTLS
config MBEDTLS_ECC_OTHER_CURVES_SOFT_FALLBACK
bool "Fallback to software implementation for curves not supported in hardware"
depends on MBEDTLS_HARDWARE_ECC
default y
help
Fallback to software implementation of ECC point multiplication and point verification
for curves not supported in hardware.
config MBEDTLS_ROM_MD5
bool "Use MD5 implementation in ROM"
default y

View File

@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "soc/hwcrypto_periph.h"
#include "ecc_impl.h"
/* TBD: Remove this and use proper getter/setter methods to access
* private members of EC data structures once they are available
* in mbedTLS stack */
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#include "mbedtls/ecp.h"
#include "mbedtls/platform_util.h"
#define ECP_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA )
#define ECP_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#if defined(MBEDTLS_ECP_MUL_ALT) || defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK)
#define MAX_SIZE 32 // 256 bits
static int esp_mbedtls_ecp_point_multiply(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P)
{
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
uint8_t x_tmp[MAX_SIZE];
uint8_t y_tmp[MAX_SIZE];
ecc_point_t p_pt = {0};
ecc_point_t r_pt = {0};
p_pt.len = grp->pbits / 8;
memcpy(&p_pt.x, P->X.p, mbedtls_mpi_size(&P->X));
memcpy(&p_pt.y, P->Y.p, mbedtls_mpi_size(&P->Y));
ret = esp_ecc_point_multiply(&p_pt, (uint8_t *)m->p, &r_pt, false);
for (int i = 0; i < MAX_SIZE; i++) {
x_tmp[MAX_SIZE - i - 1] = r_pt.x[i];
y_tmp[MAX_SIZE - i - 1] = r_pt.y[i];
}
mbedtls_mpi_read_binary(&R->X, x_tmp, MAX_SIZE);
mbedtls_mpi_read_binary(&R->Y, y_tmp, MAX_SIZE);
mbedtls_mpi_lset(&R->Z, 1);
return ret;
}
/*
* Restartable multiplication R = m * P
*/
int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx )
{
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
if (grp->id != MBEDTLS_ECP_DP_SECP192R1 && grp->id != MBEDTLS_ECP_DP_SECP256R1) {
#if defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK)
return mbedtls_ecp_mul_restartable_soft(grp, R, m, P, f_rng, p_rng, rs_ctx);
#else
return ret;
#endif
}
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( R != NULL );
ECP_VALIDATE_RET( m != NULL );
ECP_VALIDATE_RET( P != NULL );
/* Common sanity checks */
MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( grp, m ) );
MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) );
ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
/* MBEDTLS_MPI_CHK macro assigns the return value of the function to
* `ret` variable
*/
MBEDTLS_MPI_CHK( esp_mbedtls_ecp_point_multiply(grp, R, m, P) );
cleanup:
return( ret );
}
#endif /* defined(MBEDTLS_ECP_MUL_ALT) || defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK) */
#if defined(MBEDTLS_ECP_VERIFY_ALT) || defined(MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK)
int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp,
const mbedtls_ecp_point *pt )
{
int res;
ecc_point_t point;
if (grp->id != MBEDTLS_ECP_DP_SECP192R1 && grp->id != MBEDTLS_ECP_DP_SECP256R1) {
#if defined(MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK)
return mbedtls_ecp_check_pubkey_soft(grp, pt);
#else
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
#endif
}
ECP_VALIDATE_RET( grp != NULL );
ECP_VALIDATE_RET( pt != NULL );
/* Must use affine coordinates */
if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 )
return( MBEDTLS_ERR_ECP_INVALID_KEY );
mbedtls_platform_zeroize((void *)&point, sizeof(ecc_point_t));
memcpy(&point.x, pt->X.p, mbedtls_mpi_size(&pt->X));
memcpy(&point.y, pt->Y.p, mbedtls_mpi_size(&pt->Y));
point.len = grp->pbits / 8;
res = esp_ecc_point_verify(&point);
if (res == 1) {
return 0;
} else {
return MBEDTLS_ERR_ECP_INVALID_KEY;
}
}
#endif /* defined(MBEDTLS_ECP_VERIFY_ALT) || defined(MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK) */

View File

@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdio.h>
#include "soc/ecc_mult_reg.h"
#include "soc/system_reg.h"
#include "esp_private/periph_ctrl.h"
#include "ecc_impl.h"
#include "hal/ecc_hal.h"
static _lock_t s_crypto_ecc_lock;
static void esp_ecc_acquire_hardware(void)
{
_lock_acquire(&s_crypto_ecc_lock);
periph_module_enable(PERIPH_ECC_MODULE);
}
static void esp_ecc_release_hardware(void)
{
periph_module_disable(PERIPH_ECC_MODULE);
_lock_release(&s_crypto_ecc_lock);
}
int esp_ecc_point_multiply(const ecc_point_t *point, const uint8_t *scalar, ecc_point_t *result, bool verify_first)
{
int ret = -1;
uint16_t len = point->len;
ecc_mode_t work_mode = verify_first ? ECC_MODE_VERIFY_THEN_POINT_MUL : ECC_MODE_POINT_MUL;
esp_ecc_acquire_hardware();
ecc_hal_write_mul_param(scalar, point->x, point->y, len);
ecc_hal_set_mode(work_mode);
ecc_hal_start_calc();
memset(result, 0, sizeof(ecc_point_t));
result->len = len;
while (!ecc_hal_is_calc_finished()) {
;
}
ret = ecc_hal_read_mul_result(result->x, result->y, len);
esp_ecc_release_hardware();
return ret;
}
int esp_ecc_point_verify(const ecc_point_t *point)
{
int result;
esp_ecc_acquire_hardware();
ecc_hal_write_verify_param(point->x, point->y, point->len);
ecc_hal_set_mode(ECC_MODE_VERIFY);
ecc_hal_start_calc();
while (!ecc_hal_is_calc_finished()) {
;
}
result = ecc_hal_read_verify_result();
esp_ecc_release_hardware();
return result;
}

View File

@ -0,0 +1,60 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define P256_LEN (256/8)
#define P192_LEN (192/8)
/* Note: x & y are stored in little endian order (same as CPU byte order, and order used internally by most libraries).
This is the same order used in hardware
Note this is opposite to most byte string formats used to represent keys, which are often big endian
*/
typedef struct {
uint8_t x[P256_LEN]; /* Little endian order */
uint8_t y[P256_LEN]; /* Little endian order */
unsigned len; /* P192_LEN or P256_LEN */
} ecc_point_t;
/**
* @brief Perform ECC point multiplication (R = K * (Px, Py))
*
* @param point ECC point (multiplicand)
* @param scalar Integer represented in byte array format (multiplier)
* @param result Result of the multiplication
* @param verify_first Verify that the point is on the curve before performing multiplication
*
* @return - 0 if the multiplication was successful
* - -1 otherwise
*
* @note 'scalar' is expected as a byte array in little endian order.
* Most byte string formats used to represent keys are in big endian order.
*/
int esp_ecc_point_multiply(const ecc_point_t *point, const uint8_t *scalar, ecc_point_t *result, bool verify_first);
/**
* @brief Perform ECC point verification,
* i.e check whether the point (Px, Py) lies on the curve
*
* @param point ECC point that needs to be verified
*
* @return - 1, if point lies on the curve
* - 0, otherwise
*
*/
int esp_ecc_point_verify(const ecc_point_t *point);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include_next "mbedtls/ecp.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK)
int mbedtls_ecp_mul_restartable_soft(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
mbedtls_ecp_restart_ctx *rs_ctx );
#endif
#if defined(MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK)
int mbedtls_ecp_check_pubkey_soft(const mbedtls_ecp_group *grp,
const mbedtls_ecp_point *pt );
#endif
#ifdef __cplusplus
}
#endif

View File

@ -178,6 +178,25 @@
#define MBEDTLS_ECDSA_VERIFY_ALT
#endif
#ifdef CONFIG_MBEDTLS_HARDWARE_ECC
#ifdef CONFIG_MBEDTLS_ECC_OTHER_CURVES_SOFT_FALLBACK
/* Use hardware accelerator for SECP192R1 and SECP256R1 curves,
* software implementation for rest of the curves
*/
#define MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK
#define MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK
#else
/* Only hardware accelerator support */
#define MBEDTLS_ECP_MUL_ALT
#define MBEDTLS_ECP_VERIFY_ALT
#endif
#else
#undef MBEDTLS_ECP_MUL_ALT
#undef MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK
#undef MBEDTLS_ECP_VERIFY_ALT
#undef MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK
#endif
/**
* \def MBEDTLS_ENTROPY_HARDWARE_ALT
*

View File

@ -84,3 +84,173 @@ TEST_CASE("mbedtls ECP mul w/ koblitz", "[mbedtls]")
mbedtls_ctr_drbg_free(&ctxRandom);
mbedtls_entropy_free(&ctxEntropy);
}
#if CONFIG_MBEDTLS_HARDWARE_ECC
/*
* Coordinates and integers stored in big endian format
*/
const uint8_t ecc_p192_point_x[] = {
0x18, 0x8D, 0xA8, 0x0E, 0xB0, 0x30, 0x90, 0xF6,
0x7C, 0xBF, 0x20, 0xEB, 0x43, 0xA1, 0x88, 0x00,
0xF4, 0xFF, 0x0A, 0xFD, 0x82, 0xFF, 0x10, 0x12
};
const uint8_t ecc_p192_point_y[] = {
0x07, 0x19, 0x2B, 0x95, 0xFF, 0xC8, 0xDA, 0x78,
0x63, 0x10, 0x11, 0xED, 0x6B, 0x24, 0xCD, 0xD5,
0x73, 0xF9, 0x77, 0xA1, 0x1E, 0x79, 0x48, 0x11
};
const uint8_t ecc_p192_scalar[] = {
0x6f, 0x18, 0x34, 0xeb, 0x16, 0xb7, 0xac, 0x9f,
0x3c, 0x77, 0x71, 0xb3, 0x02, 0x30, 0x70, 0x48,
0x75, 0x87, 0xbb, 0x6f, 0x80, 0x34, 0x8d, 0x5e
};
const uint8_t ecc_p192_mul_res_x[] = {
0x3F, 0xEE, 0x6F, 0x1F, 0x99, 0xDC, 0xCB, 0x78,
0xB7, 0x47, 0x1C, 0x2A, 0xF5, 0xA0, 0xAC, 0xE6,
0xEC, 0x24, 0x82, 0x37, 0x6C, 0xC0, 0x27, 0xC5,
};
const uint8_t ecc_p192_mul_res_y[] = {
0xDF, 0xF3, 0x9E, 0x76, 0x24, 0xF4, 0xF6, 0xB4,
0xF0, 0x0A, 0x18, 0xE1, 0x0B, 0xD2, 0xD9, 0x83,
0xE8, 0x29, 0x5E, 0xD9, 0x46, 0x54, 0xC3, 0xE1
};
const uint8_t ecc_p256_point_x[] = {
0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47,
0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96
};
const uint8_t ecc_p256_point_y[] = {
0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B,
0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE,
0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5
};
const uint8_t ecc_p256_scalar[] = {
0xB2, 0xC5, 0x9E, 0x92, 0x64, 0xCD, 0x5F, 0x66,
0x9E, 0xC8, 0x83, 0x6D, 0x99, 0x61, 0x18, 0x72,
0xC8, 0x60, 0x83, 0x1E, 0xE5, 0x79, 0xCC, 0x73,
0xA9, 0xB4, 0x74, 0x85, 0x70, 0x11, 0x2D, 0xA2,
};
const uint8_t ecc_p256_mul_res_x[] = {
0x26, 0x1A, 0x0F, 0xBD, 0xA5, 0xE5, 0x1E, 0xE7,
0xB3, 0xC3, 0xB7, 0x09, 0xD1, 0x4A, 0x7A, 0x2A,
0x16, 0x69, 0x4B, 0xAF, 0x76, 0x5C, 0xD4, 0x0E,
0x93, 0x57, 0xB8, 0x67, 0xF9, 0xA1, 0xE5, 0xE8
};
const uint8_t ecc_p256_mul_res_y[] = {
0xA0, 0xF4, 0x2E, 0x62, 0x36, 0x25, 0x9F, 0xE0,
0xF2, 0xA0, 0x41, 0x42, 0xD2, 0x95, 0x89, 0x41,
0x38, 0xF0, 0xEB, 0x6E, 0xA7, 0x96, 0x29, 0x24,
0xC7, 0xD4, 0x0C, 0x90, 0xA1, 0xC9, 0xD3, 0x3A
};
static int rng_wrapper(void *ctx, unsigned char *buf, size_t len)
{
esp_fill_random(buf, len);
return 0;
}
static void test_ecp_mul(mbedtls_ecp_group_id id, const uint8_t *x_coord, const uint8_t *y_coord, const uint8_t *scalar,
const uint8_t *result_x_coord, const uint8_t *result_y_coord)
{
uint8_t x[32];
uint8_t y[32];
int size;
int ret;
mbedtls_ecp_group grp;
mbedtls_ecp_point R;
mbedtls_ecp_point P;
mbedtls_mpi m;
mbedtls_ecp_group_init(&grp);
mbedtls_ecp_point_init(&R);
mbedtls_ecp_point_init(&P);
mbedtls_mpi_init(&m);
mbedtls_ecp_group_load(&grp, id);
size = grp.pbits / 8;
mbedtls_mpi_read_binary(&m, scalar, size);
mbedtls_mpi_read_binary(&P.X, x_coord, size);
mbedtls_mpi_read_binary(&P.Y, y_coord, size);
mbedtls_mpi_lset(&P.Z, 1);
ret = mbedtls_ecp_mul(&grp, &R, &m, &P, rng_wrapper, NULL);
TEST_ASSERT_EQUAL(0, ret);
mbedtls_mpi_write_binary(&R.X, x, mbedtls_mpi_size(&R.X));
mbedtls_mpi_write_binary(&R.Y, y, mbedtls_mpi_size(&R.Y));
TEST_ASSERT_EQUAL(0, memcmp(x, result_x_coord, mbedtls_mpi_size(&R.X)));
TEST_ASSERT_EQUAL(0, memcmp(y, result_y_coord, mbedtls_mpi_size(&R.Y)));
mbedtls_ecp_point_free(&R);
mbedtls_ecp_point_free(&P);
mbedtls_mpi_free(&m);
mbedtls_ecp_group_free(&grp);
}
TEST_CASE("mbedtls ECP point multiply with SECP192R1", "[mbedtls]")
{
test_ecp_mul(MBEDTLS_ECP_DP_SECP192R1, ecc_p192_point_x, ecc_p192_point_y, ecc_p192_scalar,
ecc_p192_mul_res_x, ecc_p192_mul_res_y);
}
TEST_CASE("mbedtls ECP point multiply with SECP256R1", "[mbedtls]")
{
test_ecp_mul(MBEDTLS_ECP_DP_SECP256R1, ecc_p256_point_x, ecc_p256_point_y, ecc_p256_scalar,
ecc_p256_mul_res_x, ecc_p256_mul_res_y);
}
static void test_ecp_verify(mbedtls_ecp_group_id id, const uint8_t *x_coord, const uint8_t *y_coord)
{
int size;
int ret;
mbedtls_ecp_group grp;
mbedtls_ecp_point P;
mbedtls_ecp_group_init(&grp);
mbedtls_ecp_point_init(&P);
mbedtls_ecp_group_load(&grp, id);
size = grp.pbits / 8;
mbedtls_mpi_read_binary(&P.X, x_coord, size);
mbedtls_mpi_read_binary(&P.Y, y_coord, size);
mbedtls_mpi_lset(&P.Z, 1);
ret = mbedtls_ecp_check_pubkey(&grp, &P);
TEST_ASSERT_EQUAL(0, ret);
mbedtls_ecp_point_free(&P);
mbedtls_ecp_group_free(&grp);
}
TEST_CASE("mbedtls ECP point verify with SECP192R1", "[mbedtls]")
{
test_ecp_verify(MBEDTLS_ECP_DP_SECP192R1, ecc_p192_mul_res_x, ecc_p192_mul_res_y);
}
TEST_CASE("mbedtls ECP point verify with SECP256R1", "[mbedtls]")
{
test_ecp_verify(MBEDTLS_ECP_DP_SECP256R1, ecc_p256_mul_res_x, ecc_p256_mul_res_y);
}
#endif /* CONFIG_MBEDTLS_HARDWARE_ECC */