Skip to content

Commit

Permalink
[Silabs] Add partial hardware acceleration of SPAKE2+ on EFR32xG2x (#…
Browse files Browse the repository at this point in the history
…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 <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Aug 8, 2024
1 parent 1a763d5 commit 0e5ebaf
Showing 1 changed file with 162 additions and 11 deletions.
173 changes: 162 additions & 11 deletions src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -1225,13 +1340,44 @@ 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)
{
return CHIP_ERROR_INTERNAL;
}

return CHIP_NO_ERROR;
#endif /* SEMAILBOX_PRESENT */
}

CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::PointInvert(void * R)
Expand All @@ -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;
}
Expand Down

0 comments on commit 0e5ebaf

Please sign in to comment.