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

sys/psa_crypto: Ed25519 (EdDSA) support #19954

Merged
merged 6 commits into from
Oct 11, 2023
Merged
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
1 change: 1 addition & 0 deletions cpu/nrf52/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ config CPU_MODEL_NRF52840XXAA
select HAS_PERIPH_CIPHER_AES_128_CBC
select HAS_PERIPH_ECC_P192R1
select HAS_PERIPH_ECC_P256R1
select HAS_PERIPH_ECC_ED25519
select HAS_PERIPH_CRYPTOCELL_310

## CPU common symbols
Expand Down
1 change: 1 addition & 0 deletions cpu/nrf52/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL)))
FEATURES_PROVIDED += periph_cipher_aes_128_cbc
FEATURES_PROVIDED += periph_ecc_p192r1
FEATURES_PROVIDED += periph_ecc_p256r1
FEATURES_PROVIDED += periph_ecc_ed25519
endif

ifeq (,$(filter nrf52832%,$(CPU_MODEL)))
Expand Down
6 changes: 6 additions & 0 deletions cpu/nrf52/periph/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ config MODULE_PERIPH_ECC_P256R1
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_P256

config MODULE_PERIPH_ECC_ED25519
bool
depends on HAS_PERIPH_ECC_ED25519
select MODULE_PERIPH_CRYPTOCELL_310
select MODULE_PSA_CRYPTOCELL_310_ECC_ED25519

# Hash Related Symbols
config MODULE_PERIPH_HASH_SHA_1
bool
Expand Down
5 changes: 5 additions & 0 deletions cpu/nrf52/periph/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ ifneq (,$(filter periph_ecc_p256r1,$(USEMODULE)))
USEMODULE += psa_cryptocell_310_ecc_p256
endif

