Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nrf_security: drivers: cracen: adding support for ed25519 without sicrypto #19812

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ endif()
if(CONFIG_PSA_NEED_CRACEN_ASYMMETRIC_SIGNATURE_DRIVER)
list(APPEND cracen_driver_sources
${CMAKE_CURRENT_LIST_DIR}/src/sign.c
${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c
)
endif()

Expand All @@ -61,6 +62,7 @@ endif()

if(CONFIG_PSA_NEED_CRACEN_KEY_MANAGEMENT_DRIVER OR CONFIG_PSA_NEED_CRACEN_KMU_DRIVER OR CONFIG_MBEDTLS_PSA_CRYPTO_BUILTIN_KEYS)
list(APPEND cracen_driver_sources
${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c
${CMAKE_CURRENT_LIST_DIR}/src/key_management.c
)
endif()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,20 @@ psa_status_t cracen_spake2p_get_shared_key(cracen_spake2p_operation_t *operation

psa_status_t cracen_spake2p_abort(cracen_spake2p_operation_t *operation);

int ed25519_sign(const uint8_t *privkey, char *signature,
const uint8_t *message, size_t message_length);

int ed25519_verify(const uint8_t *pubkey, const char *message,
size_t message_length, const char *signature);


int ed25519ph_sign(const uint8_t *privkey, char *signature,
const uint8_t *message, size_t message_length, int ismessage);

int ed25519ph_verify(const uint8_t *pubkey, const char *message,
size_t message_length, const char *signature, int ismessage);

int ed25519_create_pubkey(const uint8_t *privkey,
uint8_t *pubkey);

#endif /* CRACEN_PSA_H */
338 changes: 338 additions & 0 deletions subsys/nrf_security/src/drivers/cracen/cracenpsa/src/ed25519.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <string.h>
#include <sxsymcrypt/sha2.h>
#include <silexpk/ed25519.h>
#include <cracen/ec_helpers.h>
#include <sxsymcrypt/hash.h>
#include <cracen/mem_helpers.h>

const char dom2[34] = {
0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35,
0x35, 0x31, 0x39, 0x20, 0x6e, 0x6f, 0x20,
0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39,
0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73,
0x69, 0x6f, 0x6e, 0x73, 0x01, 0x00
};

int ed25519_hash_message(const char *message, size_t message_length, char *workmem)
{
int status;
struct sxhash hashopctx;

status = sx_hash_create(&hashopctx, &sxhashalg_sha2_512, sizeof(hashopctx));

if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, message, message_length);
if (status != 0) {
return status;
}
status = sx_hash_digest(&hashopctx, workmem);
return status;

}

int ed25519_hash_privkey(struct sxhash hashopctx, char *workmem, const uint8_t *priv_key)
{

int status;
/*Hash the private key, the digest is stored in the first 64 bytes of workmem*/
status = sx_hash_create(&hashopctx, &sxhashalg_sha2_512, sizeof(hashopctx));
if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, priv_key, 32);
if (status != 0) {
return status;
}
status = sx_hash_digest(&hashopctx, workmem);
if (status != 0) {
return status;
}
/*Wait to make sure hash operation is finished before doing calculations on it*/
status = sx_hash_wait(&hashopctx);

return status;
}


int ed25519_calculate_r(struct sxhash hashopctx, char *workmem,
const uint8_t *message, size_t message_length, int prehash)
{
int status;

status = sx_hash_create(&hashopctx, &sxhashalg_sha2_512, sizeof(hashopctx));

if (status != 0) {
return status;
}
if (prehash) {
status = sx_hash_feed(&hashopctx, dom2, 34);
if (status != 0) {
return status;
}
}
status = sx_hash_feed(&hashopctx, workmem+32, 32);
if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, message, message_length);
if (status != 0) {
return status;
}
status = sx_hash_digest(&hashopctx, workmem+96);

return status;
}

int ed25519_calculate_k(struct sxhash hashopctx, char *workmem, char *pointr,
const char *message, size_t message_length, int prehash)
{
/* Obtain k by hashing (R || A || message). where A is the public key */
int status;

status = sx_hash_create(&hashopctx, &sxhashalg_sha2_512, sizeof(hashopctx));

if (status != 0) {
return status;
}
if (prehash) {
status = sx_hash_feed(&hashopctx, dom2, sizeof(dom2));
if (status != 0) {
return status;
}
}
status = sx_hash_feed(&hashopctx, pointr, 32);
if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, workmem+32, 32);
if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, message, message_length);
if (status != 0) {
return status;
}
status = sx_hash_digest(&hashopctx, workmem+32);
return status;
}

