diff --git a/pkg/driver_cryptocell_310/include/cryptocell_310_util.h b/pkg/driver_cryptocell_310/include/cryptocell_310_util.h index 7493445f864c..0ffbbd4a57be 100644 --- a/pkg/driver_cryptocell_310/include/cryptocell_310_util.h +++ b/pkg/driver_cryptocell_310/include/cryptocell_310_util.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -23,6 +20,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 1bde0060c4b6..cc56c75ea04f 100644 --- a/pkg/driver_cryptocell_310/include/psa_error.h +++ b/pkg/driver_cryptocell_310/include/psa_error.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once diff --git a/pkg/driver_cryptocell_310/include/psa_periph_chacha20_ctx.h b/pkg/driver_cryptocell_310/include/psa_periph_chacha20_ctx.h new file mode 100644 index 000000000000..e36eae679014 --- /dev/null +++ b/pkg/driver_cryptocell_310/include/psa_periph_chacha20_ctx.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2024 TU Dresden + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup pkg_driver_cryptocell_310 + * @{ + * + * @file + * @brief CryptoCell 310 driver specific ChaCha20 contexts + * + * @author Lennard Melling + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "crys_chacha.h" +#include "kernel_defines.h" + +#if IS_USED(MODULE_PERIPH_CIPHER_CHACHA20) || DOXYGEN +/** + * @brief This struct is used to handle the discontinuity between the PSA API + * and the CRYS ChaCha20 API. The PSA API psa_cipher_update() function allows any size + * of input array, but the CRYS implementation only works on multiples of 64B. + * So we store any remainders from the input in the buffer, and if any more data + * is input, we join them with the buffer values. The psa_cipher_finish() function + * will then xcrypt the remaining buffer values. + * The buffer is also used in the setup of the operation. The psa_cipher_~_setup() + * functions only provide the key for the operation, but the CRYS ChaCha20 + * implementation also needs the counter and nonce provided by psa_cipher_set_iv(). + * So we store the key in the buffer until it is needed in the CRYS ChaCha20 setup. + */ +typedef struct { + uint8_t buffer[CRYS_CHACHA_BLOCK_SIZE_IN_BYTES]; /**< Block buffer */ + uint8_t buffer_length; /**< Current length of the data in buffer */ + union { + CRYS_CHACHA_EncryptMode_t mode; /**< Mode of the operation */ + CRYS_CHACHAUserContext_t post_setup; /**< Context of the CRYS ChaCha20 operation */ + } ctx; /**< Context Setup values */ +} psa_cipher_chacha20_ctx_t; + +#endif + +#ifdef __cplusplus +} +#endif +/** @} */ diff --git a/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c b/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c index c86aae73830c..f75512773726 100644 --- a/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c @@ -1,9 +1,6 @@ /* - * 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. + * SPDX-FileCopyrightText: 2024 TU Dresden + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -23,14 +20,192 @@ extern "C" { #endif -#include "psa/crypto.h" +#include "unaligned.h" #include "crys_chacha.h" #include "cryptocell_310_util.h" #include "psa_error.h" +#include "string_utils.h" #define ENABLE_DEBUG 0 #include "debug.h" +static psa_status_t _setup(psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length, + CRYS_CHACHA_EncryptMode_t mode) +{ + DEBUG("Peripheral ChaCha20 Cipher setup"); + + if (key_length != CRYS_CHACHA_KEY_MAX_SIZE_IN_BYTES) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + ctx->buffer_length = 0; + memset(ctx->buffer, 0, sizeof(ctx->buffer)); + /* Copy keydata into buffer for setup in psa_cipher_chacha20_set_iv() */ + memcpy(ctx->buffer, key_data, key_length); + ctx->ctx.mode = mode; + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_chacha20_encrypt_setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length) +{ + return _setup(ctx, key_data, key_length, CRYS_CHACHA_Encrypt); +} + +psa_status_t psa_cipher_chacha20_decrypt_setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length) +{ + return _setup(ctx, key_data, key_length, CRYS_CHACHA_Decrypt); +} + +psa_status_t psa_cipher_chacha20_set_iv(psa_cipher_chacha20_ctx_t *ctx, + const uint8_t *iv, + size_t iv_length) +{ + DEBUG("Peripheral ChaCha20 Cipher set IV"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + CRYSError_t periph_status = CRYS_CHACHA_GENERAL_ERROR; + + /* See PSA Specification */ + switch (iv_length) { + case 8: + /* 8 bytes: the cipher operation uses the original [CHACHA20] definition + of ChaCha20: the provided IV is used as the 64-bit nonce, and the 64-bit + counter value is set to zero. */ + status = PSA_ERROR_NOT_SUPPORTED; + break; + case 12: + /* 12 bytes: the provided IV is used as the nonce, and the counter value + is set to zero. */ + cryptocell_310_enable(); + periph_status = CRYS_CHACHA_Init( &ctx->ctx.post_setup, + (uint8_t*)iv, + CRYS_CHACHA_Nonce96BitSize, + ctx->buffer, + 0, + ctx->ctx.mode); + cryptocell_310_disable(); + status = CRYS_to_psa_error(periph_status); + break; + case 16: + /* 16 bytes: the first four bytes of the IV are used as the counter value + (encoded as little-endian), and the remaining 12 bytes are used as the nonce. */ + periph_status = CRYS_CHACHA_Init( &ctx->ctx.post_setup, + (uint8_t*)&iv[4], + CRYS_CHACHA_Nonce96BitSize, + ctx->buffer, + unaligned_get_u32(iv), + ctx->ctx.mode); + cryptocell_310_disable(); + status = CRYS_to_psa_error(periph_status); + break; + default: + /* It is recommended that implementations do not support other sizes of IV. */ + status = PSA_ERROR_INVALID_ARGUMENT; + } + /* Clear key from buffer */ + explicit_bzero(ctx->buffer, sizeof(ctx->buffer)); + return status; +} + +/* IoT-ToDo: multipart might be wrong */ +psa_status_t psa_cipher_chacha20_update(psa_cipher_chacha20_ctx_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("Peripheral ChaCha20 Cipher update"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + /* We return full blocks, so we check that we have enough output buffer + to fit all full blocks in the combined context and input buffer */ + if (output_size < (((ctx->buffer_length + input_length) / \ + CRYS_CHACHA_BLOCK_SIZE_IN_BYTES) * CRYS_CHACHA_BLOCK_SIZE_IN_BYTES)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + size_t input_index = 0; + size_t output_index = 0; + CRYSError_t periph_status; + /* check if buffer contains data */ + cryptocell_310_enable(); + if (ctx->buffer_length > 0) { + /* if yes, fill buffer up and update this block of data */ + input_index = sizeof(ctx->buffer) - ctx->buffer_length; + memcpy(&ctx->buffer[ctx->buffer_length], input, input_index); + periph_status = CRYS_CHACHA_Block( &ctx->ctx.post_setup, + ctx->buffer, + 64, + output); + status = CRYS_to_psa_error(periph_status); + if (status != PSA_SUCCESS) { + return status; + } + memset(ctx->buffer, 0, sizeof(ctx->buffer)); + ctx->buffer_length = 0; + output_index = 64; + } + /* if not, update blocks of input */ + const uint32_t blocks_length = ((input_length - input_index) / \ + CRYS_CHACHA_BLOCK_SIZE_IN_BYTES) * CRYS_CHACHA_BLOCK_SIZE_IN_BYTES; + /* xcrypt full blocks */ + + /* IoT-TODO: if blocks_length == 0: CRYS_CHACHA_Block returns PSA_INVALID_ARGUMENT (CRYS_CHACHA_DATA_IN_SIZE_ILLEGAL) */ + if(blocks_length > 0) { + periph_status = CRYS_CHACHA_Block( &ctx->ctx.post_setup, + (uint8_t *)&input[input_index], + blocks_length, + &output[output_index]); + status = CRYS_to_psa_error(periph_status); + if (status != PSA_SUCCESS) { + cryptocell_310_disable(); + return status; + } + } + cryptocell_310_disable(); + + /* put remaining data into buffer */ + ctx->buffer_length = input_length - (input_index + blocks_length); + memcpy(ctx->buffer, &input[input_index + blocks_length], ctx->buffer_length); + *output_length = output_index + blocks_length; + + status = PSA_SUCCESS; + return status; +} + +psa_status_t psa_cipher_chacha20_finish(psa_cipher_chacha20_ctx_t *ctx, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("Peripheral ChaCha20 Cipher finish."); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (output_size < ctx->buffer_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* xcrypt remaining bytes */ + cryptocell_310_enable(); + CRYSError_t periph_status = CRYS_CHACHA_Finish( &ctx->ctx.post_setup, + ctx->buffer, + ctx->buffer_length, + output); + cryptocell_310_disable(); + + status = CRYS_to_psa_error(periph_status); + if (status == PSA_SUCCESS) { + *output_length = ctx->buffer_length; + } + return status; +} + psa_status_t psa_cipher_chacha20_encrypt(uint8_t *key_buffer, size_t key_buffer_size, const uint8_t *input, 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 c91bde53ae23..d6d9183879d5 100644 --- a/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c +++ b/pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -222,6 +219,8 @@ psa_status_t SaSi_to_psa_error(SaSiStatus error) const char *cryptocell310_status_to_humanly_readable(uint32_t status) { switch(status) { + case CRYS_OK: + return "CRYS_OK"; case CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR: return "CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR"; case CRYS_ECDSA_SIGN_INVALID_IS_EPHEMER_KEY_INTERNAL_ERROR: diff --git a/sys/crypto/chacha20poly1305.c b/sys/crypto/chacha20poly1305.c index 9274076ad769..cbacb644d96a 100644 --- a/sys/crypto/chacha20poly1305.c +++ b/sys/crypto/chacha20poly1305.c @@ -1,11 +1,8 @@ /* - * Copyright (C) 2008 D. J. Bernstein (dedicated to the public domain) - * Copyright (C) 2015 René Kijewski - * Copyright (C) 2018 Koen Zandberg - * - * 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. + * SPDX-FileCopyrightText: 2008 D. J. Bernstein + * SPDX-FileCopyrightText: 2015 René Kijewski + * SPDX-FileCopyrightText: 2018 Koen Zandberg + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -43,7 +40,9 @@ static const uint32_t constant[] = {0x61707865, /* Padding to add to the poly1305 authentication tag */ static const uint8_t padding[15] = {0}; -/* Single round */ +/** + * @brief Calculates a single round of the ChaCha20 block algorithm on a 32b word. + */ static void _r(uint32_t *a, uint32_t *b, uint32_t *d, unsigned c) { *a += *b; @@ -51,64 +50,58 @@ static void _r(uint32_t *a, uint32_t *b, uint32_t *d, unsigned c) *d = (tmp << c) | (tmp >> (32 - c)); } -static void _add_initial(chacha20poly1305_ctx_t *ctx, const uint8_t *key, +/** + * @brief Initialization function, that initializes the ChaCha20 state with + * the given key, nonce and counter + */ +static void _create_initial(chacha20_ctx_t *ctx, const uint8_t *key, const uint8_t *nonce, uint32_t blk) { for (unsigned i = 0; i < 4; i++) { - ctx->state[i] += constant[i]; + ctx->split.constant[i] = constant[i]; } for (unsigned i = 0; i < 8; i++) { - ctx->state[i+4] += unaligned_get_u32(key + 4*i); + ctx->split.key[i] = unaligned_get_u32(key + 4*i); + } + ctx->split.counter[0] = unaligned_get_u32((uint8_t*)&blk); + ctx->split.nonce[0] = unaligned_get_u32(nonce); + ctx->split.nonce[1] = unaligned_get_u32(nonce+4); + ctx->split.nonce[2] = unaligned_get_u32(nonce+8); +} + +/** + * @brief Does 32bit uint addition of the initial state to the key_stream buffer. + */ +static void _add_initial(chacha20_ctx_t *ctx, uint32_t *key_stream) +{ + for (unsigned i = 0; i < 16; i++) { + key_stream[i] += ctx->words[i]; } - ctx->state[12] += unaligned_get_u32((uint8_t*)&blk); - ctx->state[13] += unaligned_get_u32(nonce); - ctx->state[14] += unaligned_get_u32(nonce+4); - ctx->state[15] += unaligned_get_u32(nonce+8); } -static void _keystream(chacha20poly1305_ctx_t *ctx, const uint8_t *key, - const uint8_t *nonce, uint32_t blk) +/** + * @brief Calculates the ChaCha20 Block function with the given state/context + * and returns it in the key_stream buffer (64B). + */ +static void _keystream(chacha20_ctx_t *ctx, uint32_t *key_stream) { /* Initialize block state */ - memset(ctx->state, 0, sizeof(ctx->state)); - _add_initial(ctx, key, nonce, blk); + memset(key_stream, 0, 16 * 4); + _add_initial(ctx, key_stream); /* perform rounds */ for (unsigned i = 0; i < 80; ++i) { - uint32_t *a = &ctx->state[((i ) & 3) ]; - uint32_t *b = &ctx->state[((i + ((i & 4) ? 1 : 0)) & 3) + (4 * 1)]; - uint32_t *c = &ctx->state[((i + ((i & 4) ? 2 : 0)) & 3) + (4 * 2)]; - uint32_t *d = &ctx->state[((i + ((i & 4) ? 3 : 0)) & 3) + (4 * 3)]; + uint32_t *a = &key_stream[((i ) & 3) ]; + uint32_t *b = &key_stream[((i + ((i & 4) ? 1 : 0)) & 3) + (4 * 1)]; + uint32_t *c = &key_stream[((i + ((i & 4) ? 2 : 0)) & 3) + (4 * 2)]; + uint32_t *d = &key_stream[((i + ((i & 4) ? 3 : 0)) & 3) + (4 * 3)]; _r(a, b, d, 16); _r(c, d, b, 12); _r(a, b, d, 8); _r(c, d, b, 7); } /* add initial state */ - _add_initial(ctx, key, nonce, blk); -} - -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, 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 + 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 + counter); - for (size_t j = 0; j < len - pos; j++) { - out[pos+j] = in[pos+j] ^ ((uint8_t*)ctx->state)[j]; - } - } + _add_initial(ctx, key_stream); } static void _poly1305_padded(poly1305_ctx_t *pctx, const uint8_t *data, size_t len) @@ -125,8 +118,10 @@ static void _poly1305_gentag(uint8_t *mac, const uint8_t *key, const uint8_t *no { chacha20poly1305_ctx_t ctx; /* generate one time key */ - _keystream(&ctx, key, nonce, 0); - poly1305_init(&ctx.poly, (uint8_t*)ctx.state); + _create_initial(&ctx.chacha20, key, nonce, 0); + uint32_t key_stream[16]; + _keystream(&ctx.chacha20, key_stream); + poly1305_init(&ctx.poly, (uint8_t*)key_stream); /* Add aad */ _poly1305_padded(&ctx.poly, aad, aadlen); /* Add ciphertext */ @@ -142,9 +137,7 @@ void chacha20poly1305_encrypt(uint8_t *cipher, const uint8_t *msg, size_t msglen, const uint8_t *aad, size_t aadlen, const uint8_t *key, const uint8_t *nonce) { - chacha20poly1305_ctx_t ctx; - _xcrypt(&ctx, key, nonce, msg, cipher, msglen, 1); - crypto_secure_wipe(&ctx, sizeof(ctx)); + chacha20_encrypt_decrypt(key, nonce, 1, msg, msglen, cipher); /* Generate tag */ _poly1305_gentag(&cipher[msglen], key, nonce, cipher, msglen, aad, aadlen); @@ -163,16 +156,62 @@ int chacha20poly1305_decrypt(const uint8_t *cipher, size_t cipherlen, if (crypto_equals(cipher+*msglen, mac, CHACHA20POLY1305_TAG_BYTES) == 0) { return 0; } - chacha20poly1305_ctx_t ctx; - /* Number of full blocks */ - _xcrypt(&ctx, key, nonce, cipher, msg, *msglen, 1); + chacha20_encrypt_decrypt(key, nonce, 1, cipher, cipherlen, msg); return 1; } -void chacha20_encrypt_decrypt(const uint8_t *input, uint8_t *output, - const uint8_t *key, const uint8_t *nonce, - size_t inputlen) +void chacha20_encrypt_decrypt( const uint8_t *key, + const uint8_t *nonce, + uint32_t counter, + const uint8_t *input, + size_t input_length, + uint8_t *output) { - chacha20poly1305_ctx_t ctx; - _xcrypt(&ctx, key, nonce, input, output, inputlen, 0); + chacha20_ctx_t ctx; + chacha20_setup(&ctx, key, nonce, counter); + const size_t num_blocks = input_length >> 6; + size_t pos = 0; + /* xcrypt full blocks */ + for (size_t i = 0; i < num_blocks; i++, pos += 64) { + chacha20_update(&ctx, &input[pos], &output[pos]); + } + /* xcrypt remaining bytes */ + if (input_length - pos) { + chacha20_finish(&ctx, &input[pos], input_length - pos, &output[pos]); + } +} + +void chacha20_setup(chacha20_ctx_t *ctx, + const uint8_t *key, + const uint8_t *nonce, + const uint32_t counter) +{ + _create_initial(ctx, key, nonce, counter); +} + +void chacha20_update( chacha20_ctx_t *ctx, + const uint8_t *input, + uint8_t *output) +{ + + uint32_t key_stream[16]; + /* xcrypt full block */ + _keystream(ctx, key_stream); + for (size_t j = 0; j < 64; j++) { + output[j] = input[j] ^ ((uint8_t*)key_stream)[j]; + } + ctx->split.counter[0]++; +} + +void chacha20_finish( chacha20_ctx_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output) +{ + uint32_t key_stream[16]; + _keystream(ctx, key_stream); + for (size_t j = 0; j < input_length; j++) { + output[j] = input[j] ^ ((uint8_t*)key_stream)[j]; + } + crypto_secure_wipe(ctx, sizeof(*ctx)); } diff --git a/sys/crypto/psa_riot_cipher/chacha20.c b/sys/crypto/psa_riot_cipher/chacha20.c index dc8dd2e76ba6..6f05fddcecdf 100644 --- a/sys/crypto/psa_riot_cipher/chacha20.c +++ b/sys/crypto/psa_riot_cipher/chacha20.c @@ -1,9 +1,6 @@ /* - * 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. + * SPDX-FileCopyrightText: 2024 TU Dresden + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -18,12 +15,143 @@ * @} */ +#include "string_utils.h" +#include "unaligned.h" #include "psa/crypto.h" #include "crypto/chacha20poly1305.h" #define ENABLE_DEBUG 0 #include "debug.h" +static psa_status_t _setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length) +{ + DEBUG("RIOT ChaCha20 Cipher setup"); + + if (key_length != CHACHA20POLY1305_KEY_BYTES) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + ctx->buffer_length = 0; + memset(ctx->buffer, 0, sizeof(ctx->buffer)); + /* Copy keydata into buffer for setup in psa_cipher_chacha20_set_iv() */ + memcpy(ctx->buffer, key_data, key_length); + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_chacha20_encrypt_setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length) +{ + return _setup(ctx, key_data, key_length); +} + +psa_status_t psa_cipher_chacha20_decrypt_setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length) +{ + return _setup(ctx, key_data, key_length); +} + +psa_status_t psa_cipher_chacha20_set_iv(psa_cipher_chacha20_ctx_t *ctx, + const uint8_t *iv, + size_t iv_length) +{ + DEBUG("RIOT ChaCha20 Cipher set IV"); + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + /* See PSA Specification */ + switch (iv_length) { + case 8: + /* IoT-TODO: Chacha20 implementation only handles 12byte nonce */ + /* 8 bytes: the cipher operation uses the original [CHACHA20] definition + of ChaCha20: the provided IV is used as the 64-bit nonce, and the 64-bit + counter value is set to zero. */ + status = PSA_ERROR_NOT_SUPPORTED; + break; + case 12: + /* 12 bytes: the provided IV is used as the nonce, and the counter value + is set to zero. */ + chacha20_setup(&ctx->ctx, ctx->buffer, iv, 0); + status = PSA_SUCCESS; + break; + case 16: + /* 16 bytes: the first four bytes of the IV are used as the counter value + (encoded as little-endian), and the remaining 12 bytes are used as the nonce. */ + chacha20_setup(&ctx->ctx, ctx->buffer, &iv[4], unaligned_get_u32(iv)); + status = PSA_SUCCESS; + break; + default: + /* It is recommended that implementations do not support other sizes of IV. */ + status = PSA_ERROR_INVALID_ARGUMENT; + } + /* Clear key from buffer */ + explicit_bzero(ctx->buffer, sizeof(ctx->buffer)); + return status; +} + +psa_status_t psa_cipher_chacha20_update(psa_cipher_chacha20_ctx_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("RIOT ChaCha20 Cipher update"); + /* We return full blocks, so we check that we have enough output buffer + to fit all full blocks in the combined context and input buffer */ + if (output_size < (((ctx->buffer_length + input_length) / CHACHA20POLY1305_BLOCK_BYTES) * CHACHA20POLY1305_BLOCK_BYTES)) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + size_t input_index = 0; + size_t output_index = 0; + /* check if buffer contains data */ + if (ctx->buffer_length > 0) { + /* if yes, fill buffer up and update this block of data */ + input_index = sizeof(ctx->buffer) - ctx->buffer_length; + memcpy(&ctx->buffer[ctx->buffer_length], input, input_index); + chacha20_update(&ctx->ctx, ctx->buffer, output); + memset(ctx->buffer, 0, sizeof(ctx->buffer)); + ctx->buffer_length = 0; + output_index = 64; + } + + /* if not, update blocks of input */ + const size_t num_blocks = (input_length - input_index) >> 6; + size_t pos = 0; + + for (size_t i = 0; i < num_blocks; i++, pos += 64) { + chacha20_update(&ctx->ctx, &input[input_index + pos], &output[output_index + pos]); + } + + /* put remaining data into buffer */ + ctx->buffer_length = input_length - (input_index + pos); + memcpy(ctx->buffer, &input[input_index + pos], ctx->buffer_length); + *output_length = output_index + pos; + + return PSA_SUCCESS; +} + +psa_status_t psa_cipher_chacha20_finish(psa_cipher_chacha20_ctx_t *ctx, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + DEBUG("RIOT ChaCha20 Cipher finish"); + + if (output_size < ctx->buffer_length) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + /* xcrypt remaining bytes */ + chacha20_finish(&ctx->ctx, ctx->buffer, ctx->buffer_length, output); + + *output_length = ctx->buffer_length; + + return PSA_SUCCESS; +} + psa_status_t psa_cipher_chacha20_encrypt(uint8_t *key_buffer, size_t key_buffer_size, const uint8_t *input, @@ -49,10 +177,12 @@ psa_status_t psa_cipher_chacha20_encrypt(uint8_t *key_buffer, if (status != PSA_SUCCESS) return status; - chacha20_encrypt_decrypt(input, data_out, key_buffer, nonce, input_length); + chacha20_encrypt_decrypt(key_buffer, nonce, 0, input, input_length, data_out); + status = PSA_SUCCESS; *output_length = input_length + CHACHA20POLY1305_NONCE_BYTES; - return PSA_SUCCESS; + + return status; } psa_status_t psa_cipher_chacha20_decrypt(uint8_t *key_buffer, @@ -77,7 +207,7 @@ psa_status_t psa_cipher_chacha20_decrypt(uint8_t *key_buffer, 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); + chacha20_encrypt_decrypt(key_buffer, nonce, 0, data_in, input_length - CHACHA20POLY1305_NONCE_BYTES, output); *output_length = input_length; return PSA_SUCCESS; } diff --git a/sys/include/crypto/chacha20poly1305.h b/sys/include/crypto/chacha20poly1305.h index abc441f64f6a..39e85cda0779 100644 --- a/sys/include/crypto/chacha20poly1305.h +++ b/sys/include/crypto/chacha20poly1305.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2018 Koen Zandberg - * - * 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. + * SPDX-FileCopyrightText: 2018 Koen Zandberg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -33,9 +30,30 @@ extern "C" { #endif +#define CHACHA20POLY1305_CONSTANT_BYTES (16U) /**< Constants length in bytes */ #define CHACHA20POLY1305_KEY_BYTES (32U) /**< Key length in bytes */ +#define CHACHA20POLY1305_COUNTER_BYTES (4U) /**< Counter length in bytes */ #define CHACHA20POLY1305_NONCE_BYTES (12U) /**< Nonce length in bytes */ #define CHACHA20POLY1305_TAG_BYTES (16U) /**< Tag length in bytes */ +#define CHACHA20POLY1305_BLOCK_BYTES (64U) /**< Block length in bytes */ + +/** + * @brief Context of a ChaCha20 multipart operation + */ +typedef union { + /**< Array Access to ChaCha20 state */ + uint32_t words[CHACHA20POLY1305_BLOCK_BYTES / sizeof(uint32_t)]; + struct { + /**< Constant Value */ + uint32_t constant[CHACHA20POLY1305_CONSTANT_BYTES / sizeof(uint32_t)]; + /**< Key of the ChaCha20 operation */ + uint32_t key[CHACHA20POLY1305_KEY_BYTES / sizeof(uint32_t)]; + /**< Counter of the ChaCha20 operation */ + uint32_t counter[CHACHA20POLY1305_COUNTER_BYTES / sizeof(uint32_t)]; + /**< Nonce of the ChaCha20 operation */ + uint32_t nonce[CHACHA20POLY1305_NONCE_BYTES / sizeof(uint32_t)]; + }__attribute__ ((__packed__)) split; /**< Individual access to ChaCha20 state */ +} chacha20_ctx_t; /** * @brief Chacha20poly1305 state struct @@ -45,7 +63,7 @@ typedef union { * the same time. This works as long as the first 8 members of state * overlap fully or completely not with the first and second key parts * from the @ref poly1305_ctx_t struct */ - uint32_t state[16]; /**< The current state of the key stream. */ + chacha20_ctx_t chacha20; /**< The context of the ChaCha20 operation. */ poly1305_ctx_t poly; /**< Poly1305 state for the MAC */ } chacha20poly1305_ctx_t; @@ -72,7 +90,6 @@ typedef union { void chacha20poly1305_encrypt(uint8_t *cipher, const uint8_t *msg, size_t msglen, const uint8_t *aad, size_t aadlen, const uint8_t *key, const uint8_t *nonce); - /** * @brief Verify the tag and decrypt a ciphertext to plaintext. * @@ -98,17 +115,58 @@ int chacha20poly1305_decrypt(const uint8_t *cipher, size_t cipherlen, /** * @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. + * @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] counter Initial counter for the ChaCha20 operation. + * @param[in] input Input for the encryption/decryption. + * @param[in] input_length Length of the input byte array. + * @param[out] output The resulting encrypted cipher/decrypted message. */ -void chacha20_encrypt_decrypt(const uint8_t *input, uint8_t *output, - const uint8_t *key, const uint8_t *nonce, - size_t inputlen); +void chacha20_encrypt_decrypt( const uint8_t *key, + const uint8_t *nonce, + uint32_t counter, + const uint8_t *input, + size_t input_length, + uint8_t *output); +/** + * @brief Setup a ChaCha20 encrypt or decrypt multipart operation. + * + * @param[out] ctx Context of the multipart ChaCha20 operation. + * @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] counter Initial counter for the multipart ChaCha20 operation. + */ +void chacha20_setup(chacha20_ctx_t *ctx, + const uint8_t *key, + const uint8_t *nonce, + const uint32_t counter); + +/** + * @brief Update a ChaCha20 encrypt or decrypt multipart operation. + * + * @param[in] ctx Context of the multipart ChaCha20 operation. + * @param[in] input Input buffer containing one block of input data (64B). + * @param[out] output Output buffer. Must be at least length of input buffer. + */ +void chacha20_update( chacha20_ctx_t *ctx, + const uint8_t *input, + uint8_t *output); + +/** + * @brief Finish a ChaCha20 encrypt or decrypt multipart operation. + * + * @param[in] ctx Context of the multipart ChaCha20 operation. + * @param[in] input Input buffer. + * @param[in] input_length Length of input buffer. Must be a less than 64B. + * @param[out] output Output buffer. Must be at least length of input buffer. + */ +void chacha20_finish( chacha20_ctx_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output); #ifdef __cplusplus } diff --git a/sys/include/crypto/psa/riot_ciphers.h b/sys/include/crypto/psa/riot_ciphers.h index eaf06fcc705e..2c6880924200 100644 --- a/sys/include/crypto/psa/riot_ciphers.h +++ b/sys/include/crypto/psa/riot_ciphers.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2022 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2022 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -34,6 +31,26 @@ typedef cipher_t psa_cipher_aes_192_ctx_t; #if IS_USED(MODULE_PSA_RIOT_CIPHER_AES_256_CBC) typedef cipher_t psa_cipher_aes_256_ctx_t; #endif +#if IS_USED(MODULE_PSA_RIOT_CIPHER_CHACHA20) +#include "crypto/chacha20poly1305.h" +/** + * @brief This struct is used to handle the discontinuity between the PSA API + * and the RIOT ChaCha20 API. The PSA API psa_cipher_update() function allows any size + * of input array, but the RIOT implementation only works on multiples of 64B. + * So we store any remainders from the input in the buffer, and if any more data + * is input, we join them with the buffer values. The psa_cipher_finish() function + * will then xcrypt the remaining buffer values. + * The buffer is also used in the setup of the operation. The psa_cipher_~_setup() + * functions only provide the key for the operation, but the ChaCha20 implementation + * also needs the counter and nonce provided by psa_cipher_set_iv(). So we store + * the key in the buffer until it is needed in the RIOT API setup. + */ +typedef struct { + uint8_t buffer[CHACHA20POLY1305_BLOCK_BYTES]; /**< Block buffer */ + uint8_t buffer_length; /**< Current length of the data in buffer */ + chacha20_ctx_t ctx; /**< Context of the RIOT ChaCha20 operation */ +} psa_cipher_chacha20_ctx_t; +#endif #ifdef __cplusplus } diff --git a/sys/include/psa_crypto/psa/cipher/sizes.h b/sys/include/psa_crypto/psa/cipher/sizes.h index e8572b0abf72..99e21e29277d 100644 --- a/sys/include/psa_crypto/psa/cipher/sizes.h +++ b/sys/include/psa_crypto/psa/cipher/sizes.h @@ -41,7 +41,7 @@ extern "C" { * * @return The block size for a block cipher, or 1 for a stream cipher. */ -#define PSA_BLOCK_CIPHER_BLOCK_LENGTH(type) \ +#define PSA_BLOCK_CIPHER_BLOCK_LENGTH(type) \ (1u << (((type) >> 8) & 7)) /** @@ -49,7 +49,7 @@ extern "C" { * * @details See also @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH(). */ -#define PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE /* implementation-defined value */ +#define PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE 64 /** * @brief The default IV size for a cipher algorithm, in bytes. @@ -91,7 +91,7 @@ extern "C" { * * See also @ref PSA_CIPHER_IV_LENGTH(). */ -#define PSA_CIPHER_IV_MAX_SIZE /* implementation-defined value */ +#define PSA_CIPHER_IV_MAX_SIZE 16 /** * @brief The maximum size of the output of @ref psa_cipher_encrypt(), in bytes. @@ -126,7 +126,10 @@ extern "C" { * @param input_length Size of the input in bytes. */ #define PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE(input_length) \ - (PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, input_length)) + (PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, input_length) \ + > PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_CHACHA20, PSA_ALG_STREAM_CIPHER, input_length) \ + ? PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING, input_length) \ + : PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_CHACHA20, PSA_ALG_STREAM_CIPHER, input_length)) /** * @brief The maximum size of the output of @ref psa_cipher_decrypt(), in bytes. @@ -183,7 +186,8 @@ extern "C" { * are incompatible. */ #define PSA_CIPHER_UPDATE_OUTPUT_SIZE(key_type, alg, input_length) \ -/* implementation-defined value */ + ((key_type == PSA_KEY_TYPE_CHACHA20 \ + && alg == PSA_ALG_STREAM_CIPHER) ? (input_length + 64) : 0) /** * @brief A sufficient output buffer size for @ref psa_cipher_update(), @@ -198,7 +202,7 @@ extern "C" { * @param input_length Size of the input in bytes. */ #define PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(input_length) \ -/* implementation-defined value */ + (input_length + 64) /** * @brief A sufficient output buffer size for @ref psa_cipher_finish(). @@ -218,7 +222,7 @@ extern "C" { * parameters are incompatible. */ #define PSA_CIPHER_FINISH_OUTPUT_SIZE(key_type, alg) \ -/* implementation-defined value */ + ((key_type == PSA_KEY_TYPE_CHACHA20) ? 64 : 0 ) /** * @brief A sufficient output buffer size for @ref psa_cipher_finish(), for any of the supported @@ -229,7 +233,7 @@ extern "C" { * * See also @ref PSA_CIPHER_FINISH_OUTPUT_SIZE(). */ -#define PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE /* implementation-defined value */ +#define PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE 64 #ifdef __cplusplus } diff --git a/sys/include/psa_crypto/psa/cipher/types.h b/sys/include/psa_crypto/psa/cipher/types.h index 26ff35e182a9..f9d2613edadd 100644 --- a/sys/include/psa_crypto/psa/cipher/types.h +++ b/sys/include/psa_crypto/psa/cipher/types.h @@ -28,11 +28,17 @@ extern "C" { #include "crypto/psa/riot_ciphers.h" #include "kernel_defines.h" #include "psa/algorithm.h" +#include "psa_crypto_operation_encoder.h" #if IS_USED(MODULE_PERIPH_CIPHER_AES_128_CBC) #include "psa_periph_aes_ctx.h" #endif +// TODO +#if IS_USED(MODULE_PERIPH_CIPHER_CHACHA20) +#include "psa_periph_chacha20_ctx.h" +#endif + #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) #include "atca_params.h" #endif @@ -61,6 +67,9 @@ typedef union { #if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || defined(DOXYGEN) psa_cipher_aes_256_ctx_t aes_256; /**< AES 256 context*/ #endif +#if IS_USED(MODULE_PSA_CIPHER_CHACHA20) || defined(DOXYGEN) + psa_cipher_chacha20_ctx_t chacha20; /**< ChaCha20 context*/ +#endif } psa_cipher_context_t; /** @@ -86,6 +95,8 @@ struct psa_cipher_operation_s { uint8_t iv_set : 1; /**< True if IV was already set */ uint8_t default_iv_length; /**< Default IV length for algorithm */ psa_algorithm_t alg; /**< Operation algorithm*/ + /** Combination of the psa_algorithm_t and psa_key_type_t for a specific implementation. */ + psa_cipher_op_t cipher_instance; /** Union containing cipher contexts for the executing backend */ union cipher_context { psa_cipher_context_t cipher_ctx; /**< Cipher context */ diff --git a/sys/include/psa_crypto/psa/crypto_contexts.h b/sys/include/psa_crypto/psa/crypto_contexts.h index ec19362b760f..42c8e3f03761 100644 --- a/sys/include/psa_crypto/psa/crypto_contexts.h +++ b/sys/include/psa_crypto/psa/crypto_contexts.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once diff --git a/sys/include/psa_crypto/psa/crypto_includes.h b/sys/include/psa_crypto/psa/crypto_includes.h index 9c19cdd2ae8b..5b0f32e85e85 100644 --- a/sys/include/psa_crypto/psa/crypto_includes.h +++ b/sys/include/psa_crypto/psa/crypto_includes.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -41,6 +38,10 @@ extern "C" { #include "psa_periph_aes_ctx.h" #endif +#if IS_USED(MODULE_PERIPH_CIPHER_CHACHA20) +#include "psa_periph_chacha20_ctx.h" +#endif + #if IS_USED(MODULE_PERIPH_HASH_SHA_1) || IS_USED(MODULE_PERIPH_HASH_SHA_224) || \ IS_USED(MODULE_PERIPH_HASH_SHA_256) || IS_USED(MODULE_PERIPH_HASH_SHA_384) || \ IS_USED(MODULE_PERIPH_HASH_SHA_512) || IS_USED(MODULE_PERIPH_HASH_SHA_512_224) || \ diff --git a/sys/include/psa_crypto/psa/crypto_sizes.h b/sys/include/psa_crypto/psa/crypto_sizes.h index 7b76ca666b72..f0e4c0a702a7 100644 --- a/sys/include/psa_crypto/psa/crypto_sizes.h +++ b/sys/include/psa_crypto/psa/crypto_sizes.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once diff --git a/sys/include/psa_crypto/psa/crypto_struct.h b/sys/include/psa_crypto/psa/crypto_struct.h index 8d44a80a6d7c..4ddeefa0c0a9 100644 --- a/sys/include/psa_crypto/psa/crypto_struct.h +++ b/sys/include/psa_crypto/psa/crypto_struct.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once diff --git a/sys/include/psa_crypto/psa/key/sizes.h b/sys/include/psa_crypto/psa/key/sizes.h index ae3f30888d45..32f87c13498b 100644 --- a/sys/include/psa_crypto/psa/key/sizes.h +++ b/sys/include/psa_crypto/psa/key/sizes.h @@ -25,6 +25,7 @@ extern "C" { #endif +#include "modules.h" #include "psa/sizes.h" #include "type.h" diff --git a/sys/psa_crypto/include/psa_ciphers.h b/sys/psa_crypto/include/psa_ciphers.h index cd74fd8af9e7..ad2d876a6497 100644 --- a/sys/psa_crypto/include/psa_ciphers.h +++ b/sys/psa_crypto/include/psa_ciphers.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -90,6 +87,87 @@ psa_status_t psa_cipher_cbc_aes_256_encrypt(const psa_key_attributes_t *attribut #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) || defined(DOXYGEN) +/** + * @brief ChaCha20 setup function + * + * @param ctx Driver specific ChaCha20 context of type @c psa_cipher_chacha20_ctx_t + * @param key_data Key Buffer. + * @param key_length Length of the key buffer. Must be @c 32 bytes. + * @return psa_status_t + */ +psa_status_t psa_cipher_chacha20_encrypt_setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length); + +/** + * @brief ChaCha20 setup function + * + * @param ctx Driver specific ChaCha20 context of type @c psa_cipher_chacha20_ctx_t + * @param key_data Key Buffer. + * @param key_length Length of the key buffer. Must be @c 32 bytes. + * @return psa_status_t + */ +psa_status_t psa_cipher_chacha20_decrypt_setup( psa_cipher_chacha20_ctx_t *ctx, + uint8_t *key_data, + size_t key_length); + +/** + * @brief ChaCha20 set nonce and initial counter function + * + * @param ctx Driver specific ChaCha20 context of type @c psa_cipher_chacha20_ctx_t + * @param iv Buffer of IV to be set + * @param iv_length Length of the IV Buffer. + * - 12 bytes: the provided IV is used as the nonce, and the + * counter value is set to zero. + * - 16 bytes: the first four bytes of the IV are used as the + * counter value (encoded as little-endian), and the remaining + * 12 bytes are used as the nonce. + * - 8 bytes: the cipher operation uses the original [CHACHA20] + * definition of ChaCha20: the provided IV is used as the + * 64-bit nonce, and the 64-bit counter value is set to zero. + * - It is recommended that implementations do not support + * other sizes of IV. + */ +psa_status_t psa_cipher_chacha20_set_iv(psa_cipher_chacha20_ctx_t *ctx, + const uint8_t *iv, + size_t iv_length); + +/** + * @brief ChaCha20 update function, encrypting/decrypting aligned blocks. + * + * @param ctx Driver specific ChaCha20 context of type @c psa_cipher_chacha20_ctx_t + * @param input Input that is going to be encrypted/decrypted + * @param input_length Length of @c input buffer + * @param output Output Buffer for the encrypted/decrypted input + * @param output_size Length of @c output buffer. Must be large enough to + * fit the output blocks from buffer and input + * @param output_length Actual length of the output data. Will be multiple + * of Block size (64B). + * @return psa_status_t + */ +psa_status_t psa_cipher_chacha20_update(psa_cipher_chacha20_ctx_t *ctx, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief ChaCha20 finish function. Outputs the xcrytion of the remaining buffer. + * + * @param ctx Driver specific ChaCha context of type @c psa_cipher_chacha20_ctx_t + * @param output Output Buffer for the encrypted/decrypted data + * @param output_size Length of @c output buffer. Must be large enough to + * fit the buffer (64B). + * @param output_length Actual length of the output data. Will be less than + * Block size (64B). + * @return psa_status_t + */ +psa_status_t psa_cipher_chacha20_finish(psa_cipher_chacha20_ctx_t *ctx, + uint8_t *output, + size_t output_size, + size_t *output_length); + /** * @brief Low level wrapper function to call a driver for ChaCha20 encryption/decryption. * See @ref psa_cipher_encrypt(). diff --git a/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h b/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h index 3e756b18bbf0..a79982777068 100644 --- a/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h +++ b/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -152,6 +149,53 @@ psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t * uint8_t *output, size_t output_size, size_t *output_length); + +/** + * @brief Dispatch call of a cipher encrypt setup function to a location specific backend. + * See psa_cipher_setup() + */ +psa_status_t psa_algorithm_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg); + +/** + * @brief Dispatch call of a cipher decrypt setup function to a location specific backend. + * See psa_cipher_setup() + */ +psa_status_t psa_algorithm_dispatch_cipher_decrypt_setup( psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg); + +/** + * @brief Dispatch call of a cipher finish function to a location specific backend. + * See psa_cipher_finish() + */ +psa_status_t psa_algorithm_dispatch_cipher_finish( psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch call of a cipher update function to a location specific backend. + * See psa_cipher_update() + */ +psa_status_t psa_algorithm_dispatch_cipher_update( psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch call of a function to set a cipher IV to a location specific backend. + * See psa_cipher_set_iv() + */ +psa_status_t psa_algorithm_dispatch_cipher_set_iv( psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length); + #endif /* MODULE_PSA_CIPHER */ #if IS_USED(MODULE_PSA_AEAD) diff --git a/sys/psa_crypto/include/psa_crypto_location_dispatch.h b/sys/psa_crypto/include/psa_crypto_location_dispatch.h index 211978309e91..7bea328c4b27 100644 --- a/sys/psa_crypto/include/psa_crypto_location_dispatch.h +++ b/sys/psa_crypto/include/psa_crypto_location_dispatch.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -190,6 +187,25 @@ psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t * const psa_key_attributes_t *attributes, const psa_key_slot_t *slot, psa_algorithm_t alg); +/** + * @brief Dispatch call of a cipher finish function to a location specific backend. + * See psa_cipher_finish() + */ +psa_status_t psa_location_dispatch_cipher_finish( psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length); + +/** + * @brief Dispatch call of a cipher update function to a location specific backend. + * See psa_cipher_update() + */ +psa_status_t psa_location_dispatch_cipher_update( psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length); /** * @brief Dispatch call of a function to set a cipher IV to a location specific backend. diff --git a/sys/psa_crypto/include/psa_crypto_operation_encoder.h b/sys/psa_crypto/include/psa_crypto_operation_encoder.h index 37a40b62083e..3cdf622eb622 100644 --- a/sys/psa_crypto/include/psa_crypto_operation_encoder.h +++ b/sys/psa_crypto/include/psa_crypto_operation_encoder.h @@ -1,9 +1,6 @@ /* - * Copyright (C) 2022 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2022 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ #pragma once @@ -27,8 +24,9 @@ extern "C" { #endif -#include "psa/crypto.h" -#include "psa_crypto_slot_management.h" +//#include "unaligned.h" +#include "psa/aead/algorithm.h" +#include "psa/cipher/algorithm.h" /** * @brief Unknown or invalid operation diff --git a/sys/psa_crypto/include/psa_crypto_se_driver.h b/sys/psa_crypto/include/psa_crypto_se_driver.h index e9d056c11d68..ab50a4c6cc1e 100644 --- a/sys/psa_crypto/include/psa_crypto_se_driver.h +++ b/sys/psa_crypto/include/psa_crypto_se_driver.h @@ -45,8 +45,12 @@ extern "C" { #include #include -#include "psa/crypto_values.h" -#include "psa/crypto_types.h" +//#include "psa/crypto_values.h" +//#include "psa/crypto_types.h" +#include "psa/algorithm.h" +#include "psa/error.h" +#include "psa/key/lifetime.h" +#include "psa/cipher/types.h" /** * @brief Maximum size of persistent driver data in bytes diff --git a/sys/psa_crypto/include/psa_crypto_slot_management.h b/sys/psa_crypto/include/psa_crypto_slot_management.h index cccb0033c5fc..1508cb073063 100644 --- a/sys/psa_crypto/include/psa_crypto_slot_management.h +++ b/sys/psa_crypto/include/psa_crypto_slot_management.h @@ -25,7 +25,6 @@ extern "C" { #endif #include "clist.h" -#include "psa/crypto.h" #include "psa_crypto_se_management.h" /** diff --git a/sys/psa_crypto/psa_crypto.c b/sys/psa_crypto/psa_crypto.c index b58e633e8e03..e3fb6cef80fb 100644 --- a/sys/psa_crypto/psa_crypto.c +++ b/sys/psa_crypto/psa_crypto.c @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -710,11 +707,26 @@ psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation, size_t output_size, size_t *output_length) { - (void)operation; - (void)output; - (void)output_size; - (void)output_length; - return PSA_ERROR_NOT_SUPPORTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !output || !output_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (operation->iv_required && !operation->iv_set) { + psa_cipher_abort(operation); + return PSA_ERROR_BAD_STATE; + } + + status = psa_location_dispatch_cipher_finish(operation, output, output_size, output_length); + if (status != PSA_SUCCESS) { + psa_cipher_abort(operation); + } + return status; } psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, @@ -745,7 +757,7 @@ psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation, status = psa_generate_random(iv, iv_size); if (status != PSA_SUCCESS) { - return status; + return status; } operation->iv_set = 1; @@ -758,10 +770,28 @@ psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation, const uint8_t *iv, size_t iv_length) { - (void)operation; - (void)iv; - (void)iv_length; - return PSA_ERROR_NOT_SUPPORTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !iv) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (!operation->iv_required || operation->iv_set) { + return PSA_ERROR_BAD_STATE; + } + + status = psa_location_dispatch_cipher_set_iv(operation, iv, iv_length); + if (status != PSA_SUCCESS){ + return status; + } + + operation->iv_set = 1; + + return status; } psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, @@ -771,13 +801,25 @@ psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, size_t output_size, size_t *output_length) { - (void)operation; - (void)input; - (void)input_length; - (void)output; - (void)output_size; - (void)output_length; - return PSA_ERROR_NOT_SUPPORTED; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + + if (!lib_initialized) { + return PSA_ERROR_BAD_STATE; + } + + if (!operation || !input || !output || !output_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (operation->iv_required && !operation->iv_set) { + return PSA_ERROR_BAD_STATE; + } + + status = psa_location_dispatch_cipher_update(operation, input, input_length, + output, output_size, output_length); + + + return status; } #endif /* MODULE_PSA_CIPHER */ diff --git a/sys/psa_crypto/psa_crypto_algorithm_dispatch.c b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c index 8947af798008..c792bedcba16 100644 --- a/sys/psa_crypto/psa_crypto_algorithm_dispatch.c +++ b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -21,6 +18,7 @@ #include #include "kernel_defines.h" #include "psa/crypto.h" +#include "psa_crypto_algorithm_dispatch.h" #if IS_USED(MODULE_PSA_MAC) #include "psa_mac.h" @@ -633,7 +631,133 @@ psa_status_t psa_algorithm_dispatch_import_key(const psa_key_attributes_t *attri } #endif /* MODULE_PSA_KEY_MANAGEMENT */ + + #if IS_USED(MODULE_PSA_CIPHER) +psa_status_t psa_algorithm_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg) +{ + operation->cipher_instance = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->type, attributes->bits); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (operation->cipher_instance == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + switch (operation->cipher_instance) { + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_encrypt_setup(&operation->backend_ctx.cipher_ctx.chacha20, key_data, *key_bytes); + #endif + default: + (void)operation; + (void)attributes; + (void)slot; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_cipher_decrypt_setup( psa_cipher_operation_t *operation, + const psa_key_attributes_t *attributes, + const psa_key_slot_t *slot, + psa_algorithm_t alg) +{ + operation->cipher_instance = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->type, attributes->bits); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (operation->cipher_instance == PSA_INVALID_OPERATION) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + switch (operation->cipher_instance) { + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_decrypt_setup(&operation->backend_ctx.cipher_ctx.chacha20, key_data, *key_bytes); + #endif + default: + (void)operation; + (void)attributes; + (void)slot; + (void)alg; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_cipher_finish( psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + switch (operation->cipher_instance) { + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_finish( &operation->backend_ctx.cipher_ctx.chacha20, + output, output_size, output_length); + #endif + default: + (void)operation; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_cipher_update( psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + + switch (operation->cipher_instance) { + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_update( &operation->backend_ctx.cipher_ctx.chacha20, + input, input_length, + output, output_size, output_length); + #endif + default: + (void)operation; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + +psa_status_t psa_algorithm_dispatch_cipher_set_iv( psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length) +{ + switch (operation->cipher_instance) { + #if IS_USED(MODULE_PSA_CIPHER_CHACHA20) + case PSA_STREAM_CIPHER_CHACHA20: + return psa_cipher_chacha20_set_iv( &operation->backend_ctx.cipher_ctx.chacha20, + iv, iv_length); + #endif + default: + (void)operation; + (void)iv; + (void)iv_length; + return PSA_ERROR_NOT_SUPPORTED; + } +} + psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes, psa_algorithm_t alg, const psa_key_slot_t *slot, diff --git a/sys/psa_crypto/psa_crypto_location_dispatch.c b/sys/psa_crypto/psa_crypto_location_dispatch.c index b4f0e9e29288..208532e205b0 100644 --- a/sys/psa_crypto/psa_crypto_location_dispatch.c +++ b/sys/psa_crypto/psa_crypto_location_dispatch.c @@ -1,9 +1,6 @@ /* - * Copyright (C) 2021 HAW Hamburg - * - * 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. + * SPDX-FileCopyrightText: 2021 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only */ /** @@ -22,6 +19,7 @@ #include "kernel_defines.h" #include "psa/crypto.h" #include "psa_crypto_algorithm_dispatch.h" +#include "psa_crypto_location_dispatch.h" #include "psa_crypto_se_management.h" #include "psa_crypto_se_driver.h" @@ -141,11 +139,7 @@ psa_status_t psa_location_dispatch_cipher_encrypt_setup( psa_cipher_operation_ } } #endif /* MODULE_PSA_SECURE_ELEMENT */ - (void)operation; - (void)attributes; - (void)slot; - (void)alg; - return PSA_ERROR_NOT_SUPPORTED; + return psa_algorithm_dispatch_cipher_encrypt_setup(operation, attributes, slot, alg); } psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t *operation, @@ -153,11 +147,81 @@ psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t * const psa_key_slot_t *slot, psa_algorithm_t alg) { + #if IS_USED(MODULE_PSA_SECURE_ELEMENT) + psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime); + if (location != PSA_KEY_LOCATION_LOCAL_STORAGE) { + const psa_drv_se_t *drv; + psa_drv_se_context_t *drv_context; + psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; + psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot); + + uint8_t *key_data = NULL; + size_t *key_bytes = NULL; + psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes); + + if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) { + if (drv->cipher == NULL || drv->cipher->p_setup == NULL) { + return PSA_ERROR_NOT_SUPPORTED; + } + + status = drv->cipher->p_setup(drv_context, &operation->backend_ctx.se_ctx, *slot_number, + attributes->policy.alg, PSA_CRYPTO_DRIVER_DECRYPT); + + return status; + } + } + #endif /* MODULE_PSA_SECURE_ELEMENT */ + return psa_algorithm_dispatch_cipher_decrypt_setup(operation, attributes, slot, alg); +} + +psa_status_t psa_location_dispatch_cipher_finish( psa_cipher_operation_t *operation, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + #if IS_USED(MODULE_PSA_SECURE_ELEMENT) + (void)operation; + (void)output; + (void)output_size; + (void)output_length; + return PSA_ERROR_NOT_SUPPORTED; + #endif /* MODULE_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_cipher_finish(operation, output, output_size, output_length); +} + +psa_status_t psa_location_dispatch_cipher_update( psa_cipher_operation_t *operation, + const uint8_t *input, + size_t input_length, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + #if IS_USED(MODULE_PSA_SECURE_ELEMENT) (void)operation; - (void)attributes; - (void)slot; - (void)alg; + (void)input; + (void)input_length; + (void)output; + (void)output_size; + (void)output_length; return PSA_ERROR_NOT_SUPPORTED; + #endif /* MODULE_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_cipher_update(operation, input, input_length, output, output_size, output_length); +} + +psa_status_t psa_location_dispatch_cipher_set_iv( psa_cipher_operation_t *operation, + const uint8_t *iv, + size_t iv_length) +{ + #if IS_USED(MODULE_PSA_SECURE_ELEMENT) + (void)operation; + (void)iv; + (void)iv_length; + return PSA_ERROR_NOT_SUPPORTED; + #endif /* MODULE_PSA_SECURE_ELEMENT */ + + return psa_algorithm_dispatch_cipher_set_iv(operation, iv, iv_length); } #if IS_USED(MODULE_PSA_SECURE_ELEMENT) diff --git a/tests/sys/crypto/tests-crypto-chacha20poly1305.c b/tests/sys/crypto/tests-crypto-chacha20poly1305.c index b377bedcf41c..17f46c9d834b 100644 --- a/tests/sys/crypto/tests-crypto-chacha20poly1305.c +++ b/tests/sys/crypto/tests-crypto-chacha20poly1305.c @@ -23,7 +23,7 @@ uint8_t ebuf[1024]; /* Plaintext buffer */ uint8_t pbuf[1024]; -static const uint8_t key_1[32] = { +static const uint8_t key_1[] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f }; diff --git a/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c b/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c index 2bd604e87847..15e79a73169b 100644 --- a/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c +++ b/tests/sys/psa_crypto_cipher/example_cipher_chacha20.c @@ -35,13 +35,92 @@ static uint8_t PLAINTEXT[] = { 0x73, 0x20, 0x34, 0x32, 0x2E }; +static const uint8_t key_multipart[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 +}; + +static const uint8_t iv_multipart[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02 +}; + +/* 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_multipart[] = { +0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, +0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 0x54, 0x46, +0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, +0x74, 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, +0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, +0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, +0x6f, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, +0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, +0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x52, 0x46, +0x43, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, 0x74, 0x61, +0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, +0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, +0x74, 0x65, 0x78, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, +0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, +0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 0x65, 0x64, 0x20, +0x61, 0x6e, 0x20, 0x22, 0x49, 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, +0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x20, 0x53, 0x75, +0x63, 0x68, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, +0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, +0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x69, +0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, +0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, +0x73, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, +0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, +0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, +0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, +0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, +0x2c, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, +0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f +}; + +/* 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 ciphertext_multipart[] = { +0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, 0x4f, 0x37, 0x6c, 0xa2, 0x3e, +0x82, 0x73, 0x70, 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd, 0x8c, 0xff, +0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec, 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, +0x15, 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, 0x0e, 0x9e, 0x96, 0xd6, +0x47, 0xb7, 0xc3, 0x9f, 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d, 0x40, +0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa, 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, +0x44, 0x0e, 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, 0xc6, 0x13, 0x2f, +0x42, 0x0e, 0x52, 0x79, 0x50, 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05, +0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c, 0x68, 0x04, 0x65, 0x55, 0x2a, +0xa6, 0xc4, 0x05, 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, 0xd0, 0x0f, +0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, +0x66, 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4, 0x1f, 0x43, 0xab, 0xf9, +0x37, 0xd3, 0x25, 0x9d, 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, 0x39, +0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, +0x5c, 0x87, 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b, 0x08, 0x71, 0xcd, +0xac, 0x63, 0x89, 0x39, 0xe2, 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, +0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, 0x59, 0x89, 0xcb, 0xcf, 0x3d, +0xaa, 0x8b, 0x6c, 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b, 0x37, 0x20, +0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84, 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, +0xfd, 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, 0xc3, 0x9c, 0x1e, 0x87, +0x6b, 0x19, 0x3b, 0xfe, 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0, 0x8a, +0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80, 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, +0x41, 0x1f, 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, 0x6f, 0xf2, 0x16, +0xb9, 0xc1, 0xd3, 0x00, 0x62, 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91, +0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6, 0x98, 0xce, 0xd7, 0x59, 0xc3, +0xff, 0x9b, 0x64, 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, 0x14, 0xea, +0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41, 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, +0xab, 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba, 0x5b, 0x86, 0x2f, 0x37, +0x30, 0xe3, 0x7c, 0xfd, 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21 +}; + /** * @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 example_cipher_chacha20_oneshot(void) { psa_status_t status = PSA_ERROR_DOES_NOT_EXIST; psa_key_id_t key_id = 0; @@ -78,3 +157,160 @@ psa_status_t example_cipher_chacha20(void) } return status; } + +/** + * @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_multipart(void) +{ + psa_cipher_operation_t operation; + operation = psa_cipher_operation_init(); + 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 = sizeof(ciphertext_multipart); + size_t plain_output_size = sizeof(plaintext_multipart); + + printf("cipher output size: %zu\n", cipher_output_size); + uint8_t cipher_out[cipher_output_size]; + uint8_t plain_out[plain_output_size]; + + 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_multipart, sizeof(key_multipart), &key_id); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + return status; + } + + /* test encrypt */ + status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_STREAM_CIPHER); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Encrypt Setup Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + status = psa_cipher_set_iv(&operation, iv_multipart, sizeof(iv_multipart)); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Encrypt Set IV Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + size_t max_encrypt_size = sizeof(plaintext_multipart); + uint16_t processed_bytes = 0; + uint8_t input_length = 80; + uint16_t calculated_output = 0; + while ( processed_bytes < max_encrypt_size ) { + if( (sizeof(plaintext_multipart) - processed_bytes) < 80 ) { + input_length = sizeof(plaintext_multipart) - processed_bytes; + } + size_t new_output_length = 0; + status = psa_cipher_update( + &operation, + &plaintext_multipart[processed_bytes], + input_length, + &cipher_out[calculated_output], + (cipher_output_size-calculated_output), + &new_output_length); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Encrypt Update Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + calculated_output += new_output_length; + processed_bytes += input_length; + } + + size_t finish_output_length = 0; + status = psa_cipher_finish(&operation, + &cipher_out[calculated_output], + (cipher_output_size-calculated_output), + &finish_output_length + ); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Encrypt Finish Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + calculated_output += finish_output_length; + + if( calculated_output != sizeof(ciphertext_multipart) ) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if( memcmp(cipher_out, ciphertext_multipart, sizeof(ciphertext_multipart)) != 0 ) { + return PSA_ERROR_DATA_INVALID; + } + + + /* test decrypt */ + status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_STREAM_CIPHER); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Decrypt Setup Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + status = psa_cipher_set_iv(&operation, iv_multipart, sizeof(iv_multipart)); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Decrypt Set IV Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + size_t max_decrypt_size = sizeof(ciphertext_multipart); + processed_bytes = 0; + input_length = 80; + calculated_output = 0; + while( processed_bytes < max_decrypt_size ) { + if( (sizeof(plaintext_multipart) - processed_bytes) < 80 ) { + input_length = sizeof(plaintext_multipart) - processed_bytes; + } + size_t new_output_length = 0; + status = psa_cipher_update( + &operation, + &ciphertext_multipart[processed_bytes], + input_length, + &plain_out[calculated_output], + (plain_output_size-calculated_output), + &new_output_length); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Decrypt Update Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + calculated_output += new_output_length; + processed_bytes += input_length; + } + + finish_output_length = 0; + status = psa_cipher_finish(&operation, + &plain_out[calculated_output], + (plain_output_size-calculated_output), + &finish_output_length + ); + if (status != PSA_SUCCESS) { + psa_destroy_key(key_id); + printf("Decrypt Finish Error: %s", psa_status_to_humanly_readable(status)); + return status; + } + calculated_output += finish_output_length; + + if( calculated_output != sizeof(plaintext_multipart) ) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + + if( memcmp(plain_out, plaintext_multipart, sizeof(plaintext_multipart)) != 0 ) { + return PSA_ERROR_DATA_INVALID; + } + + psa_destroy_key(key_id); + return status; + +} diff --git a/tests/sys/psa_crypto_cipher/main.c b/tests/sys/psa_crypto_cipher/main.c index a3e98f3fa4f8..5d377d1aaba5 100644 --- a/tests/sys/psa_crypto_cipher/main.c +++ b/tests/sys/psa_crypto_cipher/main.c @@ -20,7 +20,8 @@ #include "ztimer.h" extern psa_status_t example_cipher_aes_128(void); -extern psa_status_t example_cipher_chacha20(void); +extern psa_status_t example_cipher_chacha20_oneshot(void); +extern psa_status_t example_cipher_chacha20_multipart(void); int main(void) { @@ -39,8 +40,16 @@ int main(void) } start = ztimer_now(ZTIMER_USEC); - status = example_cipher_chacha20(); - printf("Cipher CHACHA20 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); + status = example_cipher_chacha20_oneshot(); + printf("Cipher CHACHA20 oneshot 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)); + } + + start = ztimer_now(ZTIMER_USEC); + status = example_cipher_chacha20_multipart(); + printf("Cipher CHACHA20 multipart 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));