ifneq (,$(filter periph_ecc_ed25519,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_ecc_ed25519
endif

ifneq (,$(filter periph_hash_sha_1,$(USEMODULE)))
USEPKG += driver_cryptocell_310
USEMODULE += psa_cryptocell_310_hashes_sha1
Expand Down
11 changes: 8 additions & 3 deletions examples/psa_crypto/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ else
USEMODULE += psa_secure_element_ateccx08a_ecc_p256
else ifdef CUSTOM_BACKEND
# Necessary configuration when using Make dependency resolution
# This first part chooses the operation. If nothing else es specified,
# This first part chooses the operation. If nothing else is specified,
# a default backend is built depending on the platform capabilities.
USEMODULE += psa_cipher
USEMODULE += psa_cipher_aes_128_cbc
Expand All @@ -73,6 +73,7 @@ else

USEMODULE += psa_asymmetric
USEMODULE += psa_asymmetric_ecc_p256r1
USEMODULE += psa_asymmetric_ecc_ed25519

# If you want to use a custom backend, you need to do it this way.
USEMODULE += psa_cipher_aes_128_cbc_custom_backend
Expand All @@ -86,6 +87,9 @@ else

USEMODULE += psa_asymmetric_ecc_p256r1_custom_backend
USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc # force custom backend

USEMODULE += psa_asymmetric_ecc_ed25519_custom_backend
USEMODULE += psa_asymmetric_ecc_ed25519_backend_c25519 # force custom backend
else
# Necessary configuration when using Make dependency resolution
# This part only chooses the operation. If nothing else es specified,
Expand All @@ -98,11 +102,12 @@ else

USEMODULE += psa_asymmetric
USEMODULE += psa_asymmetric_ecc_p256r1
USEMODULE += psa_asymmetric_ecc_ed25519
endif

ifndef SECURE_ELEMENT
CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3
CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=2
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=4
endif
endif

Expand Down
3 changes: 2 additions & 1 deletion examples/psa_crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ This example application is supposed to show two things:
2. How to configure the implementation with Kconfig dependency resolution vs. Make dependency resolution

## Basic usage of PSA Crypto
There are three example operations:
There are four example operations:
- AES 128 CBC
- HMAC SHA256
- ECDSA with a P256 curve
- EdDSA with the Ed25519 curve

Each comes in its own sourcefile called `example_<operation>.c`. To see which functions to call to perform each operations, please read the code.

Expand Down
5 changes: 3 additions & 2 deletions examples/psa_crypto/app.config.test.base
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CONFIG_MODULE_PSA_MAC_HMAC_SHA_256=y

CONFIG_MODULE_PSA_ASYMMETRIC=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_ED25519=y

CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CONFIG_PSA_SINGLE_KEY_COUNT=3
CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=2
CONFIG_PSA_SINGLE_KEY_COUNT=4
5 changes: 3 additions & 2 deletions examples/psa_crypto/app.config.test.custom
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CONFIG_MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT=y
CONFIG_MODULE_PSA_HASH_SHA_256_BACKEND_RIOT=y
CONFIG_MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC=y
CONFIG_MODULE_PSA_ASYMMETRIC_ECC_ED25519_BACKEND_C25519=y

CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
CONFIG_PSA_SINGLE_KEY_COUNT=3
CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=2
CONFIG_PSA_SINGLE_KEY_COUNT=4
68 changes: 30 additions & 38 deletions examples/psa_crypto/example_ecdsa_p256.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
#include "psa/crypto.h"

#define ECDSA_MESSAGE_SIZE (127)

#define ECC_KEY_SIZE (256)
#define ECC_KEY_TYPE (PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1))
#define ECC_ALG_HASH (PSA_ALG_SHA_256)
#define ECC_ALG (PSA_ALG_ECDSA(ECC_ALG_HASH))

/**
* @brief Example function to perform an ECDSA operation with a NIST P256 curve
Expand All @@ -39,26 +43,19 @@ psa_status_t example_ecdsa_p256(void)
psa_key_attributes_t pubkey_attr = psa_key_attributes_init();

psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH;
psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
psa_key_bits_t bits = ECC_KEY_SIZE;
uint8_t bytes =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits);

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1),
ECC_KEY_SIZE)] = { 0 };

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)];
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE, ECC_ALG)];
size_t sig_length;
uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b };
uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
uint8_t hash[PSA_HASH_LENGTH(ECC_ALG_HASH)];
size_t hash_length;

psa_set_key_algorithm(&privkey_attr, alg);
psa_set_key_algorithm(&privkey_attr, ECC_ALG);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, type);
psa_set_key_bits(&privkey_attr, bits);
psa_set_key_type(&privkey_attr, ECC_KEY_TYPE);
psa_set_key_bits(&privkey_attr, ECC_KEY_SIZE);

#ifdef SECURE_ELEMENT
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
Expand All @@ -78,31 +75,32 @@ psa_status_t example_ecdsa_p256(void)
return status;
}

status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
status = psa_hash_compute(ECC_ALG_HASH, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
return status;
}

#ifdef SECURE_ELEMENT
psa_set_key_lifetime(&pubkey_attr, lifetime);
#endif
psa_set_key_algorithm(&pubkey_attr, alg);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes));
psa_set_key_algorithm(&pubkey_attr, ECC_ALG);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(pubkey_length));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));

status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature),
status = psa_sign_hash(privkey_id, ECC_ALG, hash, sizeof(hash), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}

return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length);
/* verify on original message with internal hashing operation */
return psa_verify_message(pubkey_id, ECC_ALG, msg, sizeof(msg), signature, sig_length);
}

#ifdef MULTIPLE_SE
Expand All @@ -116,27 +114,21 @@ psa_status_t example_ecdsa_p256_sec_se(void)
psa_key_lifetime_t lifetime = PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(
PSA_KEY_LIFETIME_VOLATILE, PSA_ATCA_LOCATION_DEV1);
psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH;
psa_key_type_t type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_algorithm_t alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256);
psa_key_bits_t bits = 256;
uint8_t bytes =
PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1), bits);

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(PSA_KEY_TYPE_ECC_KEY_PAIR(
PSA_ECC_FAMILY_SECP_R1), 256)] = { 0 };

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;

uint8_t signature[PSA_SIGN_OUTPUT_SIZE(type, bits, alg)];
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE, ECC_ALG)];
size_t sig_length;
uint8_t msg[ECDSA_MESSAGE_SIZE] = { 0x0b };
uint8_t hash[PSA_HASH_LENGTH(PSA_ALG_SHA_256)];
uint8_t hash[PSA_HASH_LENGTH(ECC_ALG_HASH)];
size_t hash_length;

psa_set_key_lifetime(&privkey_attr, lifetime);
psa_set_key_algorithm(&privkey_attr, alg);
psa_set_key_algorithm(&privkey_attr, ECC_ALG);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, type);
psa_set_key_bits(&privkey_attr, bits);
psa_set_key_type(&privkey_attr, ECC_KEY_TYPE);
psa_set_key_bits(&privkey_attr, ECC_KEY_SIZE);

psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;

Expand All @@ -150,28 +142,28 @@ psa_status_t example_ecdsa_p256_sec_se(void)
return status;
}

status = psa_hash_compute(PSA_ALG_SHA_256, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
status = psa_hash_compute(ECC_ALG_HASH, msg, sizeof(msg), hash, sizeof(hash), &hash_length);
if (status != PSA_SUCCESS) {
return status;
}

psa_set_key_lifetime(&pubkey_attr, lifetime);
psa_set_key_algorithm(&pubkey_attr, alg);
psa_set_key_algorithm(&pubkey_attr, ECC_ALG);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(bytes));
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(pubkey_length));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));

