From 0e5ebafb5656952d5bef5efd62ce3ab67aba6e6c Mon Sep 17 00:00:00 2001 From: Steven Cooreman Date: Wed, 8 Feb 2023 23:32:11 +0100 Subject: [PATCH] [Silabs] Add partial hardware acceleration of SPAKE2+ on EFR32xG2x (#24845) * Reuse curve parameters stored in object instead of recreating * Speed up SPAKE2+ point multiplication on devices with HSE Silicon Labs devices with SEMAILBOX have a feature to return the full result of the ECDH key derivation operation, which is equal to the result of a scalar ECPoint multiplication operation. Leverage that hardware- accelerated primitive to speed up the commissioning process versus doing ECP calculations in pure software. * Speed up SPAKE2+ point multiplication on devices with HSE (2) Now that the base point multiplication operation is accelerated, split up the AddMul function in two (accelerated) multiplications and one software-backed addition. * Speed up SPAKE2+ point multiplication on devices with HSE (3) Replace the last instance of mbedtls_ecp_mul with the accelerated operation * Restyled by clang-format * Add error handling to EFR32 accelerated version of PointAddMul --------- Co-authored-by: Restyled.io --- .../silabs/efr32/CHIPCryptoPALPsaEfr32.cpp | 173 ++++++++++++++++-- 1 file changed, 162 insertions(+), 11 deletions(-) diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index f7cde6fd14fe33..6972da95aff7a8 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -1207,15 +1207,130 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointWrite(const void * R, uint8_t * o return CHIP_NO_ERROR; } +extern "C" { +#include "em_device.h" +} + +#if defined(SEMAILBOX_PRESENT) +// Add inlined optimisation which can use the SE to do point multiplication operations using +// the ECDH primitive as a proxy for scalar multiplication. +extern "C" { +#include "sl_se_manager.h" +#include "sl_se_manager_key_derivation.h" +#include "sl_se_manager_util.h" +#include "sli_se_driver_key_management.h" +#include "sli_se_manager_internal.h" +} +#endif /* SEMAILBOX_PRESENT */ + CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointMul(void * R, const void * P1, const void * fe1) { Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); +#if defined(SEMAILBOX_PRESENT) + psa_status_t status = PSA_SUCCESS; + uint8_t point[2 * kP256_FE_Length] = { 0 }; + uint8_t scalar[kP256_FE_Length] = { 0 }; + + // This inlined implementation only supports P256, but check assumptions + if (context->curve.id != MBEDTLS_ECP_DP_SECP256R1) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + /* pull out key info from mbedtls structures */ + status = mbedtls_mpi_write_binary((const mbedtls_mpi *) fe1, scalar, sizeof(scalar)); + if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + status = mbedtls_mpi_write_binary(&((const mbedtls_ecp_point *) P1)->MBEDTLS_PRIVATE(X), point, kP256_FE_Length); + if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + status = + mbedtls_mpi_write_binary(&((const mbedtls_ecp_point *) P1)->MBEDTLS_PRIVATE(Y), point + kP256_FE_Length, kP256_FE_Length); + if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + { + sl_se_key_descriptor_t priv_desc = { 0 }; + sl_se_key_descriptor_t pub_desc = { 0 }; + sl_se_key_descriptor_t shared_desc = { 0 }; + sl_se_command_context_t cmd_ctx = SL_SE_COMMAND_CONTEXT_INIT; + sl_status_t sl_status = SL_STATUS_FAIL; + + // Set private key to scalar + priv_desc.type = SL_SE_KEY_TYPE_ECC_P256; + priv_desc.flags |= SL_SE_KEY_FLAG_ASYMMETRIC_BUFFER_HAS_PRIVATE_KEY; + sli_se_key_descriptor_set_plaintext(&priv_desc, scalar, sizeof(scalar)); + + // Set public key to point + pub_desc.type = SL_SE_KEY_TYPE_ECC_P256; + pub_desc.flags |= SL_SE_KEY_FLAG_ASYMMETRIC_BUFFER_HAS_PUBLIC_KEY; + sli_se_key_descriptor_set_plaintext(&pub_desc, point, sizeof(point)); + + // Set output to point + shared_desc.type = SL_SE_KEY_TYPE_SYMMETRIC; + shared_desc.size = sizeof(point); + sli_se_key_descriptor_set_plaintext(&shared_desc, point, sizeof(point)); + + // Re-init SE command context. + sl_status = sl_se_init_command_context(&cmd_ctx); + if (sl_status != SL_STATUS_OK) + { + return CHIP_ERROR_INTERNAL; + } + + // Perform key agreement algorithm (ECDH). + sl_status = sl_se_ecdh_compute_shared_secret(&cmd_ctx, &priv_desc, &pub_desc, &shared_desc); + if (sl_status != SL_STATUS_OK) + { + ChipLogError(Crypto, "ECDH SL failure %lx", sl_status); + if (sl_status == SL_STATUS_COMMAND_IS_INVALID) + { + // This error will be returned if the key type isn't supported. + return CHIP_ERROR_NOT_IMPLEMENTED; + } + else + { + // If the ECDH operation failed, this is most likely due to the peer key + // being an invalid elliptic curve point. Other sources for failure should + // hopefully have been caught during parameter validation. + return CHIP_ERROR_INVALID_ARGUMENT; + } + } + } + + status = mbedtls_mpi_read_binary(&((mbedtls_ecp_point *) R)->MBEDTLS_PRIVATE(X), point, kP256_FE_Length); + if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + status = mbedtls_mpi_read_binary(&((mbedtls_ecp_point *) R)->MBEDTLS_PRIVATE(Y), point + kP256_FE_Length, kP256_FE_Length); + if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } + + status = mbedtls_mpi_lset(&((mbedtls_ecp_point *) R)->MBEDTLS_PRIVATE(Z), 1); + if (status != PSA_SUCCESS) + { + return CHIP_ERROR_INTERNAL; + } +#else /* SEMAILBOX_PRESENT */ if (mbedtls_ecp_mul(&context->curve, (mbedtls_ecp_point *) R, (const mbedtls_mpi *) fe1, (const mbedtls_ecp_point *) P1, CryptoRNG, nullptr) != 0) { return CHIP_ERROR_INTERNAL; } +#endif /* SEMAILBOX_PRESENT */ return CHIP_NO_ERROR; } @@ -1225,6 +1340,36 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointAddMul(void * R, const void * P1, { Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); +#if defined(SEMAILBOX_PRESENT) + CHIP_ERROR error = CHIP_NO_ERROR; + int result; + + // Accelerate 'muladd' using separate point multiplication operations + mbedtls_ecp_point fe1P1, fe2P2; + mbedtls_mpi one; + mbedtls_mpi_init(&one); + mbedtls_ecp_point_init(&fe1P1); + mbedtls_ecp_point_init(&fe2P2); + + result = mbedtls_mpi_lset(&one, 1); + VerifyOrExit(result == 0, error = CHIP_ERROR_NO_MEMORY); + + // Do fe1P1 = fe1 * P1 and fe2P2 = fe2 * P2 since those can be accelerated + SuccessOrExit(error = PointMul(&fe1P1, P1, fe1)); + SuccessOrExit(error = PointMul(&fe2P2, P2, fe2)); + + // Do R = (1 * fe1P1) + (1 * fe2P2) since point addition is not a public mbedTLS API + // mbedTLS will apply a shortcut since (1 * A) == A + result = mbedtls_ecp_muladd(&context->curve, (mbedtls_ecp_point *) R, &one, &fe1P1, &one, &fe2P2); + VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); + +exit: + mbedtls_mpi_free(&one); + mbedtls_ecp_point_free(&fe1P1); + mbedtls_ecp_point_free(&fe2P2); + + return error; +#else /* SEMAILBOX_PRESENT */ if (mbedtls_ecp_muladd(&context->curve, (mbedtls_ecp_point *) R, (const mbedtls_mpi *) fe1, (const mbedtls_ecp_point *) P1, (const mbedtls_mpi *) fe2, (const mbedtls_ecp_point *) P2) != 0) { @@ -1232,6 +1377,7 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointAddMul(void * R, const void * P1, } return CHIP_NO_ERROR; +#endif /* SEMAILBOX_PRESENT */ } CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointInvert(void * R) @@ -1254,39 +1400,44 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointCofactorMul(void * R) CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeL(uint8_t * Lout, size_t * L_len, const uint8_t * w1in, size_t w1in_len) { - CHIP_ERROR error = CHIP_NO_ERROR; - int result = 0; + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + Spake2p_Context * context = to_inner_spake2p_context(&mSpake2pContext); - mbedtls_ecp_group curve; mbedtls_mpi w1_bn; mbedtls_ecp_point Ltemp; - mbedtls_ecp_group_init(&curve); mbedtls_mpi_init(&w1_bn); mbedtls_ecp_point_init(&Ltemp); - result = mbedtls_ecp_group_load(&curve, MBEDTLS_ECP_DP_SECP256R1); - VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - result = mbedtls_mpi_read_binary(&w1_bn, Uint8::to_const_uchar(w1in), w1in_len); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - result = mbedtls_mpi_mod_mpi(&w1_bn, &w1_bn, &curve.N); + result = mbedtls_mpi_mod_mpi(&w1_bn, &w1_bn, &context->curve.N); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); - result = mbedtls_ecp_mul(&curve, &Ltemp, &w1_bn, &curve.G, CryptoRNG, nullptr); +#if defined(SEMAILBOX_PRESENT) + // Do the point multiplication using hardware acceleration via ECDH primitive + error = PointMul(&Ltemp, &context->curve.G, &w1_bn); + if (error != CHIP_NO_ERROR) + { + goto exit; + } +#else /* SEMAILBOX_PRESENT */ + result = mbedtls_ecp_mul(&context->curve, &Ltemp, &w1_bn, &context->curve.G, CryptoRNG, nullptr); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); +#endif /* SEMAILBOX_PRESENT */ memset(Lout, 0, *L_len); - result = mbedtls_ecp_point_write_binary(&curve, &Ltemp, MBEDTLS_ECP_PF_UNCOMPRESSED, L_len, Uint8::to_uchar(Lout), *L_len); + result = + mbedtls_ecp_point_write_binary(&context->curve, &Ltemp, MBEDTLS_ECP_PF_UNCOMPRESSED, L_len, Uint8::to_uchar(Lout), *L_len); VerifyOrExit(result == 0, error = CHIP_ERROR_INTERNAL); exit: _log_mbedTLS_error(result); mbedtls_ecp_point_free(&Ltemp); mbedtls_mpi_free(&w1_bn); - mbedtls_ecp_group_free(&curve); return error; }