mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
sys/psa_crypto: chacha20 oneshot gluecode
This commit is contained in:
parent
4612cc2348
commit
b9396c4739
@ -20,6 +20,7 @@ ifneq (,$(filter nrf52840xxaa,$(CPU_MODEL)))
|
|||||||
FEATURES_PROVIDED += periph_hash_sha_512
|
FEATURES_PROVIDED += periph_hash_sha_512
|
||||||
FEATURES_PROVIDED += periph_hmac_sha_256
|
FEATURES_PROVIDED += periph_hmac_sha_256
|
||||||
FEATURES_PROVIDED += periph_cipher_aes_128_cbc
|
FEATURES_PROVIDED += periph_cipher_aes_128_cbc
|
||||||
|
FEATURES_PROVIDED += periph_cipher_chacha20
|
||||||
FEATURES_PROVIDED += periph_ecc_p192r1
|
FEATURES_PROVIDED += periph_ecc_p192r1
|
||||||
FEATURES_PROVIDED += periph_ecc_p256r1
|
FEATURES_PROVIDED += periph_ecc_p256r1
|
||||||
FEATURES_PROVIDED += periph_ecc_ed25519
|
FEATURES_PROVIDED += periph_ecc_ed25519
|
||||||
|
@ -38,6 +38,11 @@ ifneq (,$(filter periph_cipher_aes_128_cbc,$(USEMODULE)))
|
|||||||
USEMODULE += psa_cryptocell_310_aes_cbc
|
USEMODULE += psa_cryptocell_310_aes_cbc
|
||||||
endif
|
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)))
|
ifneq (,$(filter periph_hmac_sha_256,$(USEMODULE)))
|
||||||
USEPKG += driver_cryptocell_310
|
USEPKG += driver_cryptocell_310
|
||||||
USEMODULE += psa_cryptocell_310_hmac
|
USEMODULE += psa_cryptocell_310_hmac
|
||||||
|
@ -851,6 +851,8 @@ groups:
|
|||||||
help: A Hardware Random Number Generator (HWRNG) peripheral is present.
|
help: A Hardware Random Number Generator (HWRNG) peripheral is present.
|
||||||
- name: periph_cipher_aes_128_cbc
|
- name: periph_cipher_aes_128_cbc
|
||||||
help: AES 128 CBC hardware acceleration present
|
help: AES 128 CBC hardware acceleration present
|
||||||
|
- name: periph_cipher_chacha20
|
||||||
|
help: ChaCha20 hardware acceleration present
|
||||||
- name: periph_ecc_p192r1
|
- name: periph_ecc_p192r1
|
||||||
help: ECC P192R1 hardware acceleration peripheral present.
|
help: ECC P192R1 hardware acceleration peripheral present.
|
||||||
- name: periph_ecc_p256r1
|
- name: periph_ecc_p256r1
|
||||||
|
@ -139,6 +139,7 @@ FEATURES_EXISTING := \
|
|||||||
periph_adc_continuous \
|
periph_adc_continuous \
|
||||||
periph_can \
|
periph_can \
|
||||||
periph_cipher_aes_128_cbc \
|
periph_cipher_aes_128_cbc \
|
||||||
|
periph_cipher_chacha20 \
|
||||||
periph_clic \
|
periph_clic \
|
||||||
periph_coretimer \
|
periph_coretimer \
|
||||||
periph_cpuid \
|
periph_cpuid \
|
||||||
|
@ -12,6 +12,7 @@ USEMODULE += $(PERIPH_FEATURES)
|
|||||||
# Add all USED periph_% init modules unless they are blacklisted
|
# Add all USED periph_% init modules unless they are blacklisted
|
||||||
PERIPH_IGNORE_MODULES := \
|
PERIPH_IGNORE_MODULES := \
|
||||||
periph_cipher_aes_128_cbc \
|
periph_cipher_aes_128_cbc \
|
||||||
|
periph_cipher_chacha20 \
|
||||||
periph_clic \
|
periph_clic \
|
||||||
periph_common \
|
periph_common \
|
||||||
periph_coretimer \
|
periph_coretimer \
|
||||||
|
@ -357,6 +357,7 @@ PSEUDOMODULES += psa_riot_cipher_aes_128_ecb
|
|||||||
PSEUDOMODULES += psa_riot_cipher_aes_128_cbc
|
PSEUDOMODULES += psa_riot_cipher_aes_128_cbc
|
||||||
PSEUDOMODULES += psa_riot_cipher_aes_192_cbc
|
PSEUDOMODULES += psa_riot_cipher_aes_192_cbc
|
||||||
PSEUDOMODULES += psa_riot_cipher_aes_256_cbc
|
PSEUDOMODULES += psa_riot_cipher_aes_256_cbc
|
||||||
|
PSEUDOMODULES += psa_riot_cipher_chacha20
|
||||||
PSEUDOMODULES += psa_riot_hashes_md5
|
PSEUDOMODULES += psa_riot_hashes_md5
|
||||||
PSEUDOMODULES += psa_riot_hashes_sha_1
|
PSEUDOMODULES += psa_riot_hashes_sha_1
|
||||||
PSEUDOMODULES += psa_riot_hashes_sha_224
|
PSEUDOMODULES += psa_riot_hashes_sha_224
|
||||||
|
@ -13,6 +13,7 @@ CFLAGS += -Wno-cast-align
|
|||||||
|
|
||||||
PSEUDOMODULES += psa_cryptocell_310_aes_cbc
|
PSEUDOMODULES += psa_cryptocell_310_aes_cbc
|
||||||
PSEUDOMODULES += psa_cryptocell_310_aes_common
|
PSEUDOMODULES += psa_cryptocell_310_aes_common
|
||||||
|
PSEUDOMODULES += psa_cryptocell_310_cipher_chacha20
|
||||||
PSEUDOMODULES += psa_cryptocell_310_ecc_common
|
PSEUDOMODULES += psa_cryptocell_310_ecc_common
|
||||||
PSEUDOMODULES += psa_cryptocell_310_ecc_p192
|
PSEUDOMODULES += psa_cryptocell_310_ecc_p192
|
||||||
PSEUDOMODULES += psa_cryptocell_310_ecc_p256
|
PSEUDOMODULES += psa_cryptocell_310_ecc_p256
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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.
|
* @brief Enable CryptoCell module and IRQs.
|
||||||
*
|
*
|
||||||
|
@ -28,6 +28,7 @@ extern "C" {
|
|||||||
#include "crys_ec_mont_edw_error.h"
|
#include "crys_ec_mont_edw_error.h"
|
||||||
#include "crys_hash_error.h"
|
#include "crys_hash_error.h"
|
||||||
#include "ssi_aes_error.h"
|
#include "ssi_aes_error.h"
|
||||||
|
#include "crys_chacha_error.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert CryptoCell CRYS errors to PSA status values
|
* @brief Convert CryptoCell CRYS errors to PSA status values
|
||||||
|
135
pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c
Normal file
135
pkg/driver_cryptocell_310/psa_cryptocell_310/cipher_chacha20.c
Normal 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 */
|
||||||
|
/** @} */
|
@ -27,12 +27,23 @@ psa_status_t CRYS_to_psa_error(CRYSError_t error)
|
|||||||
return PSA_SUCCESS;
|
return PSA_SUCCESS;
|
||||||
case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR:
|
case CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR:
|
||||||
case CRYS_HASH_IS_NOT_SUPPORTED:
|
case CRYS_HASH_IS_NOT_SUPPORTED:
|
||||||
|
case CRYS_CHACHA_IS_NOT_SUPPORTED:
|
||||||
return PSA_ERROR_NOT_SUPPORTED;
|
return PSA_ERROR_NOT_SUPPORTED;
|
||||||
case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR:
|
case CRYS_HASH_USER_CONTEXT_CORRUPTED_ERROR:
|
||||||
return PSA_ERROR_CORRUPTION_DETECTED;
|
return PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
case CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR:
|
case CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR:
|
||||||
case CRYS_ECEDW_SIGN_VERIFY_FAILED_ERROR:
|
case CRYS_ECEDW_SIGN_VERIFY_FAILED_ERROR:
|
||||||
return PSA_ERROR_INVALID_SIGNATURE;
|
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_CONTEXT_VALIDATION_TAG_ERROR:
|
||||||
case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR:
|
case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR:
|
||||||
case CRYS_ECDSA_VERIFY_USER_CONTEXT_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";
|
return "CRYS_ECMONT_IS_NOT_SUPPORTED";
|
||||||
case CRYS_ECEDW_IS_NOT_SUPPORTED:
|
case CRYS_ECEDW_IS_NOT_SUPPORTED:
|
||||||
return "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:
|
default:
|
||||||
return "Error value not recognized";
|
return "Error value not recognized";
|
||||||
}
|
}
|
||||||
|
@ -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,
|
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 */
|
/* Number of full 64 byte blocks */
|
||||||
const size_t num_blocks = len >> 6;
|
const size_t num_blocks = len >> 6;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
/* xcrypt full blocks */
|
/* xcrypt full blocks */
|
||||||
for (size_t i = 0; i < num_blocks; i++, pos += 64) {
|
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++) {
|
for (size_t j = 0; j < 64; j++) {
|
||||||
out[pos+j] = in[pos+j] ^ ((uint8_t*)ctx->state)[j];
|
out[pos+j] = in[pos+j] ^ ((uint8_t*)ctx->state)[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* xcrypt remaining bytes */
|
/* xcrypt remaining bytes */
|
||||||
if (len - pos) {
|
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++) {
|
for (size_t j = 0; j < len - pos; j++) {
|
||||||
out[pos+j] = in[pos+j] ^ ((uint8_t*)ctx->state)[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)
|
const uint8_t *key, const uint8_t *nonce)
|
||||||
{
|
{
|
||||||
chacha20poly1305_ctx_t ctx;
|
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));
|
crypto_secure_wipe(&ctx, sizeof(ctx));
|
||||||
/* Generate tag */
|
/* Generate tag */
|
||||||
_poly1305_gentag(&cipher[msglen], key, nonce,
|
_poly1305_gentag(&cipher[msglen], key, nonce,
|
||||||
@ -164,6 +165,14 @@ int chacha20poly1305_decrypt(const uint8_t *cipher, size_t cipherlen,
|
|||||||
}
|
}
|
||||||
chacha20poly1305_ctx_t ctx;
|
chacha20poly1305_ctx_t ctx;
|
||||||
/* Number of full blocks */
|
/* Number of full blocks */
|
||||||
_xcrypt(&ctx, key, nonce, cipher, msg, *msglen);
|
_xcrypt(&ctx, key, nonce, cipher, msg, *msglen, 1);
|
||||||
return 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);
|
||||||
|
}
|
||||||
|
84
sys/crypto/psa_riot_cipher/chacha20.c
Normal file
84
sys/crypto/psa_riot_cipher/chacha20.c
Normal 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;
|
||||||
|
}
|
@ -96,6 +96,21 @@ int chacha20poly1305_decrypt(const uint8_t *cipher, size_t cipherlen,
|
|||||||
const uint8_t *aad, size_t aadlen,
|
const uint8_t *aad, size_t aadlen,
|
||||||
const uint8_t *key, const uint8_t *nonce);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -61,7 +61,8 @@ extern "C" {
|
|||||||
IS_USED(MODULE_PSA_ASYMMETRIC_ECC_ED25519) || \
|
IS_USED(MODULE_PSA_ASYMMETRIC_ECC_ED25519) || \
|
||||||
IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || \
|
IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || \
|
||||||
IS_USED(MODULE_PSA_MAC_HMAC_SHA_256) || \
|
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
|
#define CONFIG_PSA_MAX_KEY_SIZE 32
|
||||||
#elif (IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || \
|
#elif (IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || \
|
||||||
IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1))
|
IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1))
|
||||||
@ -591,8 +592,9 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define PSA_CIPHER_IV_LENGTH(key_type, alg) \
|
#define PSA_CIPHER_IV_LENGTH(key_type, alg) \
|
||||||
(PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1 && \
|
((PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1 && \
|
||||||
((alg) == PSA_ALG_CBC_NO_PADDING) ? 16 : 0)
|
((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(),
|
* @brief A sufficient buffer size for storing the IV generated by @ref psa_cipher_generate_iv(),
|
||||||
|
@ -143,6 +143,30 @@ ifneq (,$(filter psa_cipher_aes_192_cbc_backend_riot,$(USEMODULE)))
|
|||||||
USEMODULE += psa_riot_cipher_aes_192_cbc
|
USEMODULE += psa_riot_cipher_aes_192_cbc
|
||||||
endif
|
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
|
# Hash
|
||||||
|
|
||||||
## MD5
|
## MD5
|
||||||
|
@ -85,6 +85,18 @@ ifneq (,$(filter psa_cipher_aes_256_cbc,$(USEMODULE)))
|
|||||||
endif
|
endif
|
||||||
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
|
## Hash
|
||||||
PSEUDOMODULES += psa_hash
|
PSEUDOMODULES += psa_hash
|
||||||
PSEUDOMODULES += psa_hash_md5
|
PSEUDOMODULES += psa_hash_md5
|
||||||
|
@ -286,6 +286,12 @@
|
|||||||
* - psa_cipher_aes_256_cbc_custom_backend
|
* - psa_cipher_aes_256_cbc_custom_backend
|
||||||
* - psa_cipher_aes_256_cbc_backend_riot
|
* - 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
|
* ### Hashes
|
||||||
* - Base: psa_hash
|
* - Base: psa_hash
|
||||||
*
|
*
|
||||||
|
@ -28,6 +28,7 @@ extern "C" {
|
|||||||
#include "psa/crypto.h"
|
#include "psa/crypto.h"
|
||||||
#include "psa/crypto_contexts.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.
|
* @brief Low level wrapper function to call a driver for an AES 128 CBC encryption.
|
||||||
* See @ref psa_cipher_encrypt()
|
* 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,
|
uint8_t *output,
|
||||||
size_t output_size,
|
size_t output_size,
|
||||||
size_t *output_length);
|
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.
|
* @brief Low level wrapper function to call a driver for an AES 192 CBC encryption.
|
||||||
* See @ref psa_cipher_encrypt()
|
* 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,
|
uint8_t *output,
|
||||||
size_t output_size,
|
size_t output_size,
|
||||||
size_t *output_length);
|
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.
|
* @brief Low level wrapper function to call a driver for an AES 256 CBC encryption.
|
||||||
* See @ref psa_cipher_encrypt()
|
* 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,
|
uint8_t *output,
|
||||||
size_t output_size,
|
size_t output_size,
|
||||||
size_t *output_length);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,7 +45,8 @@ typedef enum {
|
|||||||
PSA_CBC_NO_PAD_AES_128,
|
PSA_CBC_NO_PAD_AES_128,
|
||||||
PSA_CBC_NO_PAD_AES_192,
|
PSA_CBC_NO_PAD_AES_192,
|
||||||
PSA_CBC_NO_PAD_AES_256,
|
PSA_CBC_NO_PAD_AES_256,
|
||||||
PSA_CBC_PKCS7_AES_256
|
PSA_CBC_PKCS7_AES_256,
|
||||||
|
PSA_STREAM_CIPHER_CHACHA20
|
||||||
} psa_cipher_op_t;
|
} psa_cipher_op_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,59 +110,127 @@ typedef enum {
|
|||||||
PSA_INVALID_OPERATION)
|
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_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) \
|
#define GET_CBC_NO_PADDING_OPERATION(type, bits) \
|
||||||
(((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_128 : \
|
((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)
|
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_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) \
|
#define GET_CBC_PKCS7_OPERATION(type, bits) \
|
||||||
(((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_192 : \
|
(((alg == PSA_ALG_CBC_PKCS7) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_PKCS7_AES_256 : \
|
||||||
PSA_INVALID_OPERATION)
|
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_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) \
|
#define GET_CFB_OPERATION(type, bits) \
|
||||||
(((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_256 : \
|
(PSA_INVALID_OPERATION)
|
||||||
((alg == PSA_ALG_CBC_PKCS7) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_PKCS7_AES_256 : \
|
|
||||||
|
/**
|
||||||
|
* @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)
|
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.
|
* @brief Map algorithm, key size and type to a specific operation.
|
||||||
*
|
*
|
||||||
* @param alg Algorithm of type @ref psa_algorithm_t.
|
* @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 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_cipher_op_t
|
||||||
* @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible
|
* @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible
|
||||||
*/
|
*/
|
||||||
#define PSA_ENCODE_CIPHER_OPERATION(alg, bits, type) \
|
#define PSA_ENCODE_CIPHER_OPERATION(alg, type, bits) \
|
||||||
((bits == 128) ? GET_CIPHER_OPERATION_128(alg, type) : \
|
((alg == PSA_ALG_CBC_NO_PADDING) ? GET_CBC_NO_PADDING_OPERATION(type, bits) : \
|
||||||
(bits == 192) ? GET_CIPHER_OPERATION_192(alg, type) : \
|
(alg == PSA_ALG_CBC_PKCS7) ? GET_CBC_PKCS7_OPERATION(type, bits) : \
|
||||||
(bits == 256) ? GET_CIPHER_OPERATION_256(alg, type) : \
|
(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)
|
PSA_INVALID_OPERATION)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -1019,6 +1019,11 @@ static psa_status_t psa_validate_unstructured_key_size(psa_key_type_t type, size
|
|||||||
return PSA_ERROR_INVALID_ARGUMENT;
|
return PSA_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PSA_KEY_TYPE_CHACHA20:
|
||||||
|
if (bits != 256) {
|
||||||
|
return PSA_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
(void)bits;
|
(void)bits;
|
||||||
return PSA_ERROR_NOT_SUPPORTED;
|
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)) {
|
if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) {
|
||||||
*bits = PSA_BYTES_TO_BITS(data_length);
|
*bits = PSA_BYTES_TO_BITS(data_length);
|
||||||
|
|
||||||
status = psa_validate_unstructured_key_size(type, *bits);
|
status = psa_validate_unstructured_key_size(type, *bits);
|
||||||
if (status != PSA_SUCCESS) {
|
if (status != PSA_SUCCESS) {
|
||||||
return status;
|
return status;
|
||||||
|
@ -602,7 +602,8 @@ psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *
|
|||||||
size_t output_size,
|
size_t output_size,
|
||||||
size_t *output_length)
|
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;
|
uint8_t *key_data = NULL;
|
||||||
size_t *key_bytes = 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) {
|
switch (op) {
|
||||||
#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)
|
#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)
|
||||||
case PSA_CBC_NO_PAD_AES_128:
|
case PSA_CBC_NO_PAD_AES_128:
|
||||||
return psa_cipher_cbc_aes_128_encrypt(attributes, key_data, *key_bytes, alg, input,
|
return psa_cipher_cbc_aes_128_encrypt(attributes, key_data, *key_bytes, alg, input,
|
||||||
input_length, output, output_size, output_length);
|
input_length, output, output_size, output_length);
|
||||||
#endif
|
#endif
|
||||||
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC)
|
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC)
|
||||||
case PSA_CBC_NO_PAD_AES_192:
|
case PSA_CBC_NO_PAD_AES_192:
|
||||||
return psa_cipher_cbc_aes_192_encrypt(attributes, key_data, *key_bytes, alg, input,
|
return psa_cipher_cbc_aes_192_encrypt(attributes, key_data, *key_bytes, alg, input,
|
||||||
input_length, output, output_size, output_length);
|
input_length, output, output_size, output_length);
|
||||||
#endif
|
#endif
|
||||||
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC)
|
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC)
|
||||||
case PSA_CBC_NO_PAD_AES_256:
|
case PSA_CBC_NO_PAD_AES_256:
|
||||||
return psa_cipher_cbc_aes_256_encrypt(attributes, key_data, *key_bytes, alg, input,
|
return psa_cipher_cbc_aes_256_encrypt(attributes, key_data, *key_bytes, alg, input,
|
||||||
input_length, output, output_size, output_length);
|
input_length, output, output_size, output_length);
|
||||||
#endif
|
#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:
|
default:
|
||||||
(void)slot;
|
(void)slot;
|
||||||
(void)input;
|
(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_size,
|
||||||
size_t *output_length)
|
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;
|
uint8_t *key_data = NULL;
|
||||||
size_t *key_bytes = 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) {
|
switch (op) {
|
||||||
#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)
|
#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)
|
||||||
case PSA_CBC_NO_PAD_AES_128:
|
case PSA_CBC_NO_PAD_AES_128:
|
||||||
return psa_cipher_cbc_aes_128_decrypt(attributes, key_data, *key_bytes, alg, input,
|
return psa_cipher_cbc_aes_128_decrypt(attributes, key_data, *key_bytes, alg, input,
|
||||||
input_length, output, output_size, output_length);
|
input_length, output, output_size, output_length);
|
||||||
#endif
|
#endif
|
||||||
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC)
|
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC)
|
||||||
case PSA_CBC_NO_PAD_AES_192:
|
case PSA_CBC_NO_PAD_AES_192:
|
||||||
return psa_cipher_cbc_aes_192_decrypt(attributes, key_data, *key_bytes, alg, input,
|
return psa_cipher_cbc_aes_192_decrypt(attributes, key_data, *key_bytes, alg, input,
|
||||||
input_length, output, output_size, output_length);
|
input_length, output, output_size, output_length);
|
||||||
#endif
|
#endif
|
||||||
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC)
|
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC)
|
||||||
case PSA_CBC_NO_PAD_AES_256:
|
case PSA_CBC_NO_PAD_AES_256:
|
||||||
return psa_cipher_cbc_aes_256_decrypt(attributes, key_data, *key_bytes, alg, input,
|
return psa_cipher_cbc_aes_256_decrypt(attributes, key_data, *key_bytes, alg, input,
|
||||||
input_length, output, output_size, output_length);
|
input_length, output, output_size, output_length);
|
||||||
#endif
|
#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:
|
default:
|
||||||
(void)slot;
|
(void)slot;
|
||||||
(void)input;
|
(void)input;
|
||||||
|
@ -6,6 +6,7 @@ USEMODULE += ztimer_usec
|
|||||||
USEMODULE += psa_crypto
|
USEMODULE += psa_crypto
|
||||||
|
|
||||||
USEMODULE += psa_cipher
|
USEMODULE += psa_cipher
|
||||||
|
USEMODULE += psa_cipher_chacha20
|
||||||
USEMODULE += psa_cipher_aes_128_cbc
|
USEMODULE += psa_cipher_aes_128_cbc
|
||||||
|
|
||||||
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1
|
CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1
|
||||||
|
@ -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);
|
status = psa_import_key(&attr, KEY_128, AES_128_KEY_SIZE, &key_id);
|
||||||
if (status != PSA_SUCCESS) {
|
if (status != PSA_SUCCESS) {
|
||||||
|
psa_destroy_key(key_id);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT,
|
status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT,
|
||||||
PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len);
|
PLAINTEXT_LEN, cipher_out, encr_output_size, &output_len);
|
||||||
if (status != PSA_SUCCESS) {
|
if (status != PSA_SUCCESS) {
|
||||||
|
psa_destroy_key(key_id);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out,
|
status = psa_cipher_decrypt(key_id, PSA_ALG_CBC_NO_PADDING, cipher_out,
|
||||||
sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len);
|
sizeof(cipher_out), plain_out, sizeof(plain_out), &output_len);
|
||||||
|
psa_destroy_key(key_id);
|
||||||
if (status == PSA_SUCCESS) {
|
if (status == PSA_SUCCESS) {
|
||||||
return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0);
|
return (memcmp(PLAINTEXT, plain_out, sizeof(plain_out)) ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
83
tests/sys/psa_crypto_cipher/example_cipher_chacha20.c
Normal file
83
tests/sys/psa_crypto_cipher/example_cipher_chacha20.c
Normal 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;
|
||||||
|
}
|
@ -23,6 +23,7 @@
|
|||||||
#include "ztimer.h"
|
#include "ztimer.h"
|
||||||
|
|
||||||
extern psa_status_t example_cipher_aes_128(void);
|
extern psa_status_t example_cipher_aes_128(void);
|
||||||
|
extern psa_status_t example_cipher_chacha20(void);
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
@ -42,6 +43,14 @@ int main(void)
|
|||||||
printf("Cipher AES 128 failed: %s\n", psa_status_to_humanly_readable(status));
|
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);
|
ztimer_release(ZTIMER_USEC);
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
|
Loading…
Reference in New Issue
Block a user