status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_sign_hash(privkey_id, alg, hash, sizeof(hash), signature, sizeof(signature),
status = psa_sign_hash(privkey_id, ECC_ALG, hash, sizeof(hash), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}

return psa_verify_hash(pubkey_id, alg, hash, sizeof(hash), signature, sig_length);
return psa_verify_hash(pubkey_id, ECC_ALG, hash, sizeof(hash), signature, sig_length);
}
#endif
83 changes: 83 additions & 0 deletions examples/psa_crypto/example_eddsa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2023 TU Dresden
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup examples
* @{
*
* @brief Example functions for EdDSA with PSA Crypto
*
* @author Mikolai Gütschow <[email protected]>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>

#include "psa/crypto.h"

#define EDDSA_MESSAGE_SIZE (127)

#define ECC_KEY_SIZE (255)
#define ECC_KEY_TYPE (PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS))
#define ECC_ALG (PSA_ALG_PURE_EDDSA)

/**
* @brief Example function to perform an EdDSA operation with the twisted Edwards curve Edwards25519
* with the PSA Crypto API.
*/
psa_status_t example_eddsa(void)
{
psa_key_id_t privkey_id;
psa_key_attributes_t privkey_attr = psa_key_attributes_init();
psa_key_id_t pubkey_id;
psa_key_attributes_t pubkey_attr = psa_key_attributes_init();

psa_key_usage_t usage = PSA_KEY_USAGE_SIGN_MESSAGE | PSA_KEY_USAGE_VERIFY_MESSAGE;

uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE)] = { 0 };
size_t pubkey_length;
uint8_t signature[PSA_SIGN_OUTPUT_SIZE(ECC_KEY_TYPE, ECC_KEY_SIZE, ECC_ALG)];
size_t sig_length;
uint8_t msg[EDDSA_MESSAGE_SIZE] = { 0x0b };

psa_set_key_algorithm(&privkey_attr, ECC_ALG);
psa_set_key_usage_flags(&privkey_attr, usage);
psa_set_key_type(&privkey_attr, ECC_KEY_TYPE);
psa_set_key_bits(&privkey_attr, ECC_KEY_SIZE);

psa_status_t status = PSA_ERROR_DOES_NOT_EXIST;

status = psa_generate_key(&privkey_attr, &privkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_export_public_key(privkey_id, public_key, sizeof(public_key), &pubkey_length);
if (status != PSA_SUCCESS) {
return status;
}

psa_set_key_algorithm(&pubkey_attr, ECC_ALG);
psa_set_key_usage_flags(&pubkey_attr, PSA_KEY_USAGE_VERIFY_MESSAGE);
psa_set_key_bits(&pubkey_attr, PSA_BYTES_TO_BITS(pubkey_length));
psa_set_key_type(&pubkey_attr, PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(ECC_KEY_TYPE));

status = psa_import_key(&pubkey_attr, public_key, pubkey_length, &pubkey_id);
if (status != PSA_SUCCESS) {
return status;
}

status = psa_sign_message(privkey_id, ECC_ALG, msg, sizeof(msg), signature, sizeof(signature),
&sig_length);
if (status != PSA_SUCCESS) {
return status;
}

return psa_verify_message(pubkey_id, ECC_ALG, msg, sizeof(msg), signature, sig_length);
}
8 changes: 8 additions & 0 deletions examples/psa_crypto/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
extern psa_status_t example_cipher_aes_128(void);
extern psa_status_t example_hmac_sha256(void);
extern psa_status_t example_ecdsa_p256(void);
extern psa_status_t example_eddsa(void);

#ifdef MULTIPLE_SE
extern psa_status_t example_cipher_aes_128_sec_se(void);
Expand Down Expand Up @@ -60,6 +61,13 @@ int main(void)
printf("ECDSA failed: %s\n", psa_status_to_humanly_readable(status));
}

start = ztimer_now(ZTIMER_USEC);
status = example_eddsa();
printf("EdDSA took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start));
if (status != PSA_SUCCESS) {
printf("EdDSA failed: %s\n", psa_status_to_humanly_readable(status));
}

#ifdef MULTIPLE_SE
puts("Running Examples with secondary SE:");
status = example_hmac_sha256_sec_se();
Expand Down
5 changes: 5 additions & 0 deletions kconfigs/Kconfig.features
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ config HAS_PERIPH_ECC_P256R1
help
Indicates that there is ECC P256R1 hardware acceleration peripheral present.

config HAS_PERIPH_ECC_ED25519
bool
help
Indicates that there is ECC Edwards25519 hardware acceleration peripheral present.

config HAS_PERIPH_EEPROM
bool
help
Expand Down
1 change: 1 addition & 0 deletions makefiles/features_modules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ PERIPH_IGNORE_MODULES := \
periph_cryptocell_310 \
periph_ecc_p192r1 \
periph_ecc_p256r1 \
periph_ecc_ed25519 \
periph_eth \
periph_eth_common \
periph_flash \
Expand Down
Loading