1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 00:29:46 +01:00

sys/psa_crypto: chacha20 oneshot gluecode

This commit is contained in:
Wunderbaeumchen 2024-07-23 17:11:34 +02:00 committed by lulu254b
parent 4612cc2348
commit b9396c4739
26 changed files with 637 additions and 64 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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.
*

View File

@ -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

View File

@ -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 <lennard.melling@msx.tu-dresden.de>
*
*/
#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 */
/** @} */

View File

@ -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";
}

View File

@ -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);
}

View File

@ -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 <lennard.melling@msx.tu-dresden.de>
*
* @}
*/
#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;
}

View File

@ -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

View File

@ -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(),

View File

@ -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

View File

@ -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

View File

@ -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
*

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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 <mikolai.guetschow@tu-dresden.de>
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#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;
}

View File

@ -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) {