Skip to content

Commit

Permalink
nrf_security: Add Cracen key derivation for SPAKE2P keys
Browse files Browse the repository at this point in the history
Adds support for key derivation of SPAKE2P keys with Cracen.
It currently supports only SECP256R1 keys.

Ref: NCSDK-30368

Signed-off-by: Georgios Vasilakis <georgios.vasilakis@nordicsemi.no>
  • Loading branch information
Vge0rge committed Feb 3, 2025
1 parent ca3e7af commit 99fcf77
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
17 changes: 17 additions & 0 deletions subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <silexpk/ec_curves.h>
#include <silexpk/ik.h>
#include <silexpk/sxops/eccweierstrass.h>
#include <silexpk/sxops/rsa.h>
#include <stddef.h>
#include <sxsymcrypt/sha1.h>
#include <sxsymcrypt/sha2.h>
Expand Down Expand Up @@ -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)
{
Expand Down
13 changes: 13 additions & 0 deletions subsys/nrf_security/src/drivers/cracen/cracenpsa/src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Check warning on line 474 in subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LONG_LINE

subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c:474 line length of 107 exceeds 100 columns
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)
Expand Down Expand Up @@ -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;
}
22 changes: 19 additions & 3 deletions subsys/nrf_security/src/psa_crypto_driver_wrappers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}

/*
Expand Down

0 comments on commit 99fcf77

Please sign in to comment.