int ed25519_sign_internal(const uint8_t *priv_key, char *signature,
const uint8_t *message, size_t message_length, int prehash)
{
char workmem[160];
struct sxhash hashopctx;
char pointr_buffer[64];
char *pointr = pointr_buffer;
int status;

/*Hash the private key, the digest is stored in the first 64 bytes of workmem*/
status = ed25519_hash_privkey(hashopctx, workmem, priv_key);
if (status != 0) {
return status;
}

/* Obtain r by hashing (prefix || message), where prefix is the second
* half of the private key digest.
*/
status = ed25519_calculate_r(hashopctx, workmem, message, message_length, prehash);
/* Perform point multiplication R = [r]B. This is the encoded point R,
* which is the first part of the signature.
*/
status = sx_ed25519_ptmult((const struct sx_ed25519_dgst *)(workmem + 96),
(struct sx_ed25519_pt *)pointr);
if (status != 0) {
return status;

}
/* The secret scalar s is computed in place from the first half of the
* private key digest.
*/
decode_scalar_25519(workmem);

/* Clear second half of private key digest: sx_async_ed25519_ptmult_go()
* works on an input of SX_ED25519_DGST_SZ bytes.
*/
safe_memset(workmem + 32, 128, 0, 32);
/* Perform point multiplication A = [s]B,
* to obtain the public key A. which is stored in workmem[32:63]
*/
status = sx_ed25519_ptmult((const struct sx_ed25519_dgst *)(workmem),
(struct sx_ed25519_pt *)(struct sx_ed25519_pt *)((char *)workmem + 32));
if (status != 0) {
return status;
}

status = ed25519_calculate_k(hashopctx, workmem, pointr, message, message_length, prehash);
if (status != 0) {
return status;
}

/* Compute (r + k * s) mod L. This gives the second part of the
* signature, which is the encoded S which is stored in pointr.
*/

status = sx_ed25519_sign(
(const struct sx_ed25519_dgst *)(workmem + 32),
(const struct sx_ed25519_dgst *)(workmem + 3 * 32),
(const struct sx_ed25519_v *)workmem,
(struct sx_ed25519_v *)(pointr + SX_ED25519_PT_SZ));
if (status != 0) {
return status;
}

memcpy(signature, pointr, 64);

return status;

}


int ed25519_sign(const uint8_t *priv_key, char *signature,
const uint8_t *message, size_t message_length)
{
return ed25519_sign_internal(priv_key, signature, message, message_length, 0);
}

int ed25519ph_sign(const uint8_t *priv_key, char *signature,
const uint8_t *message, size_t message_length, int ismessage)
{
char hashedmessage[64];
int status;

if (ismessage) {
status = ed25519_hash_message(message, message_length, hashedmessage);
if (status != 0) {
return status;
}
return ed25519_sign_internal(priv_key, signature, hashedmessage, 64, 1);
} else {
return ed25519_sign_internal(priv_key, signature, message, message_length, 1);
}
}

int ed25519_verify_internal(const uint8_t *pubkey, const char *message,
size_t message_length, const char *signature, int prehash)
{
char workmem[64];
struct sxhash hashopctx;
int status;

status = sx_hash_create(&hashopctx, &sxhashalg_sha2_512, sizeof(hashopctx));
if (status != 0) {
return status;
}
if (prehash) {
status = sx_hash_feed(&hashopctx, dom2, sizeof(dom2));
if (status != 0) {
return status;
}
}
status = sx_hash_feed(&hashopctx, signature, 32);
if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, pubkey, 32);
if (status != 0) {
return status;
}
status = sx_hash_feed(&hashopctx, message, message_length);
if (status != 0) {
return status;
}
status = sx_hash_digest(&hashopctx, workmem);
if (status != 0) {
return status;
}

status = sx_ed25519_verify(
(struct sx_ed25519_dgst *)workmem,
(struct sx_ed25519_pt *)pubkey,
(const struct sx_ed25519_v *)(signature + 32),
(const struct sx_ed25519_pt *)signature);

return status;
}

int ed25519_verify(const uint8_t *pubkey, const char *message,
size_t message_length, const char *signature)
{
return ed25519_verify_internal(pubkey, message,
message_length, signature, 0);
}

int ed25519ph_verify(const uint8_t *pubkey, const char *message,
size_t message_length, const char *signature, int ismessage)
{
int status;
char hashedmessage[64];

if (ismessage) {
status = ed25519_hash_message(message, message_length, hashedmessage);
if (status != 0) {
return status;
}
return ed25519_verify_internal(pubkey, hashedmessage, 64, signature, 1);
}
return ed25519_verify_internal(pubkey, message, message_length, signature, 1);
}

int ed25519_create_pubkey(const uint8_t *priv_key,
uint8_t *pubkey)
{
char workmem[64];
struct sxhash hashopctx;
int status;

/*Hash the privat key*/
status = sx_hash_create(&hashopctx, &sxhashalg_sha2_512, sizeof(hashopctx));
if (status != 0) {
return status;
}

status = sx_hash_feed(&hashopctx, priv_key, 32);
if (status != 0) {
return status;
}

status = sx_hash_digest(&hashopctx, workmem);
if (status != 0) {
return status;
}

/*Wait to make sure hash operation is finished before doing
* calculations on it. Removing this breaks pubkey generation
*/
status = sx_hash_wait(&hashopctx);
if (status != 0) {
return status;
}

/* The secret scalar s is computed in place from the first half of the
* private key digest.
*/
decode_scalar_25519(workmem);

/* Clear second half of private key digest: sx_async_ed25519_ptmult_go()
* works on an input of SX_ED25519_DGST_SZ bytes.
*/
safe_memset(workmem+32, 32, 0, 32);

/* Perform point multiplication A = [s]B, to obtain the public key A. */
status = sx_ed25519_ptmult((const struct sx_ed25519_dgst *)(workmem),
(struct sx_ed25519_pt *)(struct sx_ed25519_pt *)((char *)workmem + 32));
if (status != 0) {
return status;
}

memcpy(pubkey, workmem+32, 32);

return status;

}
Loading
Loading