From b9396c4739ded7c91b098613073c75921a6692f4 Mon Sep 17 00:00:00 2001 From: Wunderbaeumchen Date: Tue, 23 Jul 2024 17:11:34 +0200 Subject: [PATCH] sys/psa_crypto: chacha20 oneshot gluecode --- cpu/nrf52/Makefile.features | 1 + cpu/nrf52/periph/Makefile.dep | 5 + features.yaml | 2 + makefiles/features_existing.inc.mk | 1 + makefiles/features_modules.inc.mk | 1 + makefiles/pseudomodules.inc.mk | 1 + pkg/driver_cryptocell_310/Makefile.include | 1 + .../include/cryptocell_310_util.h | 4 + pkg/driver_cryptocell_310/include/psa_error.h | 1 + .../psa_cryptocell_310/cipher_chacha20.c | 135 ++++++++++++++++++ .../psa_cryptocell_310/error_conversion.c | 33 +++++ sys/crypto/chacha20poly1305.c | 19 ++- sys/crypto/psa_riot_cipher/chacha20.c | 84 +++++++++++ sys/include/crypto/chacha20poly1305.h | 15 ++ sys/include/psa_crypto/psa/crypto_sizes.h | 8 +- sys/psa_crypto/Makefile.dep | 24 ++++ sys/psa_crypto/Makefile.include | 12 ++ sys/psa_crypto/doc.txt | 6 + sys/psa_crypto/include/psa_ciphers.h | 51 +++++++ .../include/psa_crypto_operation_encoder.h | 119 +++++++++++---- sys/psa_crypto/psa_crypto.c | 6 +- .../psa_crypto_algorithm_dispatch.c | 76 ++++++---- tests/sys/psa_crypto_cipher/Makefile | 1 + .../example_cipher_aes_128.c | 3 + .../example_cipher_chacha20.c | 83 +++++++++++ tests/sys/psa_crypto_cipher/main.c | 9 ++ 26 files changed, 637 insertions(+), 64 deletions(-) create mode 100644 pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c create mode 100644 sys/crypto/psa_riot_cipher/chacha20.c create mode 100644 tests/sys/psa_crypto_cipher/example_cipher_chacha20.c diff --git a/cpu/nrf52/Makefile.features b/cpu/nrf52/Makefile.features index 70e56f6b32..2e1817d29d 100644 --- a/cpu/nrf52/Makefile.features +++ b/cpu/nrf52/Makefile.features @@ -20,6 +20,7 @@ ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL))) FEATURES_PROVIDED += periph_hash_sha_512 FEATURES_PROVIDED += periph_hmac_sha_256 FEATURES_PROVIDED += periph_cipher_aes_128_cbc + FEATURES_PROVIDED += periph_cipher_chacha20 FEATURES_PROVIDED += periph_ecc_p192r1 FEATURES_PROVIDED += periph_ecc_p256r1 FEATURES_PROVIDED += periph_ecc_ed25519 diff --git a/cpu/nrf52/periph/Makefile.dep b/cpu/nrf52/periph/Makefile.dep index 0eb51e479f..d60cc5e393 100644 --- a/cpu/nrf52/periph/Makefile.dep +++ b/cpu/nrf52/periph/Makefile.dep @@ -38,6 +38,11 @@ ifneq (,$(filter periph_cipher_aes_128_cbc,$(USEMODULE))) USEMODULE += psa_cryptocell_310_aes_cbc endif +ifneq (,$(filter periph_cipher_chacha20,$(USEMODULE))) + USEPKG += driver_cryptocell_310 + USEMODULE += psa_cryptocell_310_cipher_chacha20 +endif + ifneq (,$(filter periph_hmac_sha_256,$(USEMODULE))) USEPKG += driver_cryptocell_310 USEMODULE += psa_cryptocell_310_hmac diff --git a/features.yaml b/features.yaml index 4013f303d6..d6e0f6432c 100644 --- a/features.yaml +++ b/features.yaml @@ -851,6 +851,8 @@ groups: help: A Hardware Random Number Generator (HWRNG) peripheral is present. - name: periph_cipher_aes_128_cbc help: AES 128 CBC hardware acceleration present + - name: periph_cipher_chacha20 + help: ChaCha20 hardware acceleration present - name: periph_ecc_p192r1 help: ECC P192R1 hardware acceleration peripheral present. - name: periph_ecc_p256r1 diff --git a/makefiles/features_existing.inc.mk b/makefiles/features_existing.inc.mk index 79c055c6fc..cb130f1c9b 100644 --- a/makefiles/features_existing.inc.mk +++ b/makefiles/features_existing.inc.mk @@ -139,6 +139,7 @@ FEATURES_EXISTING := \ periph_adc_continuous \ periph_can \ periph_cipher_aes_128_cbc \ + periph_cipher_chacha20 \ periph_clic \ periph_coretimer \ periph_cpuid \ diff --git a/makefiles/features_modules.inc.mk b/makefiles/features_modules.inc.mk index df45d4ef47..2a81c5e285 100644 --- a/makefiles/features_modules.inc.mk +++ b/makefiles/features_modules.inc.mk @@ -12,6 +12,7 @@ USEMODULE += $(PERIPH_FEATURES) # Add all USED periph_% init modules unless they are blacklisted PERIPH_IGNORE_MODULES := \ periph_cipher_aes_128_cbc \ + periph_cipher_chacha20 \ periph_clic \ periph_common \ periph_coretimer \ diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index fb28302282..af658f9f08 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -357,6 +357,7 @@ PSEUDOMODULES += psa_riot_cipher_aes_128_ecb PSEUDOMODULES += psa_riot_cipher_aes_128_cbc PSEUDOMODULES += psa_riot_cipher_aes_192_cbc PSEUDOMODULES += psa_riot_cipher_aes_256_cbc +PSEUDOMODULES += psa_riot_cipher_chacha20 PSEUDOMODULES += psa_riot_hashes_md5 PSEUDOMODULES += psa_riot_hashes_sha_1 PSEUDOMODULES += psa_riot_hashes_sha_224 diff --git a/pkg/driver_cryptocell_310/Makefile.include b/pkg/driver_cryptocell_310/Makefile.include index 2f32616198..a6424efe04 100644 --- a/pkg/driver_cryptocell_310/Makefile.include +++ b/pkg/driver_cryptocell_310/Makefile.include @@ -13,6 +13,7 @@ CFLAGS += -Wno-cast-align PSEUDOMODULES += psa_cryptocell_310_aes_cbc PSEUDOMODULES += psa_cryptocell_310_aes_common +PSEUDOMODULES += psa_cryptocell_310_cipher_chacha20 PSEUDOMODULES += psa_cryptocell_310_ecc_common PSEUDOMODULES += psa_cryptocell_310_ecc_p192 PSEUDOMODULES += psa_cryptocell_310_ecc_p256 diff --git a/pkg/driver_cryptocell_310/include/cryptocell_310_util.h b/pkg/driver_cryptocell_310/include/cryptocell_310_util.h index 4040eb8f13..540617ee08 100644 --- a/pkg/driver_cryptocell_310/include/cryptocell_310_util.h +++ b/pkg/driver_cryptocell_310/include/cryptocell_310_util.h @@ -23,6 +23,10 @@ extern "C" { #endif +#ifdef CPU_NRF52 +#define CHECK_POINTER_DMA_ACCESS(p) ((unsigned int)p >= 0x20000000 ? (unsigned int)p < 0x40000000 : 0) +#endif + /** * @brief Enable CryptoCell module and IRQs. * diff --git a/pkg/driver_cryptocell_310/include/psa_error.h b/pkg/driver_cryptocell_310/include/psa_error.h index 343f31973c..cb522406c5 100644 --- a/pkg/driver_cryptocell_310/include/psa_error.h +++ b/pkg/driver_cryptocell_310/include/psa_error.h @@ -28,6 +28,7 @@ extern "C" { #include "crys_ec_mont_edw_error.h" #include "crys_hash_error.h" #include "ssi_aes_error.h" +#include "crys_chacha_error.h" /** * @brief Convert CryptoCell CRYS errors to PSA status values diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c new file mode 100644 index 0000000000..58e35321fc --- /dev/null +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2024 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 pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief PSA Crypto wrapper for the CryptoCell 310 ChaCha API. + * + * @author Lennard Melling + * + */ +#ifndef PSA_CRYPTOCELL_310_CHACHA_H +#define PSA_CRYPTOCELL_310_CHACHA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psa/crypto.h" +#include "crys_chacha.h" +#include "cryptocell_310_util.h" +#include "psa_error.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +psa_status_t psa_cipher_chacha20_encrypt(uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("Peripheral ChaCha20 Cipher encryption"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!CHECK_POINTER_DMA_ACCESS(key_buffer) || + !CHECK_POINTER_DMA_ACCESS(input) || + !CHECK_POINTER_DMA_ACCESS(output)) { + return PSA_ERROR_DATA_INVALID; + } + + if (output_size < (input_length + CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if (key_buffer_size != CRYS_CHACHA_KEY_MAX_SIZE_IN_BYTES) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + uint8_t *nonce = &output[0]; + uint8_t *data_out = &output[CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES]; + status = psa_generate_random(nonce, CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES); + if (status != PSA_SUCCESS) { + return status; + } + + cryptocell_310_enable(); + CRYSError_t periph_status = CRYS_CHACHA(nonce, CRYS_CHACHA_Nonce96BitSize, + key_buffer, 0UL, + CRYS_CHACHA_Encrypt, + (uint8_t *) input, + input_length, + data_out); + cryptocell_310_disable(); + status = CRYS_to_psa_error(periph_status); + if (status != PSA_SUCCESS) { + return status; + } + + *output_length = input_length + CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES; + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_chacha20_decrypt(uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("Peripheral ChaCha20 Cipher decryption"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!CHECK_POINTER_DMA_ACCESS(key_buffer) || + !CHECK_POINTER_DMA_ACCESS(input) || + !CHECK_POINTER_DMA_ACCESS(output)) { + return PSA_ERROR_DATA_INVALID; + } + + if ((key_buffer_size != CRYS_CHACHA_KEY_MAX_SIZE_IN_BYTES) || + (input_length < CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (output_size < (input_length - CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + const uint8_t *nonce = &input[0]; + const uint8_t *data_in = &input[CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES]; + size_t data_size = input_length - CRYS_CHACHA_NONCE_MAX_SIZE_IN_BYTES; + + cryptocell_310_enable(); + CRYSError_t periph_status = CRYS_CHACHA((uint8_t *)nonce, CRYS_CHACHA_Nonce96BitSize, + key_buffer, 0UL, + CRYS_CHACHA_Decrypt, + (uint8_t *)data_in, + data_size, + output); + cryptocell_310_disable(); + status = CRYS_to_psa_error(periph_status); + if (status != PSA_SUCCESS) { + return status; + } + + *output_length = data_size; + return PSA_SUCCESS; +} + +#ifdef __cplusplus +} +#endif + +#endif /* PSA_CRYPTOCELL_310_CHACHA_H */ +/** @} */ diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c index a470566120..334bd4c479 100644 --- a/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c @@ -27,12 +27,23 @@ psa_status_t CRYS_to_psa_error(CRYSError_t error) return PSA_SUCCESS; case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR: case CRYS_HASH_IS_NOT_SUPPORTED: + case CRYS_CHACHA_IS_NOT_SUPPORTED: return PSA_ERROR_NOT_SUPPORTED; case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR: return PSA_ERROR_CORRUPTION_DETECTED; case CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR: case CRYS_ECEDW_SIGN_VERIFY_FAILED_ERROR: return PSA_ERROR_INVALID_SIGNATURE; + case CRYS_CHACHA_CTX_SIZES_ERROR: + case CRYS_CHACHA_DATA_IN_POINTER_INVALID_ERROR: + case CRYS_CHACHA_DATA_IN_SIZE_ILLEGAL: + case CRYS_CHACHA_DATA_OUT_POINTER_INVALID_ERROR: + case CRYS_CHACHA_ILLEGAL_KEY_SIZE_ERROR: + case CRYS_CHACHA_INVALID_ENCRYPT_MODE_ERROR: + case CRYS_CHACHA_INVALID_KEY_POINTER_ERROR: + case CRYS_CHACHA_INVALID_NONCE_ERROR: + case CRYS_CHACHA_INVALID_NONCE_PTR_ERROR: + case CRYS_CHACHA_INVALID_USER_CONTEXT_POINTER_ERROR: case CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR: case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR: case CRYS_ECDSA_VERIFY_USER_CONTEXT_VALIDATION_TAG_ERROR: @@ -453,6 +464,28 @@ const char *cryptocell310_status_to_humanly_readable(uint32_t status) return "CRYS_ECMONT_IS_NOT_SUPPORTED"; case CRYS_ECEDW_IS_NOT_SUPPORTED: return "CRYS_ECEDW_IS_NOT_SUPPORTED"; + case CRYS_CHACHA_CTX_SIZES_ERROR: + return "CRYS_CHACHA_CTX_SIZES_ERROR"; + case CRYS_CHACHA_DATA_IN_POINTER_INVALID_ERROR: + return "CRYS_CHACHA_DATA_IN_POINTER_INVALID_ERROR"; + case CRYS_CHACHA_DATA_IN_SIZE_ILLEGAL: + return "CRYS_CHACHA_DATA_IN_SIZE_ILLEGAL"; + case CRYS_CHACHA_DATA_OUT_POINTER_INVALID_ERROR: + return "CRYS_CHACHA_DATA_OUT_POINTER_INVALID_ERROR"; + case CRYS_CHACHA_ILLEGAL_KEY_SIZE_ERROR: + return "CRYS_CHACHA_ILLEGAL_KEY_SIZE_ERROR"; + case CRYS_CHACHA_INVALID_ENCRYPT_MODE_ERROR: + return "CRYS_CHACHA_INVALID_ENCRYPT_MODE_ERROR"; + case CRYS_CHACHA_INVALID_KEY_POINTER_ERROR: + return "CRYS_CHACHA_INVALID_KEY_POINTER_ERROR"; + case CRYS_CHACHA_INVALID_NONCE_ERROR: + return "CRYS_CHACHA_INVALID_NONCE_ERROR"; + case CRYS_CHACHA_INVALID_NONCE_PTR_ERROR: + return "CRYS_CHACHA_INVALID_NONCE_PTR_ERROR"; + case CRYS_CHACHA_INVALID_USER_CONTEXT_POINTER_ERROR: + return "CRYS_CHACHA_INVALID_USER_CONTEXT_POINTER_ERROR"; + case CRYS_CHACHA_IS_NOT_SUPPORTED: + return "CRYS_CHACHA_IS_NOT_SUPPORTED"; default: return "Error value not recognized"; } diff --git a/sys/crypto/chacha20poly1305.c b/sys/crypto/chacha20poly1305.c index 0491a3950b..9274076ad7 100644 --- a/sys/crypto/chacha20poly1305.c +++ b/sys/crypto/chacha20poly1305.c @@ -89,21 +89,22 @@ static void _keystream(chacha20poly1305_ctx_t *ctx, const uint8_t *key, } static void _xcrypt(chacha20poly1305_ctx_t *ctx, const uint8_t *key, - const uint8_t *nonce, const uint8_t *in, uint8_t *out, size_t len) + const uint8_t *nonce, const uint8_t *in, uint8_t *out, + size_t len, size_t counter) { /* Number of full 64 byte blocks */ const size_t num_blocks = len >> 6; size_t pos = 0; /* xcrypt full blocks */ for (size_t i = 0; i < num_blocks; i++, pos += 64) { - _keystream(ctx, key, nonce, i+1); + _keystream(ctx, key, nonce, i + counter); for (size_t j = 0; j < 64; j++) { out[pos+j] = in[pos+j] ^ ((uint8_t*)ctx->state)[j]; } } /* xcrypt remaining bytes */ if (len - pos) { - _keystream(ctx, key, nonce, num_blocks+1); + _keystream(ctx, key, nonce, num_blocks + counter); for (size_t j = 0; j < len - pos; j++) { out[pos+j] = in[pos+j] ^ ((uint8_t*)ctx->state)[j]; } @@ -142,7 +143,7 @@ void chacha20poly1305_encrypt(uint8_t *cipher, const uint8_t *msg, const uint8_t *key, const uint8_t *nonce) { chacha20poly1305_ctx_t ctx; - _xcrypt(&ctx, key, nonce, msg, cipher, msglen); + _xcrypt(&ctx, key, nonce, msg, cipher, msglen, 1); crypto_secure_wipe(&ctx, sizeof(ctx)); /* Generate tag */ _poly1305_gentag(&cipher[msglen], key, nonce, @@ -164,6 +165,14 @@ int chacha20poly1305_decrypt(const uint8_t *cipher, size_t cipherlen, } chacha20poly1305_ctx_t ctx; /* Number of full blocks */ - _xcrypt(&ctx, key, nonce, cipher, msg, *msglen); + _xcrypt(&ctx, key, nonce, cipher, msg, *msglen, 1); return 1; } + +void chacha20_encrypt_decrypt(const uint8_t *input, uint8_t *output, + const uint8_t *key, const uint8_t *nonce, + size_t inputlen) +{ + chacha20poly1305_ctx_t ctx; + _xcrypt(&ctx, key, nonce, input, output, inputlen, 0); +} diff --git a/sys/crypto/psa_riot_cipher/chacha20.c b/sys/crypto/psa_riot_cipher/chacha20.c new file mode 100644 index 0000000000..bc0c5c7b6e --- /dev/null +++ b/sys/crypto/psa_riot_cipher/chacha20.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 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 sys_psa_crypto + * @{ + * + * @file + * @brief Glue code translating between PSA Crypto and the RIOT ChaCha20 Cipher from the ChaCha20-Poly1305 Cipher module + * + * @author Lennard Melling + * + * @} + */ + +#include "psa/crypto.h" +#include "crypto/chacha20poly1305.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +psa_status_t psa_cipher_chacha20_encrypt(uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("RIOT ChaCha20 Cipher encryption"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (output_size < (input_length + CHACHA20POLY1305_NONCE_BYTES)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if (key_buffer_size != CHACHA20POLY1305_KEY_BYTES) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + uint8_t *nonce = &output[0]; + uint8_t *data_out = &output[CHACHA20POLY1305_NONCE_BYTES]; + status = psa_generate_random(nonce, CHACHA20POLY1305_NONCE_BYTES); + if (status != PSA_SUCCESS) + return status; + + chacha20_encrypt_decrypt(input, data_out, key_buffer, nonce, input_length); + + *output_length = input_length + CHACHA20POLY1305_NONCE_BYTES; + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_chacha20_decrypt(uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("RIOT ChaCha20 Cipher decryption"); + + if ((key_buffer_size != CHACHA20POLY1305_KEY_BYTES) || + (input_length < CHACHA20POLY1305_NONCE_BYTES)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + + if (output_size < (input_length - CHACHA20POLY1305_NONCE_BYTES)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + const uint8_t *nonce = &input[0]; + const uint8_t *data_in = &input[CHACHA20POLY1305_NONCE_BYTES]; + + chacha20_encrypt_decrypt(data_in, output, key_buffer, nonce, input_length - CHACHA20POLY1305_NONCE_BYTES); + *output_length = input_length; + return PSA_SUCCESS; +} diff --git a/sys/include/crypto/chacha20poly1305.h b/sys/include/crypto/chacha20poly1305.h index 25b290e23a..1f6042089c 100644 --- a/sys/include/crypto/chacha20poly1305.h +++ b/sys/include/crypto/chacha20poly1305.h @@ -96,6 +96,21 @@ int chacha20poly1305_decrypt(const uint8_t *cipher, size_t cipherlen, const uint8_t *aad, size_t aadlen, const uint8_t *key, const uint8_t *nonce); +/** + * @brief Encrypt a plaintext to ciphertext with the ChaCha20 algorithm. + * + * @param[in] input Input for the encryption/decryption. + * @param[out] output The resulting encrypted cipher/decrypted message. + * @param[in] key Key to encrypt/decrypt with, must be + * @ref CHACHA20POLY1305_KEY_BYTES long. + * @param[in] nonce Nonce to use. Must be CHACHA20POLY1305_NONCE_BYTES + * long. + * @param[in] inputlen Length of the input byte array. +*/ +void chacha20_encrypt_decrypt(const uint8_t *input, uint8_t *output, + const uint8_t *key, const uint8_t *nonce, + size_t inputlen); + #ifdef __cplusplus } #endif diff --git a/sys/include/psa_crypto/psa/crypto_sizes.h b/sys/include/psa_crypto/psa/crypto_sizes.h index bdcc1be479..e1c32ac8d1 100644 --- a/sys/include/psa_crypto/psa/crypto_sizes.h +++ b/sys/include/psa_crypto/psa/crypto_sizes.h @@ -61,7 +61,8 @@ extern "C" { IS_USED(MODULE_PSA_ASYMMETRIC_ECC_ED25519) || \ IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || \ IS_USED(MODULE_PSA_MAC_HMAC_SHA_256) || \ - IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256)) + IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256) || \ + IS_USED(MODULE_PSA_CIPHER_CHACHA20)) #define CONFIG_PSA_MAX_KEY_SIZE 32 #elif (IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || \ IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)) @@ -591,8 +592,9 @@ extern "C" { * */ #define PSA_CIPHER_IV_LENGTH(key_type, alg) \ - (PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1 && \ - ((alg) == PSA_ALG_CBC_NO_PADDING) ? 16 : 0) + ((PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1 && \ + ((alg) == PSA_ALG_CBC_NO_PADDING)) ? 16 : \ + (key_type == PSA_KEY_TYPE_CHACHA20) ? 12 : 0) /** * @brief A sufficient buffer size for storing the IV generated by @ref psa_cipher_generate_iv(), diff --git a/sys/psa_crypto/Makefile.dep b/sys/psa_crypto/Makefile.dep index cba3fb23c8..3e9f88f366 100644 --- a/sys/psa_crypto/Makefile.dep +++ b/sys/psa_crypto/Makefile.dep @@ -143,6 +143,30 @@ ifneq (,$(filter psa_cipher_aes_192_cbc_backend_riot,$(USEMODULE))) USEMODULE += psa_riot_cipher_aes_192_cbc endif +## ChaCha20 +ifneq (,$(filter psa_cipher_chacha20,$(USEMODULE))) + ifeq (,$(filter psa_cipher_chacha20_custom_backend,$(USEMODULE))) + FEATURES_OPTIONAL += periph_cipher_chacha20 + include $(RIOTMAKE)/features_check.inc.mk + # HACK: Due to kconfig migration, may cause problems + ifneq (,$(filter periph_cipher_chacha20,$(FEATURES_USED))) + USEMODULE += psa_cipher_chacha20_backend_periph + else + USEMODULE += psa_cipher_chacha20_backend_riot + endif + endif +endif + +ifneq (,$(filter psa_cipher_chacha20_backend_periph,$(USEMODULE))) + FEATURES_REQUIRED += periph_cipher_chacha20 +endif + +ifneq (,$(filter psa_cipher_chacha20_backend_riot,$(USEMODULE))) + USEMODULE += crypto + USEMODULE += psa_riot_cipher + USEMODULE += psa_riot_cipher_chacha20 +endif + # Hash ## MD5 diff --git a/sys/psa_crypto/Makefile.include b/sys/psa_crypto/Makefile.include index 2fa1d4aab9..5d8bbaf2ca 100644 --- a/sys/psa_crypto/Makefile.include +++ b/sys/psa_crypto/Makefile.include @@ -85,6 +85,18 @@ ifneq (,$(filter psa_cipher_aes_256_cbc,$(USEMODULE))) endif endif +PSEUDOMODULES += psa_cipher_chacha20 +PSEUDOMODULES += psa_cipher_chacha20_backend_periph +PSEUDOMODULES += psa_cipher_chacha20_backend_riot +PSEUDOMODULES += psa_cipher_chacha20_custom_backend + +# check that one and only one backend has been selected +ifneq (,$(filter psa_cipher_chacha20,$(USEMODULE))) + ifneq (1,$(call backends,psa_cipher_chacha20)) + $(error "One (and only one) backend should be selected for psa_cipher_chacha20") + endif +endif + ## Hash PSEUDOMODULES += psa_hash PSEUDOMODULES += psa_hash_md5 diff --git a/sys/psa_crypto/doc.txt b/sys/psa_crypto/doc.txt index 773f22d893..39994941be 100644 --- a/sys/psa_crypto/doc.txt +++ b/sys/psa_crypto/doc.txt @@ -286,6 +286,12 @@ * - psa_cipher_aes_256_cbc_custom_backend * - psa_cipher_aes_256_cbc_backend_riot * + * #### CHACHA20 + * - psa_cipher_chacha20 + * - psa_cipher_chacha20_backend_periph + * - psa_cipher_chacha20_custom_backend + * - psa_cipher_chacha20_backend_riot + * * ### Hashes * - Base: psa_hash * diff --git a/sys/psa_crypto/include/psa_ciphers.h b/sys/psa_crypto/include/psa_ciphers.h index 65c5601b92..4bc60d6d59 100644 --- a/sys/psa_crypto/include/psa_ciphers.h +++ b/sys/psa_crypto/include/psa_ciphers.h @@ -28,6 +28,7 @@ extern "C" { #include "psa/crypto.h" #include "psa/crypto_contexts.h" +#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) || defined(DOXYGEN) /** * @brief Low level wrapper function to call a driver for an AES 128 CBC encryption. * See @ref psa_cipher_encrypt() @@ -77,7 +78,9 @@ psa_status_t psa_cipher_cbc_aes_128_decrypt(const psa_key_attributes_t *attribut uint8_t *output, size_t output_size, size_t *output_length); +#endif /* MODULE_PSA_CIPHER_AES_128_CBC */ +#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || defined(DOXYGEN) /** * @brief Low level wrapper function to call a driver for an AES 192 CBC encryption. * See @ref psa_cipher_encrypt() @@ -102,7 +105,9 @@ psa_status_t psa_cipher_cbc_aes_192_encrypt(const psa_key_attributes_t *attribut uint8_t *output, size_t output_size, size_t *output_length); +#endif /* MODULE_PSA_CIPHER_AES_192_CBC */ +#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || defined(DOXYGEN) /** * @brief Low level wrapper function to call a driver for an AES 256 CBC encryption. * See @ref psa_cipher_encrypt() @@ -127,7 +132,53 @@ psa_status_t psa_cipher_cbc_aes_256_encrypt(const psa_key_attributes_t *attribut uint8_t *output, size_t output_size, size_t *output_length); +#endif /* MODULE_PSA_CIPHER_AES_256_CBC */ +#if IS_USED(MODULE_PSA_CIPHER_CHACHA20) || defined(DOXYGEN) + +/** + * @brief Low level wrapper function to call a driver for ChaCha20 encryption/decryption. + * See @ref psa_cipher_encrypt(). + * @param key_buffer Buffer containing the Key. + * @param key_buffer_size Size of the key in bytes. Must be 32 bytes. + * @param input Input Buffer containing the message to be encrypted. + * @param input_length Size of input buffer. + * @param output Output buffer containing the generated 12 byte nonce + * followed by the cipher of the input. + * @param output_size Size of output buffer. Must be at least + * (input_length + 12) bytes long. + * @param output_length Actual size of the output (including nonce). +*/ +psa_status_t psa_cipher_chacha20_encrypt(uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Low level wrapper function to call a driver for ChaCha20 decryption. + * See @ref psa_cipher_decrypt(). + * @param key_buffer Buffer containing the Key. + * @param key_buffer_size Size of the key in bytes. Must be 32 bytes long. + * @param input Input buffer containing the 12 byte nonce used in the + * encryption followed by the cipher to be decrypted. + * @param input_length Size of input buffer (including 12 byte nonce). + * @param output Output buffer. + * @param output_size Size of output buffer. Must be at least + * (input_length - 12) bytes long. + * @param output_length Actual size of the output. +*/ +psa_status_t psa_cipher_chacha20_decrypt(uint8_t *key_buffer, + size_t key_buffer_size, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +#endif /* MODULE_PSA_CIPHER_CHACHA20 */ #ifdef __cplusplus } #endif diff --git a/sys/psa_crypto/include/psa_crypto_operation_encoder.h b/sys/psa_crypto/include/psa_crypto_operation_encoder.h index 6ddd7b042e..7dcee3ad64 100644 --- a/sys/psa_crypto/include/psa_crypto_operation_encoder.h +++ b/sys/psa_crypto/include/psa_crypto_operation_encoder.h @@ -45,7 +45,8 @@ typedef enum { PSA_CBC_NO_PAD_AES_128, PSA_CBC_NO_PAD_AES_192, PSA_CBC_NO_PAD_AES_256, - PSA_CBC_PKCS7_AES_256 + PSA_CBC_PKCS7_AES_256, + PSA_STREAM_CIPHER_CHACHA20 } psa_cipher_op_t; /** @@ -109,59 +110,127 @@ typedef enum { PSA_INVALID_OPERATION) /** - * @brief Combine algorithm, and key type with a key size of 128 bits. + * @brief Combine key type and size with a PSA_ALG_CBC_NO_PADDING algorithm * - * @param alg Algorithm of type @ref psa_algorithm_t. - * @param type Key type of type @ref psa_key_type_t + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t * * @return @ref psa_cipher_op_t - * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible */ -#define GET_CIPHER_OPERATION_128(alg, type) \ - (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_128 : \ +#define GET_CBC_NO_PADDING_OPERATION(type, bits) \ + ((type == PSA_KEY_TYPE_AES) ? \ + ((bits == 128) ? PSA_CBC_NO_PAD_AES_128 : \ + (bits == 192) ? PSA_CBC_NO_PAD_AES_192 : \ + (bits == 256) ? PSA_CBC_NO_PAD_AES_256 : \ + PSA_INVALID_OPERATION) : \ PSA_INVALID_OPERATION) /** - * @brief Combine algorithm, and key type with a key size of 192 bits. + * @brief Combine key type and size with a PSA_ALG_CBC_PKCS7 algorithm * - * @param alg Algorithm of type @ref psa_algorithm_t. - * @param type Key type of type @ref psa_key_type_t + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t * * @return @ref psa_cipher_op_t - * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible */ -#define GET_CIPHER_OPERATION_192(alg, type) \ - (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_192 : \ +#define GET_CBC_PKCS7_OPERATION(type, bits) \ + (((alg == PSA_ALG_CBC_PKCS7) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_PKCS7_AES_256 : \ PSA_INVALID_OPERATION) /** - * @brief Combine algorithm, and key type with a key size of 256 bits. + * @brief Combine key type and size with a PSA_ALG_CFB algorithm * - * @param alg Algorithm of type @ref psa_algorithm_t. - * @param type Key type of type @ref psa_key_type_t + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t * * @return @ref psa_cipher_op_t - * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible */ -#define GET_CIPHER_OPERATION_256(alg, type) \ - (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_256 : \ - ((alg == PSA_ALG_CBC_PKCS7) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_PKCS7_AES_256 : \ +#define GET_CFB_OPERATION(type, bits) \ + (PSA_INVALID_OPERATION) + +/** + * @brief Combine key type and size with a PSA_ALG_CTR algorithm + * + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible + */ +#define GET_CTR_OPERATION(type, bits) \ + (PSA_INVALID_OPERATION) + +/** + * @brief Combine key type and size with a PSA_ALG_ECB_NO_PADDING algorithm + * + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible + */ +#define GET_ECB_NO_PADDING_OPERATION(type, bits) \ + (PSA_INVALID_OPERATION) + +/** + * @brief Combine key type and size with a PSA_ALG_OFB algorithm + * + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible + */ +#define GET_OFB_OPERATION(type, bits) \ + (PSA_INVALID_OPERATION) + +/** + * @brief Combine key type and size with a PSA_ALG_STREAM_CIPHER algorithm + * + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible + */ +#define GET_STREAM_CIPHER_OPERATION(type, bits) \ + (((type == PSA_KEY_TYPE_CHACHA20) && (bits == 256)) ? PSA_STREAM_CIPHER_CHACHA20 : \ PSA_INVALID_OPERATION) +/** + * @brief Combine key type and size with a PSA_ALG_XTS algorithm + * + * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t + * + * @return @ref psa_cipher_op_t + * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible + */ +#define GET_XTS_OPERATION(type, bits) \ + (PSA_INVALID_OPERATION) + /** * @brief Map algorithm, key size and type to a specific operation. * * @param alg Algorithm of type @ref psa_algorithm_t. - * @param bits Size of the used key of type @ref psa_key_bits_t * @param type Key type of type @ref psa_key_type_t + * @param bits Size of the used key of type @ref psa_key_bits_t * * @return @ref psa_cipher_op_t * @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible */ -#define PSA_ENCODE_CIPHER_OPERATION(alg, bits, type) \ - ((bits == 128) ? GET_CIPHER_OPERATION_128(alg, type) : \ - (bits == 192) ? GET_CIPHER_OPERATION_192(alg, type) : \ - (bits == 256) ? GET_CIPHER_OPERATION_256(alg, type) : \ +#define PSA_ENCODE_CIPHER_OPERATION(alg, type, bits) \ + ((alg == PSA_ALG_CBC_NO_PADDING) ? GET_CBC_NO_PADDING_OPERATION(type, bits) : \ + (alg == PSA_ALG_CBC_PKCS7) ? GET_CBC_PKCS7_OPERATION(type, bits) : \ + (alg == PSA_ALG_CFB) ? GET_CFB_OPERATION(type, bits) : \ + (alg == PSA_ALG_CTR) ? GET_CTR_OPERATION(type, bits) : \ + (alg == PSA_ALG_ECB_NO_PADDING) ? GET_ECB_NO_PADDING_OPERATION(type, bits) : \ + (alg == PSA_ALG_OFB) ? GET_OFB_OPERATION(type, bits) : \ + (alg == PSA_ALG_STREAM_CIPHER) ? GET_STREAM_CIPHER_OPERATION(type, bits) : \ + (alg == PSA_ALG_XTS) ? GET_XTS_OPERATION(type, bits) : \ PSA_INVALID_OPERATION) #ifdef __cplusplus diff --git a/sys/psa_crypto/psa_crypto.c b/sys/psa_crypto/psa_crypto.c index 90b573840d..21b07ecc05 100644 --- a/sys/psa_crypto/psa_crypto.c +++ b/sys/psa_crypto/psa_crypto.c @@ -1019,6 +1019,11 @@ static psa_status_t psa_validate_unstructured_key_size(psa_key_type_t type, size return PSA_ERROR_INVALID_ARGUMENT; } break; + case PSA_KEY_TYPE_CHACHA20: + if (bits != 256) { + return PSA_ERROR_INVALID_ARGUMENT; + } + break; default: (void)bits; return PSA_ERROR_NOT_SUPPORTED; @@ -1539,7 +1544,6 @@ psa_status_t psa_builtin_import_key(const psa_key_attributes_t *attributes, if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) { *bits = PSA_BYTES_TO_BITS(data_length); - status = psa_validate_unstructured_key_size(type, *bits); if (status != PSA_SUCCESS) { return status; diff --git a/sys/psa_crypto/psa_crypto_algorithm_dispatch.c b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c index eda6360948..8afa065b0d 100644 --- a/sys/psa_crypto/psa_crypto_algorithm_dispatch.c +++ b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c @@ -602,7 +602,8 @@ psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t * size_t output_size, size_t *output_length) { - psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type); + psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->type, attributes->bits); + uint8_t *key_data = NULL; size_t *key_bytes = NULL; @@ -613,21 +614,28 @@ psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t * } switch (op) { -#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) - case PSA_CBC_NO_PAD_AES_128: - return psa_cipher_cbc_aes_128_encrypt(attributes, key_data, *key_bytes, alg, input, + #if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) + case PSA_CBC_NO_PAD_AES_128: + return psa_cipher_cbc_aes_128_encrypt(attributes, key_data, *key_bytes, alg, input, input_length, output, output_size, output_length); -#endif -#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) - case PSA_CBC_NO_PAD_AES_192: - return psa_cipher_cbc_aes_192_encrypt(attributes, key_data, *key_bytes, alg, input, - input_length, output, output_size, output_length); -#endif -#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) - case PSA_CBC_NO_PAD_AES_256: - return psa_cipher_cbc_aes_256_encrypt(attributes, key_data, *key_bytes, alg, input, - input_length, output, output_size, output_length); -#endif + #endif + #if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) + case PSA_CBC_NO_PAD_AES_192: + return psa_cipher_cbc_aes_192_encrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); + #endif + #if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) + case PSA_CBC_NO_PAD_AES_256: + return psa_cipher_cbc_aes_256_encrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); + #endif + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_encrypt(key_data, *key_bytes, + input, input_length, + output, output_size, + output_length); + #endif default: (void)slot; (void)input; @@ -648,7 +656,8 @@ psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t * size_t output_size, size_t *output_length) { - psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type); + psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->type, attributes->bits); + uint8_t *key_data = NULL; size_t *key_bytes = NULL; @@ -659,21 +668,28 @@ psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t * } switch (op) { -#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) - case PSA_CBC_NO_PAD_AES_128: - return psa_cipher_cbc_aes_128_decrypt(attributes, key_data, *key_bytes, alg, input, + #if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) + case PSA_CBC_NO_PAD_AES_128: + return psa_cipher_cbc_aes_128_decrypt(attributes, key_data, *key_bytes, alg, input, input_length, output, output_size, output_length); -#endif -#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) - case PSA_CBC_NO_PAD_AES_192: - return psa_cipher_cbc_aes_192_decrypt(attributes, key_data, *key_bytes, alg, input, - input_length, output, output_size, output_length); -#endif -#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) - case PSA_CBC_NO_PAD_AES_256: - return psa_cipher_cbc_aes_256_decrypt(attributes, key_data, *key_bytes, alg, input, - input_length, output, output_size, output_length); -#endif + #endif + #if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) + case PSA_CBC_NO_PAD_AES_192: + return psa_cipher_cbc_aes_192_decrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); + #endif + #if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) + case PSA_CBC_NO_PAD_AES_256: + return psa_cipher_cbc_aes_256_decrypt(attributes, key_data, *key_bytes, alg, input, + input_length, output, output_size, output_length); + #endif + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_decrypt(key_data, *key_bytes, + input, input_length, + output, output_size, + output_length); + #endif default: (void)slot; (void)input; diff --git a/tests/sys/psa_crypto_cipher/Makefile b/tests/sys/psa_crypto_cipher/Makefile index 59599c4fc7..859b335b63 100644 --- a/tests/sys/psa_crypto_cipher/Makefile +++ b/tests/sys/psa_crypto_cipher/Makefile @@ -6,6 +6,7 @@ USEMODULE += ztimer_usec USEMODULE += psa_crypto USEMODULE += psa_cipher +USEMODULE += psa_cipher_chacha20 USEMODULE += psa_cipher_aes_128_cbc CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1 diff --git a/tests/sys/psa_crypto_cipher/example_cipher_aes_128.c b/tests/sys/psa_crypto_cipher/example_cipher_aes_128.c index 058d95967b..41da3a8f4f 100644 --- a/tests/sys/psa_crypto_cipher/example_cipher_aes_128.c +++ b/tests/sys/psa_crypto_cipher/example_cipher_aes_128.c @@ -67,17 +67,20 @@ psa_status_t example_cipher_aes_128(void) status = psa_import_key(&attr, KEY_128, AES_128_KEY_SIZE, &key_id); if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); return status; } status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len); if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); return status; } status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out, sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len); + psa_destroy_key(key_id); if (status == PSA_SUCCESS) { return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0); } diff --git a/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c b/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c new file mode 100644 index 0000000000..8e9fcd65a1 --- /dev/null +++ b/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2024 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 tests + * @{ + * + * @brief Tests the PSA cipher configurations + * Contents have been copied from `examples/psa_crypto` + * + * @author Mikolai Gütschow + * @author Lena Boeckmann + * + * @} + */ + +#include +#include + +#include "psa/crypto.h" + +static const uint8_t KEY_CHACHA20[] = { + 0x90, 0x6f, 0xdc, 0xf1, 0x72, 0xe6, 0x8a, 0xd1, 0xbb, 0xd0, 0xa3, 0x24, + 0x2a, 0xda, 0x91, 0xdb, 0x3a, 0x8d, 0xb8, 0xd4, 0x9a, 0x75, 0xc7, 0x14, + 0x00, 0x08, 0x9a, 0x8b, 0x86, 0x55, 0x2e, 0x9a +}; + +/* This cannot be const, as the Cryptocell hardware implementation does not have + DMA access to flash storage, which contains the global const values */ +static uint8_t PLAINTEXT[] = { + 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x52, 0x49, 0x4F, 0x54, 0x21, 0x20, + 0x54, 0x68, 0x65, 0x20, 0x41, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x20, 0x69, + 0x73, 0x20, 0x34, 0x32, 0x2E +}; + +/** + * @brief Example function to perform an CHACHA20 encryption and decryption + * with the PSA Crypto API. + * + * @return psa_status_t + */ +psa_status_t example_cipher_chacha20(void) +{ + psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; + psa_key_id_t key_id = 0; + psa_key_attributes_t attr = psa_key_attributes_init(); + psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT; + size_t cipher_output_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_CHACHA20, + PSA_ALG_STREAM_CIPHER, sizeof(PLAINTEXT)); + + uint8_t cipher_out[cipher_output_size]; + uint8_t plain_out[sizeof(PLAINTEXT)]; + size_t output_len = 0; + + psa_set_key_algorithm(&attr, PSA_ALG_STREAM_CIPHER); + psa_set_key_usage_flags(&attr, usage); + psa_set_key_bits(&attr, 256); + psa_set_key_type(&attr, PSA_KEY_TYPE_CHACHA20); + + status = psa_import_key(&attr, KEY_CHACHA20, sizeof(KEY_CHACHA20), &key_id); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + return status; + } + status = psa_cipher_encrypt(key_id, PSA_ALG_STREAM_CIPHER, PLAINTEXT, + sizeof(PLAINTEXT), cipher_out, cipher_output_size, &output_len); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + return status; + } + status = psa_cipher_decrypt(key_id, PSA_ALG_STREAM_CIPHER, cipher_out, + sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len); + psa_destroy_key(key_id); + if (status == PSA_SUCCESS) { + return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0); + } + return status; +} diff --git a/tests/sys/psa_crypto_cipher/main.c b/tests/sys/psa_crypto_cipher/main.c index acb7809962..5a204a2f95 100644 --- a/tests/sys/psa_crypto_cipher/main.c +++ b/tests/sys/psa_crypto_cipher/main.c @@ -23,6 +23,7 @@ #include "ztimer.h" extern psa_status_t example_cipher_aes_128(void); +extern psa_status_t example_cipher_chacha20(void); int main(void) { @@ -42,6 +43,14 @@ int main(void) printf("Cipher AES 128 failed: %s\n", psa_status_to_humanly_readable(status)); } + start = ztimer_now(ZTIMER_USEC); + status = example_cipher_chacha20(); + printf("Cipher CHACHA20 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + if (status != PSA_SUCCESS) { + failed = true; + printf("Cipher CHACHA20 failed: %s\n", psa_status_to_humanly_readable(status)); + } + ztimer_release(ZTIMER_USEC); if (failed) {