From 99fcf772ceeeada0b09cb065d521c1472e1edd69 Mon Sep 17 00:00:00 2001 From: Georgios Vasilakis Date: Fri, 3 Jan 2025 15:24:35 +0100 Subject: [PATCH] nrf_security: Add Cracen key derivation for SPAKE2P keys Adds support for key derivation of SPAKE2P keys with Cracen. It currently supports only SECP256R1 keys. Ref: NCSDK-30368 Signed-off-by: Georgios Vasilakis --- .../cracen/cracenpsa/include/cracen_psa.h | 4 + .../src/drivers/cracen/cracenpsa/src/common.c | 17 +++++ .../src/drivers/cracen/cracenpsa/src/common.h | 13 ++++ .../cracen/cracenpsa/src/key_management.c | 73 +++++++++++++++++++ .../src/psa_crypto_driver_wrappers.c | 22 +++++- 5 files changed, 126 insertions(+), 3 deletions(-) diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h index a5389c878853..81df11e817b7 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/include/cracen_psa.h @@ -361,4 +361,8 @@ psa_status_t cracen_spake2p_get_shared_key(cracen_spake2p_operation_t *operation psa_status_t cracen_spake2p_abort(cracen_spake2p_operation_t *operation); +psa_status_t cracen_derive_key(const psa_key_attributes_t *attributes, const uint8_t *input, + size_t input_length, uint8_t *key, size_t key_size, + size_t *key_length); + #endif /* CRACEN_PSA_H */ diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c index 181b1a203579..3186d32f18bd 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -329,6 +330,22 @@ bool cracen_ecc_curve_is_weierstrass(psa_ecc_family_t curve) } } +psa_status_t cracen_ecc_reduce_p256(const uint8_t *input, size_t input_size, uint8_t *output, + size_t output_size) +{ + const uint8_t *order = sx_pk_curve_order(&sx_curve_nistp256); + + sx_op modulo = {.sz = CRACEN_P256_KEY_SIZE, .bytes = (char *)order}; + sx_op b = {.sz = input_size, .bytes = (char *)input}; + sx_op result = {.sz = output_size, .bytes = output}; + + /* The nistp256 curve order (n) is prime so we use the ODD variant of the reduce command. */ + const struct sx_pk_cmd_def *cmd = SX_PK_CMD_ODD_MOD_REDUCE; + int sx_status = sx_mod_single_op_cmd(cmd, &modulo, &b, &result); + + return silex_statuscodes_to_psa(sx_status); +} + psa_status_t cracen_ecc_check_public_key(const struct sx_pk_ecurve *curve, const sx_pk_affine_point *in_pnt) { diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h index 8971f7d23dc1..bb5ee1d5c927 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h @@ -186,3 +186,16 @@ psa_status_t cracen_cipher_crypt_ecb(const struct sxkeyref *key, const uint8_t * * @return sxsymcrypt error code. */ int cracen_prepare_ik_key(const uint8_t *user_data); + +/** + * @brief Performs input modulo the order of the NIST p256 curve + * + * @param input Input for the modulo operation. + * @param input_size Input size in bytes. + * @param output Output of the modulo operation. + * @param output_size Output size in bytes. + * + * @return psa_status_t + */ +psa_status_t cracen_ecc_reduce_p256(const uint8_t *input, size_t input_size, uint8_t *output, + size_t output_size); diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c index 8eada3f22b00..b8a969eee4c9 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c @@ -471,6 +471,59 @@ static psa_status_t import_spake2p_key(const psa_key_attributes_t *attributes, c return PSA_SUCCESS; } +static psa_status_t cracen_derive_spake2p_key(const psa_key_attributes_t *attributes, const uint8_t *input, + size_t input_length, uint8_t *key, size_t key_size, + size_t *key_length) +{ + size_t bits = psa_get_key_bits(attributes); + psa_key_type_t type = psa_get_key_type(attributes); + psa_status_t status; + + switch (type) { + case PSA_KEY_TYPE_SPAKE2P_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1): + + if (bits != 256) { + return PSA_ERROR_NOT_SUPPORTED; + } + + if (input_length != 80) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (key_size < 2 * CRACEN_P256_KEY_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* Described in section 3.2 of rfc9383, split the output of the PBKDF2 + * into two parts, treat each part as integer and perform a modulo operation + * on each half. + */ + status = cracen_ecc_reduce_p256(input, input_length / 2, key, CRACEN_P256_KEY_SIZE); + if (status != PSA_SUCCESS) { + return status; + } + + if (constant_memcmp_is_zero(key, CRACEN_P256_KEY_SIZE)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = cracen_ecc_reduce_p256(input + (input_length / 2), input_length / 2, + key + CRACEN_P256_KEY_SIZE, CRACEN_P256_KEY_SIZE); + if (status != PSA_SUCCESS) { + return status; + } + + if (constant_memcmp_is_zero(key + CRACEN_P256_KEY_SIZE, CRACEN_P256_KEY_SIZE)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + *key_length = 2 * CRACEN_P256_KEY_SIZE; + return PSA_SUCCESS; + default: + return PSA_ERROR_NOT_SUPPORTED; + } +} + static psa_status_t import_srp_key(const psa_key_attributes_t *attributes, const uint8_t *data, size_t data_length, uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length, size_t *key_bits) @@ -1412,3 +1465,23 @@ psa_status_t cracen_destroy_key(const psa_key_attributes_t *attributes) return PSA_ERROR_DOES_NOT_EXIST; } + +psa_status_t cracen_derive_key(const psa_key_attributes_t *attributes, const uint8_t *input, + size_t input_length, uint8_t *key, size_t key_size, + size_t *key_length) +{ + psa_key_type_t key_type = psa_get_key_type(attributes); + + if (PSA_KEY_TYPE_IS_SPAKE2P_KEY_PAIR(key_type) && IS_ENABLED(PSA_NEED_CRACEN_SPAKE2P)) { + return cracen_derive_spake2p_key(attributes, input, input_length, key, key_size, + key_length); + } + + (void)input; + (void)input_length; + (void)key; + (void)key_size; + (void)key_length; + (void)key_type; + return PSA_ERROR_NOT_SUPPORTED; +} diff --git a/subsys/nrf_security/src/psa_crypto_driver_wrappers.c b/subsys/nrf_security/src/psa_crypto_driver_wrappers.c index 9b075837cadd..f1625f9e9093 100644 --- a/subsys/nrf_security/src/psa_crypto_driver_wrappers.c +++ b/subsys/nrf_security/src/psa_crypto_driver_wrappers.c @@ -790,12 +790,27 @@ psa_status_t psa_driver_wrapper_derive_key(const psa_key_attributes_t *attribute uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length) { + psa_status_t status = PSA_ERROR_INVALID_ARGUMENT; + switch (PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime)) { case PSA_KEY_LOCATION_LOCAL_STORAGE: /* Add cases for transparent drivers here */ +#ifdef PSA_NEED_CRACEN_KEY_MANAGEMENT_DRIVER + status = cracen_derive_key(attributes, input, input_length, key_buffer, + key_buffer_size, key_buffer_length); + + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } +#endif /* PSA_NEED_CRACEN_KEY_MANAGEMENT_DRIVER */ + #ifdef PSA_NEED_OBERON_KEY_MANAGEMENT_DRIVER - return oberon_derive_key(attributes, input, input_length, key_buffer, - key_buffer_size, key_buffer_length); + status = oberon_derive_key(attributes, input, input_length, key_buffer, + key_buffer_size, key_buffer_length); + + if (status != PSA_ERROR_NOT_SUPPORTED) { + return status; + } #endif /* PSA_NEED_OBERON_KEY_MANAGEMENT_DRIVER */ break; @@ -809,7 +824,8 @@ psa_status_t psa_driver_wrapper_derive_key(const psa_key_attributes_t *attribute (void)key_buffer_size; (void)key_buffer_length; } - return PSA_ERROR_INVALID_ARGUMENT; + + return status; } /*