diff --git a/doc/doxygen/src/riot-psa-structure.svg b/doc/doxygen/src/riot-psa-structure.svg
new file mode 100644
index 0000000000..ef2b814cd3
--- /dev/null
+++ b/doc/doxygen/src/riot-psa-structure.svg
@@ -0,0 +1,851 @@
+
+
diff --git a/makefiles/dependency_resolution.inc.mk b/makefiles/dependency_resolution.inc.mk
index ecea9e1086..274c96c1a2 100644
--- a/makefiles/dependency_resolution.inc.mk
+++ b/makefiles/dependency_resolution.inc.mk
@@ -93,4 +93,12 @@ else
"don't run this on public networks!$(COLOR_RESET)" 1>&2)
endif
endif
+
+ # Warn about PSA Crypto
+ ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ $(shell $(COLOR_ECHO) "$(COLOR_YELLOW) You are going to use the PSA Crypto module,"\
+ "which is only partly implemented and not yet thouroughly tested.\n"\
+ "Please do not use this module in production, as it may introduce"\
+ "security issues!$(COLOR_RESET)" 1>&2)
+ endif
endif
diff --git a/sys/Kconfig b/sys/Kconfig
index fc11536036..97ed70068a 100644
--- a/sys/Kconfig
+++ b/sys/Kconfig
@@ -93,6 +93,7 @@ rsource "posix/Kconfig"
rsource "preprocessor/Kconfig"
rsource "progress_bar/Kconfig"
rsource "ps/Kconfig"
+rsource "psa_crypto/Kconfig"
rsource "random/Kconfig"
rsource "rtc_utils/Kconfig"
rsource "rust_riotmodules/Kconfig"
diff --git a/sys/Makefile b/sys/Makefile
index de159e8680..835383e8b9 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -173,6 +173,9 @@ endif
ifneq (,$(filter posix_sleep,$(USEMODULE)))
DIRS += posix/sleep
endif
+ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ DIRS += psa_crypto
+endif
ifneq (,$(filter pthread,$(USEMODULE)))
DIRS += posix/pthread
endif
diff --git a/sys/Makefile.dep b/sys/Makefile.dep
index 783df5777e..8a7771accc 100644
--- a/sys/Makefile.dep
+++ b/sys/Makefile.dep
@@ -686,6 +686,14 @@ ifneq (,$(filter fido2_ctap%,$(USEMODULE)))
USEMODULE += fido2
endif
+ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ include $(RIOTBASE)/sys/psa_crypto/Makefile.dep
+endif
+
+ifneq (,$(filter psa_riot_cipher_aes_%,$(USEMODULE)))
+ USEMODULE += psa_riot_cipher_aes_common
+endif
+
ifneq (,$(filter rust_riotmodules,$(USEMODULE)))
include $(RIOTBASE)/sys/rust_riotmodules/Makefile.dep
endif
diff --git a/sys/Makefile.include b/sys/Makefile.include
index b2d5ac2c27..450b3fe401 100644
--- a/sys/Makefile.include
+++ b/sys/Makefile.include
@@ -163,6 +163,10 @@ ifneq (,$(filter prng,$(USEMODULE)))
include $(RIOTBASE)/sys/random/Makefile.include
endif
+ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ include $(RIOTBASE)/sys/psa_crypto/Makefile.include
+endif
+
ifneq (,$(filter test_utils_netdev_eth_minimal,$(USEMODULE)))
CFLAGS += -DCONFIG_NETDEV_REGISTER_SIGNAL
endif
diff --git a/sys/include/psa_crypto/psa/crypto.h b/sys/include/psa_crypto/psa/crypto.h
new file mode 100644
index 0000000000..19f8fe718e
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto.h
@@ -0,0 +1,4053 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file crypto.h
+ * @brief Function declarations for PSA Crypto
+ *
+ * @author Lena Boeckmann
+ *
+ * @see https://armmbed.github.io/mbed-crypto/html/index.html
+ *
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_H
+#define PSA_CRYPTO_PSA_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+#include "kernel_defines.h"
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_CONFIG)
+#include "psa/crypto_se_config.h"
+#endif
+
+#include "crypto_sizes.h"
+#include "crypto_struct.h"
+#include "crypto_values.h"
+#include "crypto_types.h"
+
+/**
+ * @brief The major version of this implementation of the PSA Crypto API
+ */
+#define PSA_CRYPTO_API_VERSION_MAJOR 1
+
+/**
+ * @brief The minor version of this implementation of the PSA Crypto API
+ */
+#define PSA_CRYPTO_API_VERSION_MINOR 1
+
+/**
+ * @brief Helper function to convert PSA status values humanly readable.
+ *
+ * @param status PSA status value
+ * @return Pointer to string
+ */
+const char *psa_status_to_humanly_readable(psa_status_t status);
+
+/**
+ * @brief Library initialization.
+ *
+ * @details Applications must call this function before calling any other function in this module.
+ * Applications are permitted to call this function more than once. Once a call succeeds,
+ * subsequent calls are guaranteed to succeed.
+ *
+ * If the application calls other functions before calling @ref psa_crypto_init(),
+ * the behavior is undefined. In this situation:
+ * - Implementations are encouraged to either perform the operation as if the library
+ * had been initialized or to return @ref PSA_ERROR_BAD_STATE or some other applicable
+ * error.
+ * - Implementations must not return a success status if the lack of initialization might
+ * have security implications, for example due to improper seeding of the random number
+ * generator.
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ */
+psa_status_t psa_crypto_init(void);
+
+/**
+ * @brief Process an authenticated encryption operation.
+ *
+ * @param key Identifier of the key to use for the operation. It must allow
+ * the usage @ref PSA_KEY_USAGE_ENCRYPT.
+ * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true).
+ * @param nonce Nonce or IV to use.
+ * @param nonce_length Size of the nonce buffer in bytes. This must be appropriate
+ * for the selected algorithm. The default nonce size is
+ * @ref PSA_AEAD_NONCE_LENGTH(@p key_type, @p alg) where
+ * @c key_type is the type of key.
+ * @param additional_data Additional data that will be authenticated but not encrypted.
+ * @param additional_data_length Size of additional_data in bytes.
+ * @param plaintext Data that will be authenticated and encrypted.
+ * @param plaintext_length Size of plaintext in bytes.
+ * @param ciphertext Output buffer for the authenticated and encrypted data. The
+ * additional data is not part of this output. For algorithms
+ * where the encrypted data and the authentication tag are defined
+ * as separate outputs, the authentication tag is appended to the
+ * encrypted data.
+ * @param ciphertext_size Size of the ciphertext buffer in bytes. This must be
+ * appropriate for the selected algorithm and key:
+ * - A sufficient output size is
+ * @ref PSA_AEAD_ENCRYPT_OUTPUT_SIZE(@p key_type, @p alg,
+ * @p plaintext_length) where key_type is the type of key.
+ * - @ref PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(@p plaintext_length)
+ * evaluates to the maximum ciphertext size of any supported
+ * AEAD encryption.
+ * @param ciphertext_length On success, the size of the output in the ciphertext buffer.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the
+ * @ref PSA_KEY_USAGE_ENCRYPT flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD
+ * algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL @c ciphertext_size is too small.
+ * @ref PSA_AEAD_ENCRYPT_OUTPUT_SIZE() or
+ * @ref PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE() can be
+ * used to determine the required buffer size.
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_encrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *plaintext,
+ size_t plaintext_length,
+ uint8_t *ciphertext,
+ size_t ciphertext_size,
+ size_t *ciphertext_length);
+
+/**
+ * @brief Process an authenticated decryption operation.
+ *
+ * @param key Identifier of the key to use for the operation. It must allow
+ * the usage @ref PSA_KEY_USAGE_DECRYPT.
+ * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true).
+ * @param nonce Nonce or IV to use.
+ * @param nonce_length Size of the nonce buffer in bytes. This must be appropriate
+ * for the selected algorithm. The default nonce size is
+ * @ref PSA_AEAD_NONCE_LENGTH(@p key_type, @p alg) where
+ * @c key_type is the type of @c key.
+ * @param additional_data Additional data that will be authenticated but not encrypted.
+ * @param additional_data_length Size of @c additional_data in bytes.
+ * @param ciphertext Data that has been authenticated and encrypted. For algorithms
+ * where the encrypted data and the authentication tag are defined
+ * as separate inputs, the buffer must contain the encrypted data
+ * followed by the authentication tag.
+ * @param ciphertext_length Size of @c ciphertext in bytes.
+ * @param plaintext Output buffer for the decrypted data.
+ * @param plaintext_size Size of the plaintext buffer in bytes. This must be
+ * appropriate for the selected algorithm and key:
+ * - A sufficient output size is
+ * @ref PSA_AEAD_DECRYPT_OUTPUT_SIZE(@p key_type, @p alg,
+ * @p ciphertext_length) where @c key_type is the type of key.
+ * - @ref PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(@p ciphertext_length)
+ * evaluates to the maximum ciphertext size of any supported
+ * AEAD decryption.
+ * @param plaintext_length On success, the size of the output in the plaintext buffer.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The ciphertext is not authentic.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_DECRYPT flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD
+ * algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL @c plaintext_size is too small.
+ * @ref PSA_AEAD_DECRYPT_OUTPUT_SIZE() or
+ * @ref PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE() can be
+ * used to determine the required buffer size.
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_decrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *ciphertext,
+ size_t ciphertext_length,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length);
+
+/**
+ * @brief Set the key for a multi-part authenticated encryption operation.
+ *
+ * @details The sequence of operations to encrypt a message with authentication is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_aead_operation_t, e.g. @ref PSA_AEAD_OPERATION_INIT.
+ * -# Call @ref psa_aead_encrypt_setup() to specify the algorithm and key.
+ * -# If needed, call @ref psa_aead_set_lengths() to specify the length of the inputs to
+ * the subsequent calls to @ref psa_aead_update_ad() and @ref psa_aead_update(). See
+ * the documentation of @ref psa_aead_set_lengths() for details.
+ * -# Call either @ref psa_aead_generate_nonce() or @ref psa_aead_set_nonce() to generate
+ * or set the nonce. It is recommended to use @ref psa_aead_generate_nonce() unless
+ * the protocol being implemented requires a specific nonce value.
+ * -# Call @ref psa_aead_update_ad() zero, one or more times, passing a fragment of the
+ * non-encrypted additional authenticated data each time.
+ * -# Call @ref psa_aead_update() zero, one or more times, passing a fragment of the
+ * message to encrypt each time.
+ * -# Call @ref psa_aead_finish().
+ *
+ * If an error occurs at any step after a call to @ref psa_aead_encrypt_setup(),
+ * the operation will need to be reset by a call to @ref psa_aead_abort(). The application
+ * can call @ref psa_aead_abort() at any time after the operation has been initialized.
+ *
+ * After a successful call to @ref psa_aead_encrypt_setup(), the application must
+ * eventually terminate the operation. The following events terminate an operation:
+ * - A successful call to @ref psa_aead_finish().
+ * - A call to @ref psa_aead_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized as per the
+ * documentation for @ref psa_aead_operation_t and not yet in use.
+ * @param key Identifier of the key to use for the operation. It must remain valid until
+ * the operation terminates.
+ * It must allow the usage @ref PSA_KEY_USAGE_ENCRYPT.
+ * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true).
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * inactive.
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_ENCRYPT
+ * flag, or it does not permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized by
+ * @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Set the key for a multi-part authenticated decryption operation.
+ *
+ * @details The sequence of operations to decrypt a message with authentication is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_aead_operation_t, e.g. @ref PSA_AEAD_OPERATION_INIT.
+ * -# Call @ref psa_aead_decrypt_setup() to specify the algorithm and key.
+ * -# If needed, call @ref psa_aead_set_lengths() to specify the length of the inputs to
+ * the subsequent calls to @ref psa_aead_update_ad() and @ref psa_aead_update(). See
+ * the documentation of @ref psa_aead_set_lengths() for details.
+ * -# Call @ref psa_aead_set_nonce() with the nonce for the decryption.
+ * -# Call @ref psa_aead_update_ad() zero, one or more times, passing a fragment of the
+ * non-encrypted additional authenticated data each time.
+ * -# Call @ref psa_aead_update() zero, one or more times, passing a fragment of the
+ * message to encrypt each time.
+ * -# Call @ref psa_aead_verify().
+ *
+ * If an error occurs at any step after a call to @ref psa_aead_decrypt_setup(),
+ * the operation will need to be reset by a call to @ref psa_aead_abort(). The application
+ * can call @ref psa_aead_abort() at any time after the operation has been initialized.
+ *
+ * After a successful call to @ref psa_aead_decrypt_setup(), the application must
+ * eventually terminate the operation. The following events terminate an operation:
+ * - A successful call to @ref psa_aead_verify().
+ * - A call to @ref psa_aead_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized as per the
+ * documentation for @ref psa_aead_operation_t and not yet in use.
+ * @param key Identifier of the key to use for the operation. It must remain valid
+ * until the operation terminates. It must allow the usage @ref
+ * PSA_KEY_USAGE_DECRYPT.
+ * @param alg The AEAD algorithm to compute (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true).
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * inactive.
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_DECRYPT flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not an AEAD
+ * algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Declare the lengths of the message and additional data for AEAD.
+ *
+ * @details The application must call this function before calling @ref psa_aead_set_nonce()
+ * or @ref psa_aead_generate_nonce(), if the algorithm for the operation requires it.
+ * If the algorithm does not require it, calling this function is optional, but if
+ * this function is called then the implementation must enforce the lengths.
+ * - For @ref PSA_ALG_CCM, calling this function is required.
+ * - For the other AEAD algorithms defined in this specification,
+ * calling this function is not required.
+ * - For vendor-defined algorithm, refer to the vendor documentation.
+ *
+ * If this function returns an error status, the operation enters an error state and
+ * must be aborted by calling @ref psa_aead_abort().
+ *
+ * @param operation Active AEAD operation.
+ * @param ad_length Size of the non-encrypted additional authenticated data in bytes.
+ * @param plaintext_length Size of the plaintext to encrypt in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * active, and @ref psa_aead_set_nonce() and
+ * @ref psa_aead_generate_nonce() must not have
+ * been called yet.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT At least one of the lengths is not acceptable
+ * for the chosen algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation,
+ size_t ad_length,
+ size_t plaintext_length);
+
+/**
+ * @brief Generate a random nonce for an authenticated encryption operation.
+ *
+ * @details This function generates a random nonce for the authenticated encryption operation
+ * with an appropriate size for the chosen algorithm, key type and key size.
+ *
+ * The application must call @ref psa_aead_encrypt_setup() before calling this function.
+ * If applicable for the algorithm, the application must call @ref psa_aead_set_lengths()
+ * before calling this function.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_aead_abort().
+ *
+ * @param operation Active AEAD operation.
+ * @param nonce Buffer where the generated nonce is to be written.
+ * @param nonce_size Size of the nonce buffer in bytes. This must be at least
+ * @ref PSA_AEAD_NONCE_LENGTH(@p key_type, @p alg) where @p key_type
+ * and @p alg are type of key and the algorithm respectively that
+ * were used to set up the AEAD operation.
+ * @param nonce_length On success, the number of bytes of the generated nonce.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * an active AEAD encryption operation, with no
+ * nonce set.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: this is an
+ * algorithm which requires @ref
+ * psa_aead_set_lengths() to be called before
+ * setting the nonce.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the nonce buffer is too small.
+ * @ref PSA_AEAD_NONCE_LENGTH() or @ref
+ * PSA_AEAD_NONCE_MAX_SIZE can be used to
+ * determine the required buffer size.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation,
+ uint8_t *nonce,
+ size_t nonce_size,
+ size_t *nonce_length);
+
+/**
+ * @brief Set the nonce for an authenticated encryption or decryption operation.
+ *
+ * @details This function sets the nonce for the authenticated encryption or decryption operation.
+ * The application must call @ref psa_aead_encrypt_setup() or @ref
+ * psa_aead_decrypt_setup() before calling this function. If applicable for the algorithm,
+ * the application must call @ref psa_aead_set_lengths() before calling this function.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_aead_abort().
+ *
+ * @note When encrypting, @ref psa_aead_generate_nonce() is recommended instead of using this
+ * function, unless implementing a protocol that requires a non-random IV.
+ *
+ * @param operation Active AEAD operation.
+ * @param nonce Buffer containing the nonce to use.
+ * @param nonce_length Size of the nonce in bytes. This must be a valid nonce size for the
+ * chosen algorithm. The default nonce size is @ref PSA_AEAD_NONCE_LENGTH
+ * (@p key_type, @p alg) where @c key_type and @c alg are type of key and
+ * the algorithm respectively that were used to set up the AEAD operation.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * an active AEAD encryption operation, with no
+ * nonce set.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: this is an
+ * algorithm which requires @ref
+ * psa_aead_set_lengths() to be called before
+ * setting the nonce.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The size of nonce is not acceptable for the
+ * chosen algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation,
+ const uint8_t *nonce,
+ size_t nonce_length);
+
+/**
+ * @brief Pass additional data to an active AEAD operation.
+ *
+ * @details Additional data is authenticated, but not encrypted.
+ * This function can be called multiple times to pass successive fragments of the
+ * additional data. This function must not be called after passing data to encrypt
+ * or decrypt with @ref psa_aead_update().
+ *
+ * The following must occur before calling this function:
+ * -# Call either @ref psa_aead_encrypt_setup() or @ref psa_aead_decrypt_setup().
+ * -# Set the nonce with @ref psa_aead_generate_nonce() or @ref psa_aead_set_nonce().
+ *
+ * If this function returns an error status, the operation enters an error state and
+ * must be aborted by calling @ref psa_aead_abort().
+ *
+ * @warning When decrypting, do not trust the input until @ref psa_aead_verify() succeeds.
+ * See the detailed warning.
+ *
+ * @param operation Active AEAD operation.
+ * @param input Buffer containing the fragment of additional data.
+ * @param input_length Size of the input buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * active, have a nonce set, have lengths set if
+ * required by the algorithm, and @ref
+ * psa_aead_update() must not have been called yet.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input length overflows the additional
+ * data length that was previously specified with
+ * @ref psa_aead_set_lengths().
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Encrypt or decrypt a message fragment in an active AEAD operation.
+ *
+ * @details The following must occur before calling this function:
+ * -# Call either @ref psa_aead_encrypt_setup() or @ref psa_aead_decrypt_setup().
+ * The choice of setup function determines whether this function encrypts or decrypts
+ * its input.
+ * -# Set the nonce with @ref psa_aead_generate_nonce() or @ref psa_aead_set_nonce().
+ * -# Call @ref psa_aead_update_ad() to pass all the additional data.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_aead_abort().
+ *
+ * This function does not require the input to be aligned to any particular block
+ * boundary. If the implementation can only process a whole block at a time, it must
+ * consume all the input provided, but it might delay the end of the corresponding output
+ * until a subsequent call to @ref psa_aead_update(), @ref psa_aead_finish() or @ref
+ * psa_aead_verify() provides sufficient input.
+ * The amount of data that can be delayed in this way is bounded by @ref
+ * PSA_AEAD_UPDATE_OUTPUT_SIZE().
+ *
+ * @warning When decrypting, do not trust the input until @ref psa_aead_verify() succeeds.
+ * See the detailed warning.
+ *
+ * @param operation Active AEAD operation.
+ * @param input Buffer containing the message fragment to encrypt or decrypt.
+ * @param input_length Size of the input buffer in bytes.
+ * @param output Buffer where the output is to be written.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - A sufficient output size is @ref PSA_AEAD_UPDATE_OUTPUT_SIZE(
+ * @p key_type, @p alg, @p input_length) where @c key_type is the
+ * type of key and @c alg is the algorithm that were used to set up
+ * the operation.
+ * - @ref PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(@p input_length) evaluates to
+ * the maximum output size of any supported AEAD algorithm.
+ * @param output_length On success, the number of bytes that make up the returned output.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be
+ * active, have a nonce set, and have lengths set
+ * if required by the algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_AEAD_UPDATE_OUTPUT_SIZE() or
+ * @ref PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE() can be
+ * used to determine the required buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref
+ * psa_aead_update_ad() so far is less than the
+ * additional data length that was previously
+ * specified with @ref psa_aead_set_lengths()
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input length overflows the plaintext
+ * length that was previously specified with
+ * @ref psa_aead_set_lengths().
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_update(psa_aead_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Finish encrypting a message in an AEAD operation.
+ *
+ * @details The operation must have been set up with @ref psa_aead_encrypt_setup().
+ * This function finishes the authentication of the additional data formed
+ * by concatenating the inputs passed to preceding calls to @ref psa_aead_update_ad()
+ * with the plaintext formed by concatenating the inputs passed to preceding calls to
+ * @ref psa_aead_update(). This function has two output buffers:
+ * - @p ciphertext contains trailing ciphertext that was buffered from preceding calls to
+ * @ref psa_aead_update().
+ * - @p tag contains the authentication tag.
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_aead_abort().
+ *
+ * @param operation Active AEAD operation.
+ * @param ciphertext Buffer where the last part of the ciphertext is to be written.
+ * @param ciphertext_size Size of the ciphertext buffer in bytes. This must be appropriate
+ * for the selected algorithm and key:
+ * - A sufficient output size is @ref PSA_AEAD_FINISH_OUTPUT_SIZE(
+ * @p key_type, @p alg) where @p key_type is the type of key and
+ * @p alg is the algorithm that were used to set up the operation
+ * - @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE evaluates to the maximum
+ * output size of any supported AEAD algorithm.
+ * @param ciphertext_length On success, the number of bytes of returned ciphertext.
+ * @param tag Buffer where the authentication tag is to be written.
+ * @param tag_size Size of the tag buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - The exact tag size is @ref PSA_AEAD_TAG_LENGTH(@p key_type,
+ * @p key_bits, @p alg) where @c key_type and @c key_bits are
+ * the type and bit-size of the key, and @c alg is the algorithm
+ * that were used in the call to @ref psa_aead_encrypt_setup().
+ * - @ref PSA_AEAD_TAG_MAX_SIZE evaluates to the maximum tag size
+ * of any supported AEAD algorithm.
+ * @param tag_length On success, the number of bytes that make up the returned tag.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be an
+ * active encryption operation with a nonce set.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the ciphertext or tag buffer is too
+ * small. @ref PSA_AEAD_FINISH_OUTPUT_SIZE() or
+ * @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE can be
+ * used to determine the required ciphertext
+ * buffer size. @ref PSA_AEAD_TAG_LENGTH() or
+ * @ref PSA_AEAD_TAG_MAX_SIZE can be used to
+ * determine the required tag buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref
+ * psa_aead_update_ad() so far is less than the
+ * additional data length that was previously
+ * specified with @ref psa_aead_set_lengths()
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref
+ * psa_aead_update() so far is less than the
+ * plaintext length that was previously specified
+ * with @ref psa_aead_set_lengths().
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_finish(psa_aead_operation_t *operation,
+ uint8_t *ciphertext,
+ size_t ciphertext_size,
+ size_t *ciphertext_length,
+ uint8_t *tag,
+ size_t tag_size,
+ size_t *tag_length);
+
+/**
+ * @brief Finish authenticating and decrypting a message in an AEAD operation.
+ *
+ * @details The operation must have been set up with @ref psa_aead_decrypt_setup().
+ * This function finishes the authenticated decryption of the message components:
+ * - The additional data consisting of the concatenation of the inputs passed to
+ * preceding calls to @ref psa_aead_update_ad().
+ * - The ciphertext consisting of the concatenation of the inputs passed to
+ * preceding calls to @ref psa_aead_update().
+ * - The tag passed to this function call.
+ *
+ * If the authentication tag is correct, this function outputs any remaining plaintext
+ * and reports success. If the authentication tag is not correct, this function returns
+ * @ref PSA_ERROR_INVALID_SIGNATURE.
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_aead_abort().
+ *
+ * @note Implementations must make the best effort to ensure that the comparison between
+ * the actual tag and the expected tag is performed in constant time.
+ *
+ * @param operation Active AEAD operation.
+ * @param plaintext Buffer where the last part of the plaintext is to be written. This
+ * is the remaining data from previous calls to @ref psa_aead_update()
+ * that could not be processed until the end of the input.
+ * @param plaintext_size Size of the plaintext buffer in bytes. This must be appropriate
+ * for the selected algorithm and key:
+ * - A sufficient output size is @ref PSA_AEAD_FINISH_OUTPUT_SIZE(
+ * @p key_type, @p alg) where @c key_type is the type of key and
+ * @c alg is the algorithm that were used to set up the operation
+ * - @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE evaluates to the maximum
+ * output size of any supported AEAD algorithm.
+ * @param plaintext_length On success, the number of bytes of returned plaintext.
+ * @param tag Buffer containing the authentication tag.
+ * @param tag_length Size of the tag buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculations were successful, but the
+ * authentication tag is not correct.
+ * @return @ref PSA_ERROR_BAD_STATE The operation state is not valid: it must be an
+ * active encryption operation with a nonce set.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the plaintext buffer is too small.
+ * @ref PSA_AEAD_VERIFY_OUTPUT_SIZE() or
+ * @ref PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE can be
+ * used to determine the required buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref
+ * psa_aead_update_ad() so far is less than the
+ * additional data length that was previously
+ * specified with @ref psa_aead_set_lengths()
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total length of input to @ref
+ * psa_aead_update() so far is less than the
+ * plaintext length that was previously specified
+ * with @ref psa_aead_set_lengths().
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_verify(psa_aead_operation_t *operation,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length,
+ const uint8_t *tag,
+ size_t tag_length);
+
+/**
+ * @brief Abort an AEAD operation.
+ *
+ * @details Aborting an operation frees all associated resources except for the operation object
+ * itself. Once aborted, the operation object can be reused for another operation by
+ * calling @ref psa_aead_encrypt_setup() or @ref psa_aead_decrypt_setup() again.
+ *
+ * This function can be called any time after the operation object has been initialized as
+ * described in @ref psa_aead_operation_t.
+ *
+ * In particular, calling @ref psa_aead_abort() after the operation has been terminated
+ * by a call to @ref psa_aead_abort(), @ref psa_aead_finish() or @ref psa_aead_verify()
+ * is safe and has no effect.
+ *
+ * @param operation Initialized AEAD operation.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_aead_abort(psa_aead_operation_t *operation);
+
+/**
+ * @brief Encrypt a short message with a public key.
+ *
+ * @details For @ref PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is supported.
+ *
+ * @param key Identifier of the key to use for the operation. It must be a
+ * public key or an asymmetric key pair. It must allow the usage
+ * @ref PSA_KEY_USAGE_ENCRYPT.
+ * @param alg An asymmetric encryption algorithm that is compatible with
+ * the type of key.
+ * @param input The message to encrypt.
+ * @param input_length Size of the input buffer in bytes.
+ * @param salt A salt or label, if supported by the encryption algorithm. If the
+ * algorithm does not support a salt, pass @c NULL. If the algorithm
+ * supports an optional salt, pass @c NULL to indicate that there is
+ * no salt.
+ * @param salt_length Size of the salt buffer in bytes. If salt is @c NULL, pass 0.
+ * @param output Buffer where the encrypted message is to be written.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - The required output size is @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE
+ * (@p key_type, @p key_bits, @p alg) where @p key_type and
+ * @p key_bits are the type and bit-size respectively of key
+ * - @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE evaluates to the maximum
+ * output size of any supported asymmetric encryption.
+ * @param output_length On success, the number of bytes that make up the returned output.
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_ENCRYPT flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE() or
+ * @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE can
+ * be used to determine the required buffer size.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_asymmetric_encrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *salt,
+ size_t salt_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Decrypt a short message with a private key.
+ *
+ * @details For @ref PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is supported.
+ *
+ * @param key Identifier of the key to use for the operation. It must be an asymmetric
+ * key pair. It must allow the usage @ref PSA_KEY_USAGE_DECRYPT.
+ * @param alg An asymmetric encryption algorithm that is compatible with
+ * the type of key.
+ * @param input The message to decrypt.
+ * @param input_length Size of the input buffer in bytes.
+ * @param salt A salt or label, if supported by the encryption algorithm. If the
+ * algorithm does not support a salt, pass @c NULL. If the algorithm
+ * supports an optional salt, pass @c NULL to indicate that there is
+ * no salt.
+ * @param salt_length Size of the salt buffer in bytes. If salt is @c NULL, pass 0.
+ * @param output Buffer where the decrypted message is to be written.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - The required output size is @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE
+ * (@p key_type, @p key_bits, @p alg) where @p key_type and
+ * @p key_bits are the type and bit-size respectively of key.
+ * - @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE evaluates to the maximum
+ * output size of any supported asymmetric decryption.
+ * @param output_length On success, the number of bytes that make up the returned output.
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_DECRYPT flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE() or
+ * @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE
+ * can be used to determine the required buffer
+ * size.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ * @return @ref PSA_ERROR_INVALID_PADDING
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_asymmetric_decrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *salt,
+ size_t salt_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Abort a cipher operation.
+ *
+ * @details Aborting an operation frees all associated resources except for the operation object
+ * itself. Once aborted, the operation object can be reused for another operation by
+ * calling @ref psa_cipher_encrypt_setup() or @ref psa_cipher_decrypt_setup() again.
+ *
+ * This function can be called any time after the operation object has been initialized
+ * as described in @ref psa_cipher_operation_t.
+ *
+ * In particular, calling @ref psa_cipher_abort() after the operation has been terminated
+ * by a call to @ref psa_cipher_abort() or @ref psa_cipher_finish() is safe and has no
+ * effect.
+ *
+ * @param operation Initialized cipher operation.
+ *
+ * @return @ref PSA_SUCCESS Success. The operation object can now be
+ * discarded or reused.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call
+ * to @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation);
+
+/**
+ * @brief Decrypt a message using a symmetric cipher.
+ *
+ * @details This function decrypts a message encrypted with a symmetric cipher. *
+ * The input to this function must contain the IV followed by the ciphertext, as output
+ * by @ref psa_cipher_encrypt(). The IV must be @ref PSA_CIPHER_IV_LENGTH(@p key_type,
+ * @p alg) bytes in length, where @c key_type is the type of key.
+ *
+ * Use the multi-part operation interface with a @ref psa_cipher_operation_t object to
+ * decrypt data which is not in the expected input format.
+ *
+ * @param key Identifier of the key to use for the operation. It must remain
+ * valid until the operation terminates. It must allow the usage
+ * @ref PSA_KEY_USAGE_DECRYPT.
+ * @param alg The cipher algorithm to compute: a value of type @ref psa_algorithm_t
+ * such that @ref PSA_ALG_IS_CIPHER(@p alg) is true.
+ * @param input Buffer containing the message to decrypt. This consists of the IV
+ * followed by the ciphertext proper.
+ * @param input_length Size of the input buffer in bytes.
+ * @param output Buffer where the plaintext is to be written.
+ * @param output_size Size of the output buffer in bytes.
+ * This must be appropriate for the selected algorithm and key:
+ * - A sufficient output size is @ref PSA_CIPHER_DECRYPT_OUTPUT_SIZE(
+ * @p key_type, @p alg, @p input_length) where @c key_type is the
+ * type of key.
+ * - @ref PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE(@p input_length) evaluates
+ * to the maximum output size of any supported cipher decryption.
+ * @param output_length On success, the number of bytes that make up the output.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*output_length) bytes of
+ * @p output contain the plaintext.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_DECRYPT
+ * flag, or it does not permit the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_CIPHER_DECRYPT_OUTPUT_SIZE() or
+ * @ref PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE() can be
+ * used to determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_PADDING The algorithm uses padding, and the input does not
+ * contain valid padding.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a cipher algorithm.
+ * - @c key is not compatible with alg.
+ * - The input_length is not valid for the algorithm
+ * and key type.
+ * For example, the algorithm is a based on block
+ * cipher and requires a whole number of blocks,
+ * but the total input size is not a multiple
+ * of the block size.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a cipher
+ * algorithm.
+ * - @c key is not supported for use with alg.
+ * - @c input_length is too large for the implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_cipher_decrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Set the key for a multi-part symmetric decryption operation.
+ *
+ * @details The sequence of operations to decrypt a message with a symmetric cipher is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_cipher_operation_t, e.g. @ref PSA_CIPHER_OPERATION_INIT.
+ * -# Call @ref psa_cipher_decrypt_setup() to specify the algorithm and key.
+ * -# Call @ref psa_cipher_set_iv() with the initialization vector (IV) for the
+ * decryption, if the algorithm requires one. This must match the IV used for the
+ * encryption.
+ * -# Call @ref psa_cipher_update() zero, one or more times, passing a fragment of the
+ * message each time.
+ * -# Call @ref psa_cipher_finish().
+ *
+ * If an error occurs at any step after a call to @ref psa_cipher_decrypt_setup(),
+ * the operation will need to be reset by a call to @ref psa_cipher_abort().
+ * The application can call @ref psa_cipher_abort() at any time after the operation
+ * has been initialized.
+ *
+ * After a successful call to @ref psa_cipher_decrypt_setup(), the application must
+ * eventually terminate the operation. The following events terminate an operation:
+ * - A successful call to @ref psa_cipher_finish().
+ * - A call to @ref psa_cipher_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized as per
+ * the documentation for @ref psa_cipher_operation_t and not yet in use.
+ * @param key Identifier of the key to use for the operation. It must remain valid
+ * until the operation terminates. It must allow the usage @ref
+ * PSA_KEY_USAGE_DECRYPT.
+ * @param alg The cipher algorithm to compute: a value of type @ref psa_algorithm_t
+ * such that @ref PSA_ALG_IS_CIPHER(@p alg) is true.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * inactive.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @p key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_DECRYPT
+ * flag, or it does not permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a cipher algorithm.
+ * - @c key is not compatible with alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a cipher algorithm.
+ * - @c key is not supported for use with alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Encrypt a message using a symmetric cipher.
+ *
+ * @details This function encrypts a message with a random initialization vector (IV).
+ * The length of the IV is @ref PSA_CIPHER_IV_LENGTH(@p key_type, @p alg) where
+ * @p key_type is the type of key. The output of @ref psa_cipher_encrypt() is
+ * the IV followed by the ciphertext.
+ *
+ * Use the multi-part operation interface with a @ref psa_cipher_operation_t object
+ * to provide other forms of IV or to manage the IV and ciphertext independently.
+ *
+ * @param key Identifier of the key to use for the operation. It must allow the usage
+ * @ref PSA_KEY_USAGE_ENCRYPT.
+ * @param alg The cipher algorithm to compute (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_CIPHER(@p alg) is true).
+ * @param input Buffer containing the message to encrypt.
+ * @param input_length Size of the input buffer in bytes.
+ * @param output Buffer where the output is to be written. The output contains the IV
+ * followed by the ciphertext proper.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - A sufficient output size is @ref PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(
+ * @p key_type, @p alg, @p input_length) where @c key_type is the
+ * type of key
+ * - @ref PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE(@p input_length) evaluates
+ * to the maximum output size of any supported cipher encryption.
+ * @param output_length On success, the number of bytes that make up the output.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_ENCRYPT flag, or it does not permit
+ * the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c key is not compatible with alg.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The @c input_length is not valid for the algorithm
+ * and key type. For example, the algorithm is a based
+ * on block cipher and requires a whole number of
+ * blocks, but the total input size is not a multiple
+ * of the block size.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not a cipher
+ * algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL @c output_size is too small.
+ * @ref PSA_CIPHER_ENCRYPT_OUTPUT_SIZE() or
+ * @ref PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE()
+ * can be used to determine the required buffer size.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_cipher_encrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Set the key for a multi-part symmetric encryption operation.
+ *
+ * @details The sequence of operations to encrypt a message with a symmetric cipher is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_cipher_operation_t, e.g. @ref PSA_CIPHER_OPERATION_INIT.
+ * -# Call @ref psa_cipher_encrypt_setup() to specify the algorithm and key.
+ * -# Call either @ref psa_cipher_generate_iv() or @ref psa_cipher_set_iv() to generate
+ * or set the initialization vector (IV), if the algorithm requires one. It is
+ * recommended to use @ref psa_cipher_generate_iv() unless the protocol being
+ * implemented requires a specific IV value.
+ * -# Call @ref psa_cipher_update() zero, one or more times, passing a fragment of
+ * the message each time.
+ * -# Call @ref psa_cipher_finish().
+ *
+ * If an error occurs at any step after a call to @ref psa_cipher_encrypt_setup(),
+ * the operation will need to be reset by a call to @ref psa_cipher_abort(). The
+ * application can call @ref psa_cipher_abort() at any time after the operation has
+ * been initialized.
+ *
+ * After a successful call to @ref psa_cipher_encrypt_setup(), the application must
+ * eventually terminate the operation. The following events terminate an operation:
+ * - A successful call to @ref psa_cipher_finish().
+ * - A call to @ref psa_cipher_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized as per the
+ * documentation for @ref psa_cipher_operation_t and not yet in use.
+ * @param key Identifier of the key to use for the operation. It must remain valid
+ * until the operation terminates. It must allow the usage @ref
+ * PSA_KEY_USAGE_ENCRYPT.
+ * @param alg The cipher algorithm to compute: a value of type @ref psa_algorithm_t
+ * such that @ref PSA_ALG_IS_CIPHER(@p alg) is true.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * inactive.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_ENCRYPT flag, or it does not permit
+ * the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a cipher algorithm.
+ * - @c key is not compatible with alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a cipher algorithm.
+ * - @c key is not supported for use with @c alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Finish encrypting or decrypting a message in a cipher operation.
+ *
+ * @details The application must call @ref psa_cipher_encrypt_setup() or @ref
+ * psa_cipher_decrypt_setup() before calling this function. The choice of setup function
+ * determines whether this function encrypts or decrypts its input.
+ *
+ * This function finishes the encryption or decryption of the message formed by
+ * concatenating the inputs passed to preceding calls to @ref psa_cipher_update().
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_cipher_abort().
+ *
+ * @param operation Active cipher operation.
+ * @param output Buffer where the output is to be written.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - A sufficient output size is @ref PSA_CIPHER_FINISH_OUTPUT_SIZE(
+ * @p key_type, @p alg) where @c key_type is the type of key and
+ * @c alg is the algorithm that were used to set up the operation.
+ * - @ref PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE evaluates to the maximum
+ * output size of any supported cipher algorithm.
+ * @param output_length On success, the number of bytes that make up the returned output.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @c (*output_length) bytes of
+ * @c output contain the final output.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * active, with an IV set if required for the
+ * algorithm.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_CIPHER_FINISH_OUTPUT_SIZE() or
+ * @ref PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE can be used
+ * to determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_PADDING This is a decryption operation for an algorithm that
+ * includes padding, and the ciphertext does not contain
+ * valid padding.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input size passed to this operation is not
+ * valid for this particular algorithm. For example, the
+ * algorithm is a based on block cipher and requires a
+ * whole number of blocks, but the total input size
+ * is not a multiple of the block size.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Generate an initialization vector (IV) for a symmetric encryption operation.
+ *
+ * @details This function generates a random IV, nonce or initial counter value for the encryption
+ * operation as appropriate for the chosen algorithm, key type and key size.
+ *
+ * The generated IV is always the default length for the key and algorithm:
+ * @ref PSA_CIPHER_IV_LENGTH(@p key_type, @p alg), where @p key_type is the type of key
+ * and @p alg is the algorithm that were used to set up the operation. To generate
+ * different lengths of IV, use @ref psa_generate_random() and @ref psa_cipher_set_iv().
+ *
+ * If the cipher algorithm does not use an IV, calling this function returns a
+ * @ref PSA_ERROR_BAD_STATE error. For these algorithms, @ref PSA_CIPHER_IV_LENGTH(
+ * @p key_type, @p alg) will be zero.
+ *
+ * The application must call @ref psa_cipher_encrypt_setup() before calling this function.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_cipher_abort().
+ *
+ * @param operation Active cipher operation.
+ * @param iv Buffer where the generated IV is to be written.
+ * @param iv_size Size of the iv buffer in bytes. This must be at least
+ * @ref PSA_CIPHER_IV_LENGTH(@p key_type, @p alg) where @p key_type and
+ * @p alg are type of key and the algorithm respectively that
+ * were used to set up the cipher operation.
+ * @param iv_length On success, the number of bytes of the generated IV.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE Either:
+ * - The cipher algorithm does not use an IV.
+ * - The operation state is not valid: it must be
+ * active, with no IV set.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the iv buffer is too small.
+ * @ref PSA_CIPHER_IV_LENGTH() or
+ * @ref PSA_CIPHER_IV_MAX_SIZE can be used to
+ * determine the required buffer size.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
+ uint8_t *iv,
+ size_t iv_size,
+ size_t *iv_length);
+
+/**
+ * @brief Set the initialization vector (IV) for a symmetric encryption or decryption operation.
+ *
+ * @details This function sets the IV, nonce or initial counter value for the encryption or
+ * decryption operation.
+ *
+ * If the cipher algorithm does not use an IV, calling this function returns a
+ * @ref PSA_ERROR_BAD_STATE error.
+ * For these algorithms, @ref PSA_CIPHER_IV_LENGTH(key_type, alg) will be zero.
+ *
+ * The application must call @ref psa_cipher_encrypt_setup() or @ref
+ * psa_cipher_decrypt_setup() before calling this function.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_cipher_abort().
+ *
+ * @note When encrypting, @ref psa_cipher_generate_iv() is recommended instead of using this
+ * function, unless implementing a protocol that requires a non-random IV.
+ *
+ * @param operation Active cipher operation.
+ * @param iv Buffer containing the IV to use.
+ * @param iv_length Size of the IV in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The cipher algorithm does not use an IV.
+ * - The operation state is not valid: it must be an
+ * active cipher encrypt operation, with no IV set.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - The chosen algorithm does not use an IV.
+ * - @c iv_length is not valid for the chosen algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c iv_length is not supported for use with the
+ * operation’s algorithm and key.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation,
+ const uint8_t *iv,
+ size_t iv_length);
+
+/**
+ * @brief Encrypt or decrypt a message fragment in an active cipher operation.
+ *
+ * @details The following must occur before calling this function:
+ * -# Call either @ref psa_cipher_encrypt_setup() or @ref psa_cipher_decrypt_setup().
+ * The choice of setup function determines whether this function encrypts or decrypts
+ * its input.
+ * -# If the algorithm requires an IV, call @ref psa_cipher_generate_iv() or @ref
+ * psa_cipher_set_iv(). @ref psa_cipher_generate_iv() is recommended when encrypting.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_cipher_abort().
+ *
+ * @param operation Active cipher operation.
+ * @param input Buffer containing the message fragment to encrypt or decrypt.
+ * @param input_length Size of the @c input buffer in bytes.
+ * @param output Buffer where the output is to be written.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - A sufficient output size is @ref PSA_CIPHER_UPDATE_OUTPUT_SIZE(
+ * @p key_type, @p alg, @p input_length) where @c key_type is the type
+ * of key and @c alg is the algorithm that were used to set up the
+ * operation.
+ * - @ref PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(@p input_length) evaluates
+ * to the maximum output size of any supported cipher algorithm.
+ * @param output_length On success, the number of bytes that make up the returned output.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*output_length) bytes of
+ * @p output contain the output data.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * active, with an IV set if required for the
+ * algorithm.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_CIPHER_UPDATE_OUTPUT_SIZE() or
+ * @ref PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE() can be
+ * used to determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input size passed to this operation is
+ * too large for this particular algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The total input size passed to this operation is
+ * too large for the implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_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 Make a copy of a key.
+ *
+ * @details Copy key material from one location to another. *
+ * This function is primarily useful to copy a key from one location to another, as it
+ * populates a key using the material from another key which can have a different lifetime.
+ *
+ * This function can be used to share a key with a different party, subject to
+ * implementation-defined restrictions on key sharing.
+ *
+ * The policy on the source key must have the usage flag @ref PSA_KEY_USAGE_COPY set.
+ * This flag is sufficient to permit the copy if the key has the lifetime @ref
+ * PSA_KEY_LIFETIME_VOLATILE or @ref PSA_KEY_LIFETIME_PERSISTENT. Some secure elements
+ * do not provide a way to copy a key without making it extractable from the secure
+ * element. If a key is located in such a secure element, then the key must have
+ * both usage flags @ref PSA_KEY_USAGE_COPY and @ref PSA_KEY_USAGE_EXPORT in order to make
+ * a copy of the key outside the secure element.
+ *
+ * The resulting key can only be used in a way that conforms to both the policy of the
+ * original key and the policy specified in the attributes parameter:
+ * - The usage flags on the resulting key are the bitwise-and of the usage flags on the
+ * source policy and the usage flags in attributes.
+ * - If both permit the same algorithm or wildcard-based algorithm, the resulting key
+ * has the same permitted algorithm.
+ * - If either of the policies permits an algorithm and the other policy allows a
+ * wildcard-based permitted algorithm that includes this algorithm, the resulting key
+ * uses this permitted algorithm.
+ * - If the policies do not permit any algorithm in common, this function fails with the
+ * status @ref PSA_ERROR_INVALID_ARGUMENT.
+ *
+ * The effect of this function on implementation-defined attributes is
+ * implementation-defined.
+ *
+ * @param source_key The key to copy. It must allow the usage @ref PSA_KEY_USAGE_COPY. If a
+ * private or secret key is being copied outside of a secure element it must
+ * also allow @ref PSA_KEY_USAGE_EXPORT.
+ * @param attributes The attributes for the new key. This function uses the attributes as
+ * follows:
+ * - The key type and size can be 0. If either is nonzero, it must match the
+ * corresponding attribute of the source key.
+ * - The key location (the lifetime and, for persistent keys, the key
+ * identifier) is used directly.
+ * - The key policy (usage flags and permitted algorithm) are combined from
+ * the source key and attributes so that both sets of restrictions apply,
+ * as described in the documentation of this function.
+ * @note This is an input parameter: it is not updated with the final key
+ * attributes. The final attributes of the new key can be queried by
+ * calling @ref psa_get_key_attributes() with the key’s identifier.
+ * @param target_key On success, an identifier for the newly created key. @ref PSA_KEY_ID_NULL
+ * on failure.
+ *
+ * @return @ref PSA_SUCCESS Success. If the new key is persistent, the key material
+ * and the key’s metadata have been saved to persistent
+ * storage.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @p source_key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The following conditions can result in this error:
+ * - @p source_key does not have the @ref
+ * PSA_KEY_USAGE_COPY usage flag.
+ * - @p source_key does not have the @ref
+ * PSA_KEY_USAGE_EXPORT usage flag, and its storage
+ * location does not allow copying it to the target
+ * key’s storage location.
+ * - @p The implementation does not permit creating
+ * a key with the specified attributes due to some
+ * implementation-specific policy.
+ * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key,
+ * and there is already a persistent key with the given
+ * identifier.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @p attributes specifies a key type or
+ * key size which does not match the attributes
+ * of @p source_key.
+ * - The lifetime or identifier in @p attributes
+ * are invalid.
+ * - The key policies from @p source_key and those
+ * specified in @p attributes are incompatible.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - The @p source_key storage location does not support
+ * copying to the target key’s storage location.
+ * - The key attributes, as a whole, are not supported
+ * in the target key’s storage location.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_copy_key(psa_key_id_t source_key,
+ const psa_key_attributes_t *attributes,
+ psa_key_id_t *target_key);
+
+/**
+ * @brief Destroy a key.
+ *
+ * @details This function destroys a key from both volatile memory and, if applicable, non-volatile
+ * storage. Implementations must make a best effort to ensure that that the key material
+ * cannot be recovered.
+ *
+ * This function also erases any metadata such as policies and frees resources associated
+ * with the key. Destroying the key makes the key identifier invalid, and the key
+ * identifier must not be used again by the application.
+ *
+ * If a key is currently in use in a multi-part operation, then destroying the key will
+ * cause the multi-part operation to fail.
+ *
+ * @param key Identifier of the key to erase. If this is @ref PSA_KEY_ID_NULL, do nothing and
+ * return @ref PSA_SUCCESS.
+ *
+ * @return @ref PSA_SUCCESS Success. If @p key was a valid key identifier,
+ * then the key material that it referred to has
+ * been erased. Alternatively, @p key was
+ * @ref PSA_KEY_ID_NULL.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @p key is neither a valid key identifier,
+ * nor @ref PSA_KEY_ID_NULL.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key cannot be erased because it is
+ * read-only, either due to a policy or due to
+ * physical restrictions.
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE There was an failure in communication with
+ * the cryptoprocessor.
+ * The key material might still be present in
+ * the cryptoprocessor.
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED An unexpected condition which is not a storage
+ * corruption or a communication failure occurred.
+ * The cryptoprocessor might have been compromised.
+ * @return @ref PSA_ERROR_STORAGE_FAILURE The storage operation failed. Implementations
+ * must make a best effort to erase key material
+ * even in this situation, however, it might be
+ * impossible to guarantee that the key material
+ * is not recoverable in such cases.
+ * @return @ref PSA_ERROR_DATA_CORRUPT The storage is corrupted. Implementations must
+ * make a best effort to erase key material even
+ * in this situation, however, it might be
+ * impossible to guarantee that the key material
+ * is not recoverable in such cases.
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_destroy_key(psa_key_id_t key);
+
+/**
+ * @brief Export a key in binary format.
+ *
+ * @details The output of this function can be passed to @ref psa_import_key() to create an
+ * equivalent object.
+ *
+ * If the implementation of @ref psa_import_key() supports other formats beyond the
+ * format specified here, the output from @ref psa_export_key() must use the
+ * representation specified here, not the original representation.
+ *
+ * For standard key types, the output format is as follows:
+ * - For symmetric keys, excluding HMAC keys, the format is the raw bytes of the key.
+ * - For HMAC keys that are shorter than, or equal in size to, the underlying hash
+ * algorithm block size, the format is the raw bytes of the key.
+ * - For HMAC keys that are longer than the underlying hash algorithm block size,
+ * the format is an implementation defined choice between the following formats:
+ * - The raw bytes of the key.
+ * - The raw bytes of the hash of the key, using the underlying hash algorithm.
+ * See also @ref PSA_KEY_TYPE_HMAC.
+ * - For DES, the key data consists of 8 bytes. The parity bits must be correct.
+ * - For Triple-DES, the format is the concatenation of the two or three DES keys.
+ * - For RSA key pairs, with key type @ref PSA_KEY_TYPE_RSA_KEY_PAIR, the format is
+ * the non-encrypted DER encoding of the representation defined by in PKCS #1: RSA
+ * Cryptography Specifications Version 2.2 [RFC8017] as RSAPrivateKey, version 0.
+ * @code
+ * RSAPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- must be 0
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * }
+ * @endcode
+ * @note Although it is possible to define an RSA key pair or private key using a
+ * subset of these elements, the output from @ref psa_export_key() for an RSA
+ * key pair must include all of these elements.
+ * - For elliptic curve key pairs, with key types for which PSA_KEY_TYPE_IS_ECC_KEY_PAIR
+ * () is true, the format is a representation of the private value.
+ * - For Weierstrass curve families @c PSA_ECC_FAMILY_SECT_XX,
+ * @c PSA_ECC_FAMILY_SECP_XX, @ref PSA_ECC_FAMILY_FRP and
+ * @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1, the content of the @c privateKey field of
+ * the @c ECPrivateKey format defined by Elliptic Curve Private Key Structure
+ * [RFC5915]. This is a @c ceiling(m/8)-byte string in big-endian order where @c m
+ * is the key size in bits.
+ * - For curve family @ref PSA_ECC_FAMILY_MONTGOMERY, the scalar value of the
+ * ‘private key’ in little-endian order as defined by Elliptic Curves for Security
+ * [RFC7748] §6. The value must have the forced bits set to zero or one as
+ * specified by @c decodeScalar25519() and @c decodeScalar448() in [RFC7748] §5.
+ * This is a @c ceiling(m/8)-byte string where @c m is the key size in bits. This
+ * is 32 bytes for Curve25519, and 56 bytes for Curve448.
+ * - For the Twisted Edwards curve family @ref PSA_ECC_FAMILY_TWISTED_EDWARDS,
+ * the private key is defined by Edwards-Curve Digital Signature Algorithm (EdDSA)
+ * [RFC8032]. This is a 32-byte string for Edwards25519, and a 57-byte string
+ * for Edwards448.
+ * - For Diffie-Hellman key exchange key pairs, with key types for which @ref
+ * PSA_KEY_TYPE_IS_DH_KEY_PAIR() is true, the format is the representation of the
+ * private key x as a big-endian byte string. The length of the byte string is the
+ * private key size in bytes, and leading zeroes are not stripped.
+ * - For public keys, with key types for which @ref PSA_KEY_TYPE_IS_PUBLIC_KEY() is
+ * true, the format is the same as for @ref psa_export_public_key().
+ *
+ * The policy on the key must have the usage flag @ref PSA_KEY_USAGE_EXPORT set.
+ *
+ * @param key Identifier of the key to export. It must allow the usage @ref
+ * PSA_KEY_USAGE_EXPORT, unless it is a public key.
+ * @param data Buffer where the key data is to be written.
+ * @param data_size Size of the data buffer in bytes. This must be appropriate for the key:
+ * - The required output size is @ref PSA_EXPORT_KEY_OUTPUT_SIZE(@p type,
+ * @p bits) where @c type is the key type and @c bits is the key size in
+ * bits.
+ * - @ref PSA_EXPORT_KEY_PAIR_MAX_SIZE evaluates to the maximum output size
+ * of any supported key pair.
+ * - @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE evaluates to the maximum output
+ * size of any supported public key.
+ * - This API defines no maximum size for symmetric keys. Arbitrarily large
+ * data items can be stored in the key store, for example certificates
+ * that correspond to a stored private key or input material for key
+ * derivation.
+ * @param data_length On success, the number of bytes that make up the key data.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*data_length) bytes of data
+ * contain the exported key
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @p key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_EXPORT
+ * flag.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the data buffer is too small.
+ * @ref PSA_EXPORT_KEY_OUTPUT_SIZE() or @ref
+ * PSA_EXPORT_KEY_PAIR_MAX_SIZE can be used to determine
+ * a sufficient buffer size.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - The key’s storage location does not support export
+ * of the key
+ * - The implementation does not support export of keys
+ * with this key type.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_export_key(psa_key_id_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);
+
+/**
+ * @brief Export a public key or the public part of a key pair in binary format.
+ *
+ * @details The output of this function can be passed to @ref psa_import_key() to create an object
+ * that is equivalent to the public key.
+ *
+ * If the implementation of @ref psa_import_key() supports other formats beyond the
+ * format specified here, the output from @ref psa_export_public_key() must use the
+ * representation specified here, not the original representation.
+ *
+ * For standard key types, the output format is as follows:
+ * - For RSA public keys, with key type @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY, the DER
+ * encoding of the representation defined by Algorithms and Identifiers for the
+ * Internet X.509 Public Key Infrastructure
+ * Certificate and Certificate Revocation List (CRL) Profile [RFC3279] §2.3.1 as
+ * @c RSAPublicKey.
+ * @code
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER } -- e
+ * @endcode
+ * - For elliptic curve key pairs, with key types for which
+ * @ref PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY() is true, the format depends on the key family:
+ * - For Weierstrass curve families @c PSA_ECC_FAMILY_SECT_XX,
+ * @c PSA_ECC_FAMILY_SECP_XX, @ref PSA_ECC_FAMILY_FRP and @ref
+ * PSA_ECC_FAMILY_BRAINPOOL_P_R1, the uncompressed representation of an elliptic
+ * curve point as an octet string defined in SEC 1: Elliptic Curve Cryptography
+ * [SEC1] §2.3.3. If @c m is the bit size associated with the curve, i.e. the bit
+ * size of @c q for a curve over @c F_q. The representation consists of:
+ * - The byte @c 0x04;
+ * - @c x_P as a @c ceiling(m/8)-byte string, big-endian;
+ * - @c y_P as a @c ceiling(m/8)-byte string, big-endian.
+ * - For curve family @ref PSA_ECC_FAMILY_MONTGOMERY, the scalar value of the
+ * ‘public key’ in little-endian order as defined by Elliptic Curves for Security
+ * [RFC7748] §6. This is a @c ceiling(m/8)-byte string where @c m is the key size
+ * in bits.
+ * - This is 32 bytes for Curve25519, computed as @c X25519(private_key, 9).
+ * - This is 56 bytes for Curve448, computed as @c X448(private_key, 5).
+ * - For curve family @ref PSA_ECC_FAMILY_TWISTED_EDWARDS, the public key is defined
+ * by Edwards-Curve Digital Signature Algorithm (EdDSA) [RFC8032].
+ * This is a 32-byte string for Edwards25519, and a 57-byte string for Edwards448.
+ * - For Diffie-Hellman key exchange public keys, with key types for which
+ * @ref PSA_KEY_TYPE_IS_DH_PUBLIC_KEY is true, the format is the representation of the
+ * public key `y = g^x mod p` as a big-endian byte string. The
+ * length of the byte string is the length of the base prime p in bytes.
+ * Exporting a public key object or the public part of a key pair is always permitted,
+ * regardless of the key’s usage flags.
+ *
+ * @param key Identifier of the key to export.
+ * @param data Buffer where the key data is to be written.
+ * @param data_size Size of the @c data buffer in bytes. This must be appropriate for the key:
+ * - The required output size is @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(
+ * @p type, @p bits) where @c type is the key type and @c bits is the key
+ * size in bits.
+ * - @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE evaluates to the maximum output
+ * size of any supported public key or public part of a key pair.
+ * @param data_length On success, the number of bytes that make up the key data.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*data_length) bytes of @p data
+ * contain the exported public key.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the data buffer is too small.
+ * @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE() or
+ * @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE can be used to
+ * determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The key is neither a public key nor a key pair.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - The key’s storage location does not support export
+ * of the key.
+ * - The implementation does not support export of keys
+ * with this key type.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_export_public_key(psa_key_id_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);
+
+/**
+ * @brief Built-in key generation function.
+ *
+ * @details This function generates a random symmetric key. As of yet it does not implement
+ * asymmetric key generation.
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param key_buffer_length
+ * @return psa_status_t
+ */
+psa_status_t psa_builtin_generate_key(const psa_key_attributes_t *attributes, uint8_t *key_buffer,
+ size_t key_buffer_size, size_t *key_buffer_length);
+
+/**
+ * @brief Generate a key or key pair.
+ *
+ * @details The key is generated randomly. Its location, policy, type and size are taken from
+ * @c attributes.
+ *
+ * Implementations must reject an attempt to generate a key of size 0.
+ *
+ * The following type-specific considerations apply:
+ * - For RSA keys (@ref PSA_KEY_TYPE_RSA_KEY_PAIR), the public exponent is 65537.
+ * The modulus is a product of two probabilistic primes between 2^{n-1} and 2^n where n
+ * is the bit size specified in the attributes.
+ *
+ * @param attributes The attributes for the new key. This function uses the attributes as
+ * follows:
+ * - The key type is required. It cannot be an asymmetric public key.
+ * - The key size is required. It must be a valid size for the key type.
+ * - The key permitted-algorithm policy is required for keys that will be
+ * used for a cryptographic operation, see Permitted algorithms.
+ * - The key usage flags define what operations are permitted with the key,
+ * see Key usage flags.
+ * - The key lifetime and identifier are required for a persistent key.
+ * @note This is an input parameter: it is not updated with the final
+ * key attributes. The final attributes of the new key can be
+ * queried by calling @ref psa_get_key_attributes() with the key’s
+ * identifier.
+ * @param key On success, an identifier for the newly created key. @ref PSA_KEY_ID_NULL
+ * on failure.
+ *
+ * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material
+ * and the key’s metadata have been saved to persistent
+ * storage.
+ * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key, and
+ * there is already a persistent key with the given
+ * identifier.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The key type or key size is not supported, either by
+ * the implementation in general or in this particular
+ * persistent location.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The key attributes, as a whole, are invalid.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The key type is an asymmetric public key type.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The key size is not a valid size for the key type.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
+ psa_key_id_t *key);
+
+/**
+ * @brief Built-in function for random number generation.
+ *
+ * @details This function is being used to generate a random number if no other driver for random
+ * number generation is present. It uses the RIOT RNG module as a default backend.
+ *
+ * @param output Output buffer of the size of the random number to be generated.
+ * @param output_size Size of @c output in bytes
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c output is NULL
+ */
+psa_status_t psa_builtin_generate_random( uint8_t *output,
+ size_t output_size);
+
+/**
+ * @brief Generate random bytes.
+ *
+ * @warning This function can fail! Callers MUST check the return status and MUST NOT use the
+ * content of the output buffer if the return status is not @ref PSA_SUCCESS.
+ *
+ * @note To generate a key, use @ref psa_generate_key() instead.
+ *
+ * @param output Output buffer for the generated data.
+ * @param output_size Number of bytes to generate and output.
+ *
+ * @return @ref PSA_SUCCESS Success. @c output contains @c output_size bytes
+ * of generated random data.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c output is NULL
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_generate_random(uint8_t *output,
+ size_t output_size);
+
+/**
+ * @brief Declare the permitted algorithm policy for a key.
+ *
+ * @details The permitted algorithm policy of a key encodes which algorithm or algorithms
+ * are permitted to be used with this key.
+ * This function overwrites any permitted algorithm policy previously set in attributes.
+ *
+ * @param attributes The attribute object to write to.
+ * @param alg The permitted algorithm to write.
+ */
+static inline void psa_set_key_algorithm(psa_key_attributes_t *attributes,
+ psa_algorithm_t alg)
+{
+ attributes->policy.alg = alg;
+}
+
+/**
+ * @brief Retrieve the permitted algorithm policy from key attributes.
+ *
+ * @param attributes The key attribute object to query.
+ *
+ * @return @ref psa_algorithm_t The algorithm stored in the attribute object.
+ */
+static inline psa_algorithm_t psa_get_key_algorithm(const psa_key_attributes_t *attributes)
+{
+ return attributes->policy.alg;
+}
+
+/**
+ * @brief Declare the size of a key.
+ *
+ * @details This function overwrites any key size previously set in attributes.
+ *
+ * @param attributes The attribute object to write to.
+ * @param bits The key size in bits. If this is 0,
+ * the key size in attributes becomes
+ * unspecified. Keys of size 0 are not supported.
+ */
+static inline void psa_set_key_bits(psa_key_attributes_t *attributes,
+ size_t bits)
+{
+ attributes->bits = bits;
+}
+
+/**
+ * @brief Retrieve the key size from key attributes.
+ *
+ * @param attributes The key attribute object to query.
+ *
+ * @return size_t The key size stored in the attribute object, in bits.
+ */
+static inline size_t psa_get_key_bits(const psa_key_attributes_t *attributes)
+{
+ return attributes->bits;
+}
+
+/**
+ * @brief Declare a key as persistent and set its key identifier.
+ *
+ * @details The application must choose a value for id between @ref PSA_KEY_ID_USER_MIN and
+ * @ref PSA_KEY_ID_USER_MAX. If the attribute object currently declares the key as
+ * volatile, which is the default lifetime of an attribute object, this function sets
+ * the lifetime attribute to @ref PSA_KEY_LIFETIME_PERSISTENT.
+ *
+ * This function does not access storage, it merely stores the given value in the
+ * attribute object. The persistent key will be written to storage when the attribute
+ * object is passed to a key creation function such as @ref psa_import_key(),
+ * @ref psa_generate_key(), @ref psa_key_derivation_output_key() or @ref psa_copy_key().
+ *
+ * @param attributes The attribute object to write to.
+ * @param id The persistent identifier for the key.
+ */
+static inline void psa_set_key_id(psa_key_attributes_t *attributes, psa_key_id_t id)
+{
+ attributes->id = id;
+}
+
+/**
+ * @brief Retrieve the key identifier from key attributes.
+ *
+ * @param attributes The key attribute object to query.
+ *
+ * @return @ref psa_key_id_t The persistent identifier stored in the attribute object.
+ * This value is unspecified if the attribute object declares
+ * the key as volatile.
+ */
+static inline psa_key_id_t psa_get_key_id(const psa_key_attributes_t *attributes)
+{
+ return attributes->id;
+}
+
+/**
+ * @brief Set the location of a persistent key.
+ *
+ * @details To make a key persistent, give it a persistent key identifier by using
+ * @ref psa_set_key_id(). By default, a key that has a persistent identifier is stored in
+ * the default storage area identifier by @ref PSA_KEY_LIFETIME_PERSISTENT. Call this
+ * function to choose a storage area, or to explicitly declare the key as volatile.
+ *
+ * This function does not access storage, it merely stores the given value in the
+ * attribute object. The persistent key will be written to storage when the attribute
+ * object is passed to a key creation function such as @ref psa_import_key(),
+ * @ref psa_generate_key(), @ref psa_key_derivation_output_key() or @ref psa_copy_key().
+ *
+ * @param attributes The attribute object to write to.
+ * @param lifetime The lifetime for the key. If this is @ref PSA_KEY_LIFETIME_VOLATILE,
+ * the key will be volatile, and the key identifier attribute is reset
+ * to @ref PSA_KEY_ID_NULL.
+ */
+static inline void psa_set_key_lifetime(psa_key_attributes_t *attributes,
+ psa_key_lifetime_t lifetime)
+{
+ attributes->lifetime = lifetime;
+}
+
+/**
+ * @brief Retrieve the lifetime from key attributes.
+ *
+ * @param attributes The key attribute object to query.
+ *
+ * @return @ref psa_key_lifetime_t The lifetime value stored in the attribute object.
+ */
+static inline psa_key_lifetime_t psa_get_key_lifetime(const psa_key_attributes_t *attributes)
+{
+ return attributes->lifetime;
+}
+
+/**
+ * @brief Declare the type of a key.
+ *
+ * @details This function overwrites any key type previously set in @c attributes.
+ *
+ * @param attributes The attribute object to write to.
+ * @param type The key type to write. If this is @ref PSA_KEY_TYPE_NONE,
+ * the key type in attributes becomes unspecified.
+ */
+static inline void psa_set_key_type(psa_key_attributes_t *attributes,
+ psa_key_type_t type)
+{
+ attributes->type = type;
+}
+
+/**
+ * @brief Retrieve the key type from key attributes.
+ *
+ * @param attributes The key attribute object to query.
+ *
+ * @return @ref psa_key_type_t The key type stored in the attribute object.
+ */
+static inline psa_key_type_t psa_get_key_type(const psa_key_attributes_t *attributes)
+{
+ return attributes->type;
+}
+
+/**
+ * @brief Declare usage flags for a key.
+ *
+ * @details Usage flags are part of a key’s policy. They encode what kind of operations are
+ * permitted on the key. For more details, see Key policies.
+ *
+ * This function overwrites any usage flags previously set in attributes.
+ *
+ * @param attributes The attribute object to write to.
+ * @param usage_flags The usage flags to write.
+ */
+static inline void psa_set_key_usage_flags(psa_key_attributes_t *attributes,
+ psa_key_usage_t usage_flags)
+{
+ attributes->policy.usage = usage_flags;
+}
+
+/**
+ * @brief Retrieve the usage flags from key attributes.
+ *
+ * @param attributes The key attribute object to query.
+ *
+ * @return @ref psa_key_usage_t The usage flags stored in the attribute object.
+ */
+static inline psa_key_usage_t psa_get_key_usage_flags(const psa_key_attributes_t *attributes)
+{
+ return attributes->policy.usage;
+}
+
+/**
+ * @brief Reset a key attribute object to a freshly initialized state.
+ *
+ * @details The attribute object must be initialized as described in the documentation of the type
+ * @ref psa_key_attributes_t before calling this function. Once the object has been
+ * initialized, this function can be called at any time.
+ *
+ * This function frees any auxiliary resources that the object might contain.
+ *
+ * @param attributes The attribute object to reset.
+ */
+static inline void psa_reset_key_attributes(psa_key_attributes_t *attributes)
+{
+ *attributes = psa_key_attributes_init();
+}
+
+/**
+ * @brief Retrieve the attributes of a key.
+ *
+ * @details This function first resets the attribute object as with @ref psa_reset_key_attributes().
+ * It then copies the attributes of the given key into the given attribute object.
+ *
+ * @note This function clears any previous content from the attribute object and therefore
+ * expects it to be in a valid state. In particular, if this function is called on a newly
+ * allocated attribute object, the attribute object must be initialized before calling
+ * this function.
+ *
+ * @param key Identifier of the key to query.
+ * @param attributes On entry, @c *attributes must be in a valid state. On successful return,
+ * it contains the attributes of the key. On failure, it is equivalent
+ * to a freshly-initialized attribute object.
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INVALID_HANDLE
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_get_key_attributes(psa_key_id_t key,
+ psa_key_attributes_t *attributes);
+
+/**
+ * @brief Abort a hash operation.
+ *
+ * @details Aborting an operation frees all associated resources except for the @p operation
+ * structure itself. Once aborted, the operation object can be reused for another operation
+ * by calling @ref psa_hash_setup() again.
+ *
+ * You may call this function any time after the operation object has
+ * been initialized by one of the methods described in @ref psa_hash_operation_t.
+ *
+ * In particular, calling @ref psa_hash_abort() after the operation has been
+ * terminated by a call to @ref psa_hash_abort(), @ref psa_hash_finish() or
+ * @ref psa_hash_verify() is safe and has no effect.
+ *
+ * @param operation Initialized hash operation.
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_HARDWARE_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_BAD_STATE The library has not been previously initialized
+ * by @ref psa_crypto_init(). It is
+ * implementation-dependent whether a failure to
+ * initialize results in this error code.
+ */
+psa_status_t psa_hash_abort(psa_hash_operation_t *operation);
+
+/**
+ * @brief Clone a hash operation.
+ *
+ * @details This function copies the state of an ongoing hash operation to a new operation object.
+ * In other words, this function is equivalent to calling @ref psa_hash_setup() on
+ * @p target_operation with the same algorithm that @p source_operation was set up for,
+ * then @ref psa_hash_update() on @p target_operation with the same input that that was
+ * passed to @p source_operation. After this function returns, the two objects are
+ * independent, i.e. subsequent calls involving one of the objects do not affect the other
+ * object.
+ *
+ * @param source_operation The active hash operation to clone.
+ * @param target_operation The operation object to set up.
+ * It must be initialized but not active.
+ *
+ * @return @ref PSA_SUCCESS
+ *@return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The @p source_operation state is not valid:
+ * it must be active.
+ * - The @p target_operation state is not valid:
+ * it must be inactive.
+ * - The library requires initializing by a call
+ * to @ref psa_crypto_init().
+ *@return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ *@return @ref PSA_ERROR_HARDWARE_FAILURE
+ *@return @ref PSA_ERROR_CORRUPTION_DETECTED
+ *@return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ */
+psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
+ psa_hash_operation_t *target_operation);
+
+/**
+ * @brief Calculate the hash (digest) of a message and compare it with a reference value.
+ *
+ * @param alg The hash algorithm to compute: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_HASH(@p alg) is true.
+ * @param input Buffer containing the message to hash.
+ * @param input_length Size of the input buffer in bytes.
+ * @param hash Buffer containing the expected hash value.
+ * @param hash_length Size of the hash buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success. The expected hash is identical to the
+ * actual hash of the input.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated hash of the message does not match
+ * the value in hash.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @p alg is not a hash algorithm.
+ * - @p input_length is too large for alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @p alg is not supported or is not a hash
+ * algorithm.
+ * - @p input_length is too large for the
+ * implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_compare(psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *hash,
+ size_t hash_length);
+
+/**
+ * @brief Calculate the hash (digest) of a message.
+ *
+ * @note To verify the hash of a message against an expected value,
+ * use @ref psa_hash_compare() instead.
+ *
+ * @param alg The hash algorithm to compute: a value of type @ref psa_algorithm_t
+ * such that @ref PSA_ALG_IS_HASH(@p alg) is true.
+ * @param input Buffer containing the message to hash.
+ * @param input_length Size of the @p input buffer in bytes.
+ * @param hash Buffer where the hash is to be written.
+ * @param hash_size Size of the @p hash buffer in bytes.
+ * This must be at least @ref PSA_HASH_LENGTH(@p alg).
+ * @param hash_length On success, the number of bytes that make up the hash value.
+ * This is always @ref PSA_HASH_LENGTH(@p alg).
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*hash_length) bytes of
+ * @p hash contain the hash value.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the hash buffer is too small.
+ * @ref PSA_HASH_LENGTH() can be used to determine
+ * a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @p alg is not a hash algorithm
+ * - @p input_length is too large for alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a hash algorithm.
+ * - @c input_length is too large for the implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_compute(psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+
+/**
+ * @brief Finish the calculation of the hash of a message.
+ *
+ * @details The application must call @ref psa_hash_setup() before calling this function.
+ * This function calculates the hash of the message formed by concatenating
+ * the inputs passed to preceding calls to @ref psa_hash_update().
+ *
+ * When this function returns successfully, the operation becomes inactive.
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling @ref psa_hash_abort().
+ *
+ * @warning Applications should not call this function if they expect
+ * a specific value for the hash. Call @ref psa_hash_verify() instead.
+ * Beware that comparing integrity or authenticity data such as
+ * hash values with a function such as @c memcmp is risky
+ * because the time taken by the comparison may leak information
+ * about the hashed data which could allow an attacker to guess
+ * a valid hash and thereby bypass security controls.
+ *
+ * @param operation Active hash operation.
+ * @param hash Buffer where the hash is to be written.
+ * @param hash_size Size of the @p hash buffer in bytes. This must be at least
+ * @ref PSA_HASH_LENGTH(@p alg) where @p alg is the algorithm that
+ * the operation performs.
+ * @param hash_length On success, the number of bytes that make up the hash value. This is always
+ * @ref PSA_HASH_LENGTH(@p alg) where @p alg is the hash algorithm that is
+ * calculated.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*hash_length) bytes of @p hash
+ * contain the hash value.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the hash buffer is too small.
+ * @ref PSA_HASH_LENGTH() can be used to determine
+ * a sufficient buffer size.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+
+/**
+ * @brief Set up a multi-part hash operation using the hash suspend state from a previously
+ * suspended hash operation.
+ *
+ * @details See @ref psa_hash_suspend() for an example of how to use this function to suspend
+ * and resume a hash operation.
+ *
+ * After a successful call to @ref psa_hash_resume(), the application must eventually
+ * terminate the operation. The following events terminate an operation:
+ * - A successful call to @ref psa_hash_finish(), @ref psa_hash_verify() or
+ * @ref psa_hash_suspend().
+ * - A call to @ref psa_hash_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized
+ * as per the documentation for @ref psa_hash_operation_t and not
+ * yet in use.
+ * @param hash_state A buffer containing the suspended hash state which is to be
+ * resumed. This must be in the format output by @ref
+ * psa_hash_suspend().
+ * @param hash_state_length Length of hash_state in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * inactive.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @p hash_state does not correspond to a valid hash
+ * suspend state. See Hash suspend state format for
+ * the definition.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The provided hash suspend state is for an algorithm
+ * that is not supported.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_resume(psa_hash_operation_t *operation,
+ const uint8_t *hash_state,
+ size_t hash_state_length);
+
+/**
+ * @brief Set up a multipart hash operation.
+ *
+ * @details The sequence of operations to calculate a hash (message digest)
+ * is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_hash_operation_t, e.g. @ref PSA_HASH_OPERATION_INIT.
+ * -# Call @ref psa_hash_setup() to specify the algorithm.
+ * -# Call @ref psa_hash_update() zero, one or more times, passing a fragment of the
+ * message each time. The hash that is calculated is the hash of the concatenation
+ * of these messages in order.
+ * -# To calculate the hash, call @ref psa_hash_finish(). To compare the hash with an
+ * expected value, call @ref psa_hash_verify().
+ *
+ * If an error occurs at any step after a call to @ref psa_hash_setup(), the operation
+ * will need to be reset by a call to @ref psa_hash_abort(). The application may call
+ * @ref psa_hash_abort() at any time after the operation has been initialized.
+ *
+ * After a successful call to @ref psa_hash_setup(), the application must eventually
+ * terminate the operation. The following events terminate an operation:
+ * - A successful call to @ref psa_hash_finish() or @ref psa_hash_verify().
+ * - A call to @ref psa_hash_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized as per the
+ * documentation for @ref psa_hash_operation_t and not yet in use.
+ * @param alg The hash algorithm to compute: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_HASH(@p alg) is true.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * inactive.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @p alg is not a hash algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @p alg is not supported or is not a hash algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Halt the hash operation and extract the intermediate state of the hash computation.
+ *
+ * @details The application must call @ref psa_hash_setup() or @ref psa_hash_resume() before
+ * calling this function. This function extracts an intermediate state of the hash
+ * computation of the message formed by concatenating the inputs passed to preceding
+ * calls to @ref psa_hash_update().
+ *
+ * This function can be used to halt a hash operation, and then resume the hash operation
+ * at a later time, or in another application, by transferring the extracted hash suspend
+ * state to a call to @ref psa_hash_resume().
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_hash_abort().
+ *
+ * Hash suspend and resume is not defined for the SHA3 family of hash algorithms.
+ * Hash suspend state defines the format of the output from @ref psa_hash_suspend().
+ *
+ * @warning Applications must not use any of the hash suspend state as if it was a hash output.
+ * Instead, the suspend state must only be used to resume a hash operation, and
+ * @ref psa_hash_finish() or @ref psa_hash_verify() can then calculate or verify the
+ * final hash value.
+ *
+ * ## Usage
+ * The sequence of operations to suspend and resume a hash operation is as follows:
+ * -# Compute the first part of the hash.
+ * -# Allocate an operation object and initialize it as described in the
+ * documentation for @ref psa_hash_operation_t.
+ * -# Call @ref psa_hash_setup() to specify the algorithm.
+ * -# Call @ref psa_hash_update() zero, one or more times, passing a fragment
+ * of the message each time.
+ * -# Call @ref psa_hash_suspend() to extract the hash suspend state into a buffer.
+ * -# Pass the hash state buffer to the application which will resume the operation.
+ * -# Compute the rest of the hash.
+ * -# Allocate an operation object and initialize it as described in the
+ * documentation for @ref psa_hash_operation_t.
+ * -# Call @ref psa_hash_resume() with the extracted hash state.
+ * -# Call @ref psa_hash_update() zero, one or more times, passing a fragment
+ * of the message each time.
+ * -# To calculate the hash, call @ref psa_hash_finish(). To compare the hash
+ * with an expected value, call @ref psa_hash_verify().
+ *
+ * If an error occurs at any step after a call to @ref psa_hash_setup() or
+ * @ref psa_hash_resume(), the operation will need to be reset by a call to
+ * @ref psa_hash_abort(). The application can call @ref psa_hash_abort() at
+ * any time after the operation has been initialized.
+ *
+ * @param operation Active hash operation.
+ * @param hash_state Buffer where the hash suspend state is to be written.
+ * @param hash_state_size Size of the hash_state buffer in bytes. This must be
+ * appropriate for the selected algorithm:
+ * - A sufficient output size is @ref
+ * PSA_HASH_SUSPEND_OUTPUT_SIZE(@p alg) where alg is
+ * the algorithm that was used to set up the operation.
+ * - @ref PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE evaluates to
+ * the maximum output size of any supported hash algorithm.
+ * @param hash_state_length On success, the number of bytes that make up the hash suspend state.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @p (*hash_state_length) bytes of
+ * @p hash_state contain the intermediate hash state.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the hash_state buffer is too small.
+ * @ref PSA_HASH_SUSPEND_OUTPUT_SIZE() or
+ * @ref PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE can be used
+ * to determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The hash algorithm being computed does not support
+ * suspend and resume.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_suspend(psa_hash_operation_t *operation,
+ uint8_t *hash_state,
+ size_t hash_state_size,
+ size_t *hash_state_length);
+
+/**
+ * @brief Add a message fragment to a multi-part hash operation.
+ *
+ * @details The application must call @ref psa_hash_setup() before calling this function.
+ * If this function returns an error status, the operation enters an error
+ * state and must be aborted by calling @ref psa_hash_abort().
+ *
+ * @param operation Active hash operation.
+ * @param input Buffer containing the message fragment to hash.
+ * @param input_length Size of the @p input buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input for the operation is too large for the
+ * hash algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The total input for the operation is too large for the
+ * implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_update(psa_hash_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Finish the calculation of the hash of a message and compare it with an expected value.
+ *
+ * @details The application must call @ref psa_hash_setup() before calling this function. This
+ * function calculates the hash of the message formed by concatenating the inputs passed
+ * to preceding calls to @ref psa_hash_update(). It then compares the calculated hash with
+ * the expected hash passed as a parameter to this function.
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_hash_abort().
+ *
+ * @note Implementations shall make the best effort to ensure that the comparison between the
+ * actual hash and the expected hash is performed in constant time.
+ *
+ * @param operation Active hash operation.
+ * @param hash Buffer containing the expected hash value.
+ * @param hash_length Size of the @p hash buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success. The expected hash is identical to the
+ * actual hash of the message.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * active.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated hash of the message does not match
+ * the value in hash.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_hash_verify(psa_hash_operation_t *operation,
+ const uint8_t *hash,
+ size_t hash_length);
+
+/**
+ * @brief Built-in key import function.
+ *
+ * @details Copies a plain key into local memory. This function is used by the implementation,
+ * when an imported key is stored only in local memory.
+ *
+ * @param attributes The attributes for the new key.
+ * This function uses the attributes as follows:
+ * - The key type is required, and determines how the data buffer is
+ * interpreted.
+ * - The key size is always determined from the data buffer. If the
+ * key size in attributes is nonzero, it must be equal to the size
+ * determined from data.
+ * - The key permitted-algorithm policy is required for keys that will
+ * be used for a cryptographic operation, see Permitted algorithms.
+ * - The key usage flags define what operations are permitted with the
+ * key, see Key usage flags.
+ * - The key lifetime and identifier are required for a persistent key.
+ * @note This is an input parameter: it is not updated with the
+ * final key attributes. The final attributes of the new key
+ * can be queried by calling @ref psa_get_key_attributes()
+ * with the key’s identifier.
+ * @param data Buffer containing the key data. The content of this buffer is
+ * interpreted according to the type declared in attributes. All
+ * implementations must support at least the format described in
+ * the documentation of @ref psa_export_key() or @ref
+ * psa_export_public_key() for the chosen type.
+ * Implementations can support other formats, but be conservative in
+ * interpreting the key data: it is recommended that implementations
+ * reject content if it might be erroneous, for example, if it is the
+ * wrong type or is truncated.
+ * @param data_length Size of the data buffer in bytes.
+ * @param key_buffer Pointer to buffer containing the plain text key material
+ * @param key_buffer_size Size of @p key_buffer in bytes
+ * @param key_buffer_length Size of the key buffer
+ * @param bits Size of the key in bits
+ *
+ * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material
+ * and the key’s metadata have been saved to persistent
+ * storage.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - The key size is nonzero, and is incompatible with
+ * the key data in @p data.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The key attributes, as a whole, are not supported,
+ * either by the implementation in general or in the
+ * specified storage location.
+ */
+psa_status_t psa_builtin_import_key(const psa_key_attributes_t *attributes,
+ const uint8_t *data, size_t data_length,
+ uint8_t *key_buffer, size_t key_buffer_size,
+ size_t *key_buffer_length, size_t *bits);
+
+/**
+ * @brief Import a key in binary format.
+ *
+ * @details This function supports any output from @ref psa_export_key(). Refer to the
+ * documentation of @ref psa_export_public_key() for the format of public keys
+ * and to the documentation of @ref psa_export_key() for the format for other key types.
+ *
+ * The key data determines the key size. The attributes can optionally specify a key size;
+ * in this case it must match the size determined from the key data. A key size of 0 in
+ * attributes indicates that the key size is solely determined by the key data.
+ *
+ * Implementations must reject an attempt to import a key of size 0.
+ *
+ * This specification defines a single format for each key type. Implementations can
+ * optionally support other formats in addition to the standard format. It is recommended
+ * that implementations that support other formats ensure that the formats are clearly
+ * unambiguous, to minimize the risk that an invalid input is accidentally interpreted
+ * according to a different format.
+ *
+ * @note The PSA Crypto API does not support asymmetric private key objects outside of a key
+ * pair. To import a private key, the attributes must specify the corresponding key pair
+ * type. Depending on the key type, either the import format contains the public key data
+ * or the implementation will reconstruct the public key from the private key as needed.
+ *
+ * @param attributes The attributes for the new key.
+ * This function uses the attributes as follows:
+ * - The key type is required, and determines how the data buffer is
+ * interpreted.
+ * - The key size is always determined from the data buffer. If the key
+ * size in attributes is nonzero, it must be equal to the size
+ * determined from data.
+ * - The key permitted-algorithm policy is required for keys that will be
+ * used for a cryptographic operation, see Permitted algorithms.
+ * - The key usage flags define what operations are permitted with the key,
+ * see Key usage flags.
+ * - The key lifetime and identifier are required for a persistent key.
+ * @note This is an input parameter: it is not updated with the final key
+ * attributes. The final attributes of the new key can be queried
+ * by calling @ref psa_get_key_attributes() with the key’s identifier.
+ *
+ * @param data Buffer containing the key data. The content of this buffer is interpreted
+ * according to the type declared in attributes. All implementations must
+ * support at least the format described in the documentation of
+ * @ref psa_export_key() or @ref psa_export_public_key() for the chosen type.
+ * Implementations can support other formats, but be conservative in
+ * interpreting the key data: it is recommended that implementations reject
+ * content if it might be erroneous, for example, if it is the wrong type or
+ * is truncated.
+ * @param data_length Size of the data buffer in bytes.
+ * @param key On success, an identifier for the newly created key.
+ * @ref PSA_KEY_ID_NULL on failure.
+ *
+ * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material
+ * and the key’s metadata have been saved to persistent
+ * storage.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_NOT_PERMITTED The implementation does not permit creating a
+ * key with the specified attributes due to some
+ * implementation-specific policy.
+ * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key,
+ * and there is already a persistent key with the given
+ * identifier.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - The key type is invalid.
+ * - The key size is nonzero, and is incompatible with
+ * the key data in @p data.
+ * - The key lifetime is invalid.
+ * - The key identifier is not valid for the key
+ * lifetime.
+ * - The key usage flags include invalid values.
+ * - The key’s permitted-usage algorithm is invalid.
+ * - The key attributes, as a whole, are invalid.
+ * - The key data is not correctly formatted for the key
+ * type.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The key attributes, as a whole, are not supported,
+ * either by the implementation in general or in the
+ * specified storage location.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
+ const uint8_t *data,
+ size_t data_length,
+ psa_key_id_t *key);
+
+/**
+ * @brief Abort a key derivation operation.
+ *
+ * @details Aborting an operation frees all associated resources except for the operation object
+ * itself. Once aborted, the operation object can be reused for another operation by
+ * calling @ref psa_key_derivation_setup() again.
+ *
+ * This function can be called at any time after the operation object has been initialized
+ * as described in @ref psa_key_derivation_operation_t.
+ *
+ * In particular, it is valid to call @ref psa_key_derivation_abort() twice, or to call
+ * @ref psa_key_derivation_abort() on an operation that has not been set up.
+ *
+ * @param operation The operation to abort.
+ *
+ * @return @ref PSA_SUCCESS Success. The operation object can now be discarded or
+ * reused.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_key_derivation_abort(psa_key_derivation_operation_t *operation);
+
+/**
+ * @brief Retrieve the current capacity of a key derivation operation.
+ *
+ * @details The capacity of a key derivation is the maximum number of bytes that it can return.
+ * Reading N bytes of output from a key derivation operation reduces its capacity by at
+ * least N. The capacity can be reduced by more than N in the following situations:
+ * - Calling @ref psa_key_derivation_output_key() can reduce the capacity by more than
+ * the key size, depending on the type of key being generated. See @ref
+ * psa_key_derivation_output_key() for details of the key derivation process.
+ * - When the @ref psa_key_derivation_operation_t object is operating as a deterministic
+ * random bit generator (DBRG), which reduces capacity in whole blocks, even when less
+ * than a block is read.
+ *
+ * @param operation The operation to query.
+ * @param capacity On success, the capacity of the operation.
+ *
+ * @return @ref PSA_SUCCESS Success. The maximum number of bytes that this key
+ * derivation can return is (@c *capacity).
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_key_derivation_get_capacity(const psa_key_derivation_operation_t *operation,
+ size_t *capacity);
+
+/**
+ * @brief Provide an input for key derivation or key agreement.
+ *
+ * @details Which inputs are required and in what order depends on the algorithm. Refer to the
+ * documentation of each key derivation or key agreement algorithm for information.
+ *
+ * This function passes direct inputs, which is usually correct for non-secret inputs.
+ * To pass a secret input, which is normally in a key object, call @ref
+ * psa_key_derivation_input_key() instead of this function. Refer to the documentation
+ * of individual step types (@c PSA_KEY_DERIVATION_INPUT_xxx values of type @ref
+ * psa_key_derivation_step_t) for more information.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_key_derivation_abort().
+ *
+ * @param operation The key derivation operation object to use. It must have been set up with
+ * @ref psa_key_derivation_setup() and must not have produced any output yet.
+ * @param step Which step the input data is for.
+ * @param data Input data to use.
+ * @param data_length Size of the data buffer in bytes.
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid for this input step.
+ * This can happen if the application provides a step
+ * out of order or repeats a step that may not be
+ * repeated.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c step is not compatible with the operation’s
+ * algorithm.
+ * - @c step does not allow direct inputs.
+ * - @c data_length is too small or too large for step in
+ * this particular algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c step is not supported with the operation’s
+ * algorithm.
+ * - @c data_length is is not supported for step in this
+ * particular algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_input_bytes(psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ const uint8_t *data,
+ size_t data_length);
+
+/**
+ * @brief Provide a numeric input for key derivation or key agreement.
+ *
+ * @details Which inputs are required and in what order depends on the algorithm. However, when an
+ * algorithm requires a particular order, numeric inputs usually come first as they tend
+ * to be configuration parameters. Refer to the documentation of each key derivation or
+ * key agreement algorithm for information.
+ *
+ * This function is used for inputs which are fixed-size non-negative integers.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_key_derivation_abort().
+ *
+ * @param operation The key derivation operation object to use. It must have been set up with
+ * @ref psa_key_derivation_setup() and must not have produced any output yet.
+ * @param step Which step the input data is for.
+ * @param value The value of the numeric input.
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid for this input step.
+ * This can happen if the application provides a step
+ * out of order or repeats a step that may not be
+ * repeated.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c step is not compatible with the operation’s
+ * algorithm.
+ * - @c step does not allow numerical inputs.
+ * - @c value is not valid for step in the operation’s
+ * algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c step is not supported with the operation’s
+ * algorithm.
+ * - @c value is not supported for step in the operation’s
+ * algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_input_integer( psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ uint64_t value);
+
+/**
+ * @brief Provide an input for key derivation in the form of a key.
+ *
+ * @details Which inputs are required and in what order depends on the algorithm. Refer to the
+ * documentation of each key derivation or key agreement algorithm for information.
+ *
+ * This function obtains input from a key object, which is usually correct for secret
+ * inputs or for non-secret personalization strings kept in the key store. To pass a
+ * non-secret parameter which is not in the key store, call @ref
+ * psa_key_derivation_input_bytes() instead of this function. Refer to the documentation
+ * of individual step types (@c PSA_KEY_DERIVATION_INPUT_xxx values of type @ref
+ * psa_key_derivation_step_t) for more information.
+ *
+ * @note Once all inputs steps are completed, the following operations are permitted:
+ * - @ref psa_key_derivation_output_bytes() — if each input was either a direct
+ * input or a key with usage flag @ref PSA_KEY_USAGE_DERIVE.
+ * - @ref psa_key_derivation_output_key() — if the input for step @ref
+ * PSA_KEY_DERIVATION_INPUT_SECRET or @ref PSA_KEY_DERIVATION_INPUT_PASSWORD was
+ * a key with usage flag @ref PSA_KEY_USAGE_DERIVE, and every other input was
+ * either a direct input or a key with usage flag @ref PSA_KEY_USAGE_DERIVE.
+ * - @ref psa_key_derivation_verify_bytes() — if each input was either a direct
+ * input or a key with usage flag @ref PSA_KEY_USAGE_VERIFY_DERIVATION.
+ * - @ref psa_key_derivation_verify_key() — under the same conditions as @ref
+ * psa_key_derivation_verify_bytes().
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_key_derivation_abort().
+ *
+ * @param operation The key derivation operation object to use. It must have been set up with
+ * @ref psa_key_derivation_setup() and must not have produced any output yet.
+ * @param step Which step the input data is for.
+ * @param key Identifier of the key. The key must have an appropriate type for step, it
+ * must allow the usage @ref PSA_KEY_USAGE_DERIVE or @ref
+ * PSA_KEY_USAGE_VERIFY_DERIVATION (see note), and it must permit the
+ * algorithm used by the operation.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid for this input step.
+ * This can happen if the application provides a step
+ * out of order or repeats a step that may not be
+ * repeated.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key has neither the @ref PSA_KEY_USAGE_DERIVE nor
+ * the @ref PSA_KEY_USAGE_VERIFY_DERIVATION usage flag,
+ * or it does not permit the operation’s algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c step is not compatible with the operation’s
+ * algorithm.
+ * - @c step does not allow key inputs of the given type,
+ * or does not allow key inputs at all.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c step is not supported with the operation’s
+ * algorithm.
+ * - @c Key inputs of the given type are not supported for
+ * step in the operation’s algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_input_key(psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ psa_key_id_t key);
+
+/**
+ * @brief Perform a key agreement and use the shared secret as input to a key derivation.
+ *
+ * @details A key agreement algorithm takes two inputs: a private key @c private_key, and a public
+ * key @c peer_key. The result of this function is passed as input to the key derivation
+ * operation. The output of this key derivation can be extracted by reading from the
+ * resulting operation to produce keys and other cryptographic material.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_key_derivation_abort().
+ *
+ * @param operation The key derivation operation object to use. It must have been set
+ * up with @ref psa_key_derivation_setup() with a key agreement and
+ * derivation algorithm alg: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is true and @ref
+ * PSA_ALG_IS_RAW_KEY_AGREEMENT(@p alg) is false.
+ * The operation must be ready for an input of the type given by step.
+ * @param step Which step the input data is for.
+ * @param private_key Identifier of the private key to use. It must allow the usage @ref
+ * PSA_KEY_USAGE_DERIVE.
+ * @param peer_key Public key of the peer. The peer key must be in the same format that
+ * @ref psa_import_key() accepts for the public key type corresponding to
+ * the type of @c private_key. That is, this function performs the
+ * equivalent of @ref psa_import_key(..., @p peer_key, @p
+ * peer_key_length), with key attributes indicating the public key type
+ * corresponding to the type of @c private_key. For example, for ECC keys,
+ * this means that @c peer_key is interpreted as a point on the curve that
+ * the private key is on. The standard formats for public keys are
+ * documented in the documentation of @ref psa_export_public_key().
+ * @param peer_key_length Size of @c peer_key in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid for this key
+ * agreement step.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c private_key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED @c private_key does not have the @ref
+ * PSA_KEY_USAGE_DERIVE flag, or it does not permit the
+ * operation’s algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - The operation’s algorithm is not a key agreement
+ * algorithm.
+ * - @c step does not allow an input resulting from a key
+ * agreement.
+ * - @c private_key is not compatible with the operation’s
+ * algorithm.
+ * - @c peer_key is not a valid public key corresponding
+ * to @c private_key.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c private_key is not supported for use with the
+ * operation’s algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ psa_key_id_t private_key,
+ const uint8_t *peer_key,
+ size_t peer_key_length);
+
+/**
+ * @brief Read some data from a key derivation operation.
+ *
+ * @details This function calculates output bytes from a key derivation algorithm and returns those
+ * bytes. If the key derivation’s output is viewed as a stream of bytes, this function
+ * consumes the requested number of bytes from the stream and returns them to the caller.
+ * The operation’s capacity decreases by the number of bytes read.
+ *
+ * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA,
+ * the operation enters an error state and must be aborted by calling @ref
+ * psa_key_derivation_abort().
+ *
+ * @param operation The key derivation operation object to read from.
+ * @param output Buffer where the output will be written.
+ * @param output_length Number of bytes to output.
+ *
+ * @return @ref PSA_SUCCESS Success. The first output_length bytes of output
+ * contain the derived data.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * active, with all required input steps complete.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_NOT_PERMITTED One of the inputs was a key whose policy did not
+ * allow @ref PSA_KEY_USAGE_DERIVE.
+ * @return @ref PSA_ERROR_INSUFFICIENT_DATA The operation’s capacity was less than
+ * @c output_length bytes. In this case, the following
+ * occurs:
+ * - No output is written to the output buffer.
+ * - The operation’s capacity is set to zero —
+ * subsequent calls to this function will not
+ * succeed, even with a smaller output buffer.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_output_bytes(psa_key_derivation_operation_t *operation,
+ uint8_t *output,
+ size_t output_length);
+
+/**
+ * @brief Derive a key from an ongoing key derivation operation.
+ *
+ * @details This function calculates output bytes from a key derivation algorithm and uses those
+ * bytes to generate a key deterministically. The key’s location, policy, type and size
+ * are taken from attributes.
+ *
+ * If the key derivation’s output is viewed as a stream of bytes, this function consumes
+ * the required number of bytes from the stream. The operation’s capacity decreases by the
+ * number of bytes used to derive the key.
+ *
+ * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA,
+ * the operation enters an error state and must be aborted by calling @ref
+ * psa_key_derivation_abort().
+ *
+ * How much output is produced and consumed from the operation, and how the key is
+ * derived, depends on the key type.
+ *
+ * - For key types for which the key is an arbitrary sequence of bytes of a given size,
+ * this function is functionally equivalent to calling @ref
+ * psa_key_derivation_output_bytes() and passing the resulting output to @ref
+ * psa_import_key(). However, this function has a security benefit: if the
+ * implementation provides an isolation boundary then the key material is not exposed
+ * outside the isolation boundary. As a consequence, for these key types, this function
+ * always consumes exactly @c (bits/8) bytes from the operation.
+ * The following key types defined in this specification follow this scheme:
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARC4
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_CHACHA20
+ * - @ref PSA_KEY_TYPE_SM4
+ * - @ref PSA_KEY_TYPE_DERIVE
+ * - @ref PSA_KEY_TYPE_HMAC
+ * - @ref PSA_KEY_TYPE_PASSWORD_HASH
+ * - @ref PSA_KEY_TYPE_DES, 64 bits
+ * This function generates a key using the following process:
+ * -# Draw an 8-byte string.
+ * -# Set/clear the parity bits in each byte.
+ * -# If the result is a forbidden weak key, discard the result and return to step 1.
+ * -# Output the string.
+ * - @ref PSA_KEY_TYPE_DES, 192 bits
+ * - @ref PSA_KEY_TYPE_DES, 128 bits
+ * The two or three keys are generated by repeated application of the process used to
+ * generate a DES key.
+ * For example, for 3-key 3DES, if the first 8 bytes specify a weak key and the next 8
+ * bytes do not, discard the first 8 bytes, use the next 8 bytes as the first key, and
+ * continue reading output from the operation to derive the other two keys.
+ * - For Finite-field Diffie-Hellman keys @ref PSA_KEY_TYPE_DH_KEY_PAIR(@p dh_family)
+ * where @c dh_family designates any Diffie-Hellman family.
+ * - ECC keys on a Weierstrass elliptic curve (@ref PSA_KEY_TYPE_ECC_KEY_PAIR(
+ * @p ecc_family) where @c ecc_family designates a Weierstrass curve family.) require
+ * the generation of a private key which is an integer in the range [1, N - 1], where N
+ * is the boundary of the private key domain: N is the prime p for Diffie-Hellman, or
+ * the order of the curve’s base point for ECC.
+ * Let m be the bit size of N, such that 2^m > N >= 2^(m-1). This function generates the
+ * private key using the following process:
+ * -# Draw a byte string of length ceiling(m/8) bytes.
+ * -# If m is not a multiple of 8, set the most significant (8 * ceiling(m/8) - m) bits
+ * of the first byte in the string to zero.
+ * -# Convert the string to integer k by decoding it as a big-endian byte string.
+ * -# If k > N - 2, discard the result and return to step 1.
+ * -# Output k + 1 as the private key.
+ * This method allows compliance to NIST standards, specifically the methods titled
+ * Key-Pair Generation by Testing Candidates in the following publications:
+ * - NIST Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment
+ * Schemes Using Discrete Logarithm Cryptography SP800-56A §5.6.1.1.4 for
+ * Diffie-Hellman keys.
+ * - SP800-56A §5.6.1.2.2 or FIPS Publication 186-4: Digital Signature Standard (DSS)
+ * FIPS186-4 §B.4.2 for elliptic curve keys.
+ * - For ECC keys on a Montgomery elliptic curve (where @ref PSA_KEY_TYPE_ECC_KEY_PAIR
+ * (@ref PSA_ECC_FAMILY_MONTGOMERY)) this function always draws a byte string whose
+ * length is determined by the curve, and sets the mandatory bits accordingly. That is:
+ * - Curve25519 (@ref PSA_ECC_FAMILY_MONTGOMERY, 255 bits): draw a 32-byte string and
+ * process it as specified in Elliptic Curves for Security RFC7748 §5.
+ * - Curve448 (@ref PSA_ECC_FAMILY_MONTGOMERY, 448 bits): draw a 56-byte string and
+ * process it as specified in RFC7748 §5.
+ *
+ * In all cases, the data that is read is discarded from the operation. The operation’s
+ * capacity is decreased by the number of bytes read.
+ *
+ * For algorithms that take an input step @ref PSA_KEY_DERIVATION_INPUT_SECRET, the input
+ * to that step must be provided with @ref psa_key_derivation_input_key(). Future versions
+ * of this specification might include additional restrictions on the derived key based on
+ * the attributes and strength of the secret key.
+ *
+ * @param attributes The attributes for the new key. This function uses the attributes as
+ * follows:
+ * - The key type is required. It cannot be an asymmetric public key.
+ * - The key size is required. It must be a valid size for the key type.
+ * - The key permitted-algorithm policy is required for keys that will be
+ * used for a cryptographic operation.
+ * - If the key type to be created is @ref PSA_KEY_TYPE_PASSWORD_HASH,
+ * then the permitted-algorithm policy must be the same as the current
+ * operation’s algorithm.
+ * - The key usage flags define what operations are permitted with the
+ * key.
+ * - The key lifetime and identifier are required for a persistent key.
+ * @note This is an input parameter: it is not updated with the final
+ * key attributes. The final attributes of the new key can be
+ * queried by calling @ref psa_get_key_attributes() with the key’s
+ * identifier.
+ * @param operation The key derivation operation object to read from.
+ * @param key On success, an identifier for the newly created key.
+ * @ref PSA_KEY_ID_NULL on failure.
+ * @return @ref PSA_SUCCESS Success. If the key is persistent, the key material
+ * and the key’s metadata have been saved to persistent
+ * storage.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active,
+ * with all required input steps complete.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_NOT_PERMITTED The following conditions can result in this error:
+ * - The @ref PSA_KEY_DERIVATION_INPUT_SECRET input step
+ * was neither provided through a key, nor the result of
+ * a key agreement.
+ * - One of the inputs was a key whose policy did not
+ * allow @ref PSA_KEY_USAGE_DERIVE.
+ * - The implementation does not permit creating a key
+ * with the specified attributes due to some
+ * implementation-specific policy.
+ * @return @ref PSA_ERROR_ALREADY_EXISTS This is an attempt to create a persistent key, and
+ * there is already a persistent key with the given
+ * identifier.
+ * @return @ref PSA_ERROR_INSUFFICIENT_DATA There was not enough data to create the desired
+ * key. In this case, the following occurs:
+ * - No key is generated.
+ * - The operation’s capacity is set to zero —
+ * subsequent calls to this function will not
+ * succeed, even if they require less data.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - The key type is invalid, or is an asymmetric public
+ * key type.
+ * - The key type is @ref PSA_KEY_TYPE_PASSWORD_HASH, and
+ * the permitted-algorithm policy is not the same as the
+ * current operation’s algorithm.
+ * - The key size is not valid for the key type.
+ * - The key lifetime is invalid.
+ * - The key identifier is not valid for the key lifetime.
+ * - The key usage flags include invalid values.
+ * - The key’s permitted-usage algorithm is invalid.
+ * - The key attributes, as a whole, are invalid.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The key attributes, as a whole, are not supported,
+ * either by the implementation in general or in the
+ * specified storage location.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_output_key(const psa_key_attributes_t *attributes,
+ psa_key_derivation_operation_t *operation,
+ psa_key_id_t *key);
+
+/**
+ * @brief Set the maximum capacity of a key derivation operation.
+ *
+ * @details The capacity of a key derivation operation is the maximum number of bytes that the key
+ * derivation operation can return from this point onwards.
+ *
+ * @param operation The key derivation operation object to modify.
+ * @param capacity The new capacity of the operation. It must be less or equal to the
+ * operation’s current capacity.
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c capacity is larger than the operation’s current
+ * capacity. In this case, the operation object remains
+ * valid and its capacity remains unchanged.
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *operation,
+ size_t capacity);
+
+/**
+ * @brief Set up a key derivation operation.
+ *
+ * @details A key derivation algorithm takes some inputs and uses them to generate a byte stream in
+ * a deterministic way. This byte stream can be used to produce keys and other
+ * cryptographic material.
+ *
+ * A key agreement and derivation algorithm uses a key agreement protocol to provide a
+ * shared secret which is used for the key derivation. See @ref
+ * psa_key_derivation_key_agreement().
+ *
+ * To derive a key:
+ * -# Start with an initialized object of type @ref psa_key_derivation_operation_t.
+ * -# Call @ref psa_key_derivation_setup() to select the algorithm.
+ * -# Provide the inputs for the key derivation by calling @ref
+ * psa_key_derivation_input_bytes() or @ref psa_key_derivation_input_key() as
+ * appropriate. Which inputs are needed, in what order, whether keys are permitted,
+ * and what type of keys depends on the algorithm.
+ * -# Optionally set the operation’s maximum capacity with @ref
+ * psa_key_derivation_set_capacity(). This can be done before, in the middle of, or
+ * after providing inputs. For some algorithms, this step is mandatory because the
+ * output depends on the maximum capacity.
+ * -# To derive a key, call @ref psa_key_derivation_output_key(). To derive a byte string
+ * for a different purpose, call @ref psa_key_derivation_output_bytes(). Successive
+ * calls to these functions use successive output bytes calculated by the key
+ * derivation algorithm.
+ * -# Clean up the key derivation operation object with @ref psa_key_derivation_abort().
+ *
+ * If this function returns an error, the key derivation operation object is not changed.
+ *
+ * If an error occurs at any step after a call to @ref psa_key_derivation_setup(), the
+ * operation will need to be reset by a call to @ref psa_key_derivation_abort().
+ *
+ * Implementations must reject an attempt to derive a key of size 0.
+ *
+ * @param operation The key derivation operation object to set up. It must have been
+ * initialized but not set up yet.
+ * @param alg The algorithm to compute. This must be one of the following:
+ * - A key derivation algorithm: a value of type @ref psa_algorithm_t
+ * such that @ref PSA_ALG_IS_KEY_DERIVATION(@p alg) is true.
+ * - A key agreement and derivation algorithm: a value of type @ref
+ * psa_algorithm_t such that @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is
+ * true and @ref PSA_ALG_IS_RAW_KEY_AGREEMENT(@p alg) is false.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be inactive.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT @c alg is neither a key derivation algorithm, nor a key
+ * agreement and derivation algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED @c alg is not supported or is not a key derivation
+ * algorithm, or a key agreement and derivation algorithm.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Compare output data from a key derivation operation to an expected value.
+ *
+ * @details This function calculates output bytes from a key derivation algorithm and compares
+ * those bytes to an expected value. If the key derivation’s output is viewed as a stream
+ * of bytes, this function destructively reads @c output_length bytes from the stream
+ * before comparing them with @c expected_output. The operation’s capacity decreases by
+ * the number of bytes read.
+ *
+ * This is functionally equivalent to the following code:
+ * @code
+ * uint8_t tmp[output_length];
+ * psa_key_derivation_output_bytes(operation, tmp, output_length);
+ * if (memcmp(expected_output, tmp, output_length) != 0)
+ * return PSA_ERROR_INVALID_SIGNATURE;
+ * @endcode
+ *
+ * However, calling @ref psa_key_derivation_verify_bytes() works even if the key’s policy
+ * does not allow output of the bytes.
+ *
+ * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA or
+ * @ref PSA_ERROR_INVALID_SIGNATURE, the operation enters an error state and must be
+ * aborted by calling @ref psa_key_derivation_abort().
+ *
+ * @note Implementations must make the best effort to ensure that the comparison between
+ * the actual key derivation output and the expected output is performed in
+ * constant time.
+ *
+ * @param operation The key derivation operation object to read from.
+ * @param expected_output Buffer containing the expected derivation output.
+ * @param output_length Length ot the expected output. This is also the number of bytes that
+ * will be read.
+ *
+ * @return @ref PSA_SUCCESS Success. The output of the key derivation operation
+ * matches expected_output.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * active, with all required input steps complete.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_NOT_PERMITTED One of the inputs is a key whose policy does not
+ * permit @ref PSA_KEY_USAGE_VERIFY_DERIVATION.
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The output of the key derivation operation does
+ * not match the value in expected_output.
+ * @return @ref PSA_ERROR_INSUFFICIENT_DATA The operation’s capacity was less than
+ * @c output_length bytes. In this case, the
+ * operation’s capacity is set to zero — subsequent
+ * calls to this function will not succeed, even with
+ * a smaller expected output length.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_verify_bytes(psa_key_derivation_operation_t *operation,
+ const uint8_t *expected_output,
+ size_t output_length);
+
+/**
+ * @brief Compare output data from a key derivation operation to an expected value stored in a
+ * key.
+ *
+ * @details This function calculates output bytes from a key derivation algorithm and compares
+ * those bytes to an expected value, provided as key of type @ref
+ * PSA_KEY_TYPE_PASSWORD_HASH. If the key derivation’s output is viewed as a stream of
+ * bytes, this function destructively reads the number of bytes corresponding to the
+ * length of the expected key from the stream before comparing them with the key value.
+ * The operation’s capacity decreases by the number of bytes read.
+ *
+ * This is functionally equivalent to exporting the expected key and calling @ref
+ * psa_key_derivation_verify_bytes() on the result, except that it works when the key
+ * cannot be exported.
+ *
+ * If this function returns an error status other than @ref PSA_ERROR_INSUFFICIENT_DATA or
+ * @ref PSA_ERROR_INVALID_SIGNATURE, the operation enters an error state and must be
+ * aborted by calling @ref psa_key_derivation_abort().
+ *
+ * @note Implementations must make the best effort to ensure that the comparison between
+ * the actual key derivation output and the expected output is performed in
+ * constant time.
+ *
+ * @param operation The key derivation operation object to read from.
+ * @param expected A key of type @ref PSA_KEY_TYPE_PASSWORD_HASH containing the expected
+ * output. The key must allow the usage @ref PSA_KEY_USAGE_VERIFY_DERIVATION,
+ * and the permitted algorithm must match the operation’s algorithm.
+ * The value of this key is typically computed by a previous call to @ref
+ * psa_key_derivation_output_key().
+
+ * @return @ref PSA_SUCCESS Success. The output of the key derivation operation
+ * matches the expected key value.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be
+ * active, with all required input steps complete.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c expected is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The following conditions can result in this error:
+ * - The key does not have the @ref
+ * PSA_KEY_USAGE_VERIFY_DERIVATION flag, or it does
+ * not permit the requested algorithm.
+ * - One of the inputs is a key whose policy does not
+ * permit @ref PSA_KEY_USAGE_VERIFY_DERIVATION.
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The output of the key derivation operation does not
+ * match the value of the expected key.
+ * @return @ref PSA_ERROR_INSUFFICIENT_DATA The operation’s capacity was less than the length
+ * of the @c expected key. In this case, the
+ * operation’s capacity is set to zero — subsequent
+ * calls to this function will not succeed, even with
+ * a smaller expected key length.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The key type is not @ref PSA_KEY_TYPE_PASSWORD_HASH.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_key_derivation_verify_key(psa_key_derivation_operation_t *operation,
+ psa_key_id_t expected);
+
+/**
+ * @brief Abort a MAC operation.
+ *
+ * @details Aborting an operation frees all associated resources except for the operation object
+ * itself. Once aborted, the operation object can be reused for another operation by
+ * calling @ref psa_mac_sign_setup() or @ref psa_mac_verify_setup() again.
+ *
+ * This function can be called any time after the operation object has been initialized by
+ * one of the methods described in @ref psa_mac_operation_t.
+ *
+ * In particular, calling @ref psa_mac_abort() after the operation has been terminated
+ * by a call to @ref psa_mac_abort(), @ref psa_mac_sign_finish() or @ref
+ * psa_mac_verify_finish() is safe and has no effect.
+ *
+ * @param operation Initialized MAC operation.
+ * @return @ref PSA_SUCCESS Success. The operation object can now be discarded or
+ * reused.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_mac_abort(psa_mac_operation_t *operation);
+
+/**
+ * @brief Calculate the message authentication code (MAC) of a message.
+ *
+ * @note To verify the MAC of a message against an expected value, use @ref psa_mac_verify()
+ * instead. Beware that comparing integrity or authenticity data such as MAC values with a
+ * function such as @c memcmp() is risky because the time taken by the comparison might
+ * leak information about the MAC value which could allow an attacker to guess a valid MAC
+ * and thereby bypass security controls.
+ *
+ * @param key Identifier of the key to use for the operation. It must allow the usage
+ * @ref PSA_KEY_USAGE_SIGN_MESSAGE.
+ * @param alg The MAC algorithm to compute (PSA_ALG_XXX value such that @ref
+ * PSA_ALG_IS_MAC(@p alg) is true).
+ * @param input Buffer containing the input message.
+ * @param input_length Size of the input buffer in bytes.
+ * @param mac Buffer where the MAC value is to be written.
+ * @param mac_size Size of the mac buffer in bytes. This must be appropriate for the
+ * selected algorithm and key:
+ * - The exact MAC size is @ref PSA_MAC_LENGTH(@p key_type, @p key_bits,
+ * @p alg) where @c key_type and @c key_bits are attributes of the key
+ * used to compute the MAC.
+ * - @ref PSA_MAC_MAX_SIZE evaluates to the maximum MAC size of any
+ * supported MAC algorithm.
+ * @param mac_length On success, the number of bytes that make up the MAC value.
+ *
+ * @return @ref PSA_SUCCESS Success. The first @c (*mac_length) bytes of @c mac contain
+ * the MAC value.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit
+ * the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the mac buffer is too small. @ref
+ * PSA_MAC_LENGTH() or @ref PSA_MAC_MAX_SIZE can be used
+ * to determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a MAC algorithm.
+ * - @c key is not compatible with @c alg.
+ * - @c input_length is too large for @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a MAC algorithm.
+ * - @c key is not supported for use with @c alg.
+ * - @c input_length is too large for the implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_compute(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+
+/**
+ * @brief Finish the calculation of the MAC of a message.
+ *
+ * @details The application must call @ref psa_mac_sign_setup() before calling this function. This
+ * function calculates the MAC of the message formed by concatenating the inputs passed to
+ * preceding calls to @ref psa_mac_update().
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_mac_abort().
+ *
+ * @warning It is not recommended to use this function when a specific value is expected for the
+ * MAC. Call @ref psa_mac_verify_finish() instead with the expected MAC value.
+ * Comparing integrity or authenticity data such as MAC values with a function such as
+ * @c memcmp() is risky because the time taken by the comparison might leak information
+ * about the hashed data which could allow an attacker to guess a valid MAC and thereby
+ * bypass security controls.
+ *
+ * @param operation Active MAC operation.
+ * @param mac Buffer where the MAC value is to be written.
+ * @param mac_size Size of the mac buffer in bytes. This must be appropriate for the selected
+ * algorithm and key:
+ * - The exact MAC size is @ref PSA_MAC_LENGTH(@p key_type, @p key_bits,
+ * @p alg) where @c key_type and @c key_bits are attributes of the key,
+ * and @c alg is the algorithm used to compute the MAC.
+ * - @ref PSA_MAC_MAX_SIZE evaluates to the maximum MAC size of any supported
+ * MAC algorithm.
+ * @param mac_length On success, the number of bytes that make up the MAC value. This is always
+ * @ref PSA_MAC_LENGTH(@p key_type, @p key_bits, @p alg) where @c key_type and
+ * @c key_bits are attributes of the key, and @c alg is the algorithm used to
+ * compute the MAC.
+ * @return @ref PSA_SUCCESS Success. The first @c (*mac_length) bytes of mac
+ * contain the MAC value.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be an
+ * active mac sign operation.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the mac buffer is too small. @ref
+ * PSA_MAC_LENGTH() or @ref PSA_MAC_MAX_SIZE can be used
+ * to determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+
+/**
+ * @brief Set up a multi-part MAC calculation operation.
+ *
+ * @details This function sets up the calculation of the message authentication code (MAC)
+ * of a byte string. To verify the MAC of a message against an expected value,
+ * use @ref psa_mac_verify_setup() instead.
+ *
+ * The sequence of operations to calculate a MAC is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_mac_operation_t, e.g. @ref PSA_MAC_OPERATION_INIT.
+ * -# Call @ref psa_mac_sign_setup() to specify the algorithm and key.
+ * -# Call @ref psa_mac_update() zero, one or more times, passing a fragment of the
+ * message each time. The MAC that is calculated is the MAC of the concatenation of
+ * these messages in order.
+ * -# At the end of the message, call @ref psa_mac_sign_finish() to finish calculating the
+ * MAC value and retrieve it.
+ *
+ * If an error occurs at any step after a call to @ref psa_mac_sign_setup(), the operation
+ * will need to be reset by a call to @ref psa_mac_abort(). The application can call @ref
+ * psa_mac_abort() at any time after the operation has been initialized.
+ *
+ * After a successful call to @ref psa_mac_sign_setup(), the application must eventually
+ * terminate the operation through one of the following methods:
+ * - A successful call to @ref psa_mac_sign_finish().
+ * - A call to @ref psa_mac_abort().
+ *
+ * @param operation The operation object to set up. It must have been initialized as per the
+ * documentation for @ref psa_mac_operation_t and not yet in use.
+ * @param key Identifier of the key to use for the operation. It must remain valid until
+ * the operation terminates. It must allow the usage @ref
+ * PSA_KEY_USAGE_SIGN_MESSAGE.
+ * @param alg The MAC algorithm to compute: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_MAC(@p alg) is true.
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be inactive.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit
+ * the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a MAC algorithm.
+ * - @c key is not compatible with @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a MAC algorithm.
+ * - @c key is not supported for use with @c alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Add a message fragment to a multi-part MAC operation.
+ *
+ * @details The application must call @ref psa_mac_sign_setup() or @ref psa_mac_verify_setup()
+ * before calling this function.
+ *
+ * If this function returns an error status, the operation enters an error state and must
+ * be aborted by calling @ref psa_mac_abort().
+ *
+ * @param operation Active MAC operation.
+ * @param input Buffer containing the message fragment to add to the MAC calculation.
+ * @param input_length Size of the @c input buffer in bytes.
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be active.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The total input for the operation is too large for the
+ * MAC algorithm.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The total input for the operation is too large for the
+ * implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_update(psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Calculate the MAC of a message and compare it with a reference value.
+ *
+ * @param key Identifier of the key to use for the operation. It must allow the usage
+ * @ref PSA_KEY_USAGE_VERIFY_MESSAGE.
+ * @param alg The MAC algorithm to compute: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_MAC(@p alg) is true.
+ * @param input Buffer containing the input message.
+ * @param input_length Size of the @c input buffer in bytes.
+ * @param mac Buffer containing the expected MAC value.
+ * @param mac_length Size of the @c mac buffer in bytes.
+ * @return @ref PSA_SUCCESS Success. The expected MAC is identical to the
+ * actual MAC of the input.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_VERIFY_MESSAGE flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated MAC of the message does not match
+ * the value in @c mac.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a MAC algorithm.
+ * - @c key is not compatible with @c alg.
+ * - @c input_length is too large for @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a MAC algorithm.
+ * - @c key is not supported for use with @c alg.
+ * - @c input_length is too large for the
+ * implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_verify(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *mac,
+ size_t mac_length);
+
+/**
+ * @brief Finish the calculation of the MAC of a message and compare it with an expected value.
+ *
+ * @details The application must call @ref psa_mac_verify_setup() before calling this function.
+ * This function calculates the MAC of the message formed by concatenating the inputs
+ * passed to preceding calls to @ref psa_mac_update(). It then compares the calculated MAC
+ * with the expected MAC passed as a parameter to this function.
+ *
+ * When this function returns successfully, the operation becomes inactive. If this
+ * function returns an error status, the operation enters an error state and must be
+ * aborted by calling @ref psa_mac_abort().
+ *
+ * @note Implementations must make the best effort to ensure that the comparison between the
+ * actual MAC and the expected MAC is performed in constant time.
+ *
+ * @param operation Active MAC operation.
+ * @param mac Buffer containing the expected MAC value.
+ * @param mac_length Size of the @c mac buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success. The expected MAC is identical to the
+ * actual MAC of the message.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be an
+ * active mac verify operation.
+ * - The library requires initializing by a call to
+ * @ref psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE The calculated MAC of the message does not match
+ * the value in mac.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length);
+
+/**
+ * @brief Set up a multi-part MAC verification operation.
+ *
+ * @details This function sets up the verification of the message authentication code (MAC) of a
+ * byte string against an expected value.
+ *
+ * The sequence of operations to verify a MAC is as follows:
+ * -# Allocate an operation object which will be passed to all the functions listed here.
+ * -# Initialize the operation object with one of the methods described in the
+ * documentation for @ref psa_mac_operation_t, e.g. @ref PSA_MAC_OPERATION_INIT.
+ * -# Call @ref psa_mac_verify_setup() to specify the algorithm and key.
+ * -# Call @ref psa_mac_update() zero, one or more times, passing a fragment of the
+ * message each time. The MAC that is calculated is the MAC of the concatenation of
+ * these messages in order.
+ * -# At the end of the message, call @ref psa_mac_verify_finish() to finish calculating
+ * the actual MAC of the message and verify it against the expected value.
+ *
+ * If an error occurs at any step after a call to @ref psa_mac_verify_setup(), the
+ * operation will need to be reset by a call to @ref psa_mac_abort(). The application can
+ * call @ref psa_mac_abort() at any time after the operation has been initialized.
+ *
+ * After a successful call to @ref psa_mac_verify_setup(), the application must eventually
+ * terminate the operation through one of the following methods:
+ * - A successful call to @ref psa_mac_verify_finish().
+ * - A call to @ref psa_mac_abort().
+
+ * @param operation The operation object to set up. It must have been initialized as per the
+ * documentation for @ref psa_mac_operation_t and not yet in use.
+ * @param key Identifier of the key to use for the operation. It must remain valid until
+ * the operation terminates. It must allow the usage @ref
+ * PSA_KEY_USAGE_VERIFY_MESSAGE.
+ * @param alg The MAC algorithm to compute: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_MAC(@p alg) is true.
+ * @return @ref PSA_SUCCESS Success.
+ * @return @ref PSA_ERROR_BAD_STATE The following conditions can result in this error:
+ * - The operation state is not valid: it must be inactive.
+ * - The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_VERIFY_MESSAGE flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a MAC algorithm.
+ * - @c key is not compatible with @c alg.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a MAC algorithm.
+ * - @c key is not supported for use with @c alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Remove non-essential copies of key material from memory.
+ *
+ * @details For keys that have been created with the @ref PSA_KEY_USAGE_CACHE usage flag, an
+ * implementation is permitted to make additional copies of the key material that are
+ * not in storage and not for the purpose of ongoing operations.
+ *
+ * This function will remove these extra copies of the key material from memory.
+ *
+ * This function is not required to remove key material from memory in any of the
+ * following situations:
+ * - The key is currently in use in a cryptographic operation.
+ * - The key is volatile.
+
+ * @param key Identifier of the key to purge.
+ * @return @ref PSA_SUCCESS Success. The key material has been removed from memory,
+ * if the key material is not currently required.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_purge_key(psa_key_id_t key);
+
+/**
+ * @brief Perform a key agreement and return the raw shared secret.
+ *
+ * @warning The raw result of a key agreement algorithm such as finite-field Diffie-Hellman or
+ * elliptic curve Diffie-Hellman has biases, and is not suitable for use as key material.
+ * Instead it is recommended that the result is used as input to a key derivation
+ * algorithm. To chain a key agreement with a key derivation, use @ref
+ * psa_key_derivation_key_agreement() and other functions from the key derivation
+ * interface.
+ *
+ * @param alg The key agreement algorithm to compute: a value of type @ref
+ * psa_algorithm_t such that @ref PSA_ALG_IS_RAW_KEY_AGREEMENT(@c alg)
+ * is true.
+ * @param private_key Identifier of the private key to use. It must allow the usage @ref
+ * PSA_KEY_USAGE_DERIVE.
+ * @param peer_key Public key of the peer. The peer key must be in the same format that
+ * @ref psa_import_key() accepts for the public key type corresponding to
+ * the type of private_key. That is, this function performs the equivalent
+ * of @ref psa_import_key(..., @p peer_key, @p peer_key_length), with key
+ * attributes indicating the public key type corresponding to the type of
+ * @c private_key. For example, for ECC keys, this means that @c peer_key
+ * is interpreted as a point on the curve that the private key is on. The
+ * standard formats for public keys are documented in the documentation of
+ * @ref psa_export_public_key().
+ * @param peer_key_length Size of peer_key in bytes.
+ * @param output Buffer where the raw shared secret is to be written.
+ * @param output_size Size of the output buffer in bytes. This must be appropriate for the
+ * keys:
+ * - The required output size is @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE
+ * (@p type, @p bits) where type is the type of @c private_key and @c
+ * bits is the bit-size of either @c private_key or the @c peer_key.
+ * - @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE evaluates to the maximum
+ * output size of any supported raw key agreement algorithm.
+ * @param output_length On success, the number of bytes that make up the returned output.
+ *
+ * @return @ref PSA_SUCCESS Success. The first (*output_length) bytes of output
+ * contain the raw shared secret.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c private_key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED @c private_key does not have the @ref
+ * PSA_KEY_USAGE_DERIVE flag, or it does not permit
+ * the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the output buffer is too small.
+ * @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE() or @ref
+ * PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE can be used to
+ * determine a sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not a key agreement algorithm.
+ * - @c private_key is not compatible with @c alg.
+ * - @c peer_key is not a valid public key corresponding
+ * to @c private_key.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not a key agreement
+ * algorithm.
+ * - @c private_key is not supported for use with @c alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
+ psa_key_id_t private_key,
+ const uint8_t *peer_key,
+ size_t peer_key_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Sign an already-calculated hash with a private key.
+ *
+ * @details With most signature mechanisms that follow the hash-and-sign paradigm, the hash input
+ * to this function is the hash of the message to sign. The hash algorithm is encoded in
+ * the signature algorithm.
+ *
+ * Some hash-and-sign mechanisms apply a padding or encoding to the hash. In such cases,
+ * the encoded hash must be passed to this function. The current version of this
+ * specification defines one such signature algorithm: @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW.
+ *
+ * @note To perform a hash-and-sign signature algorithm, the hash must be calculated before
+ * passing it to this function. This can be done by calling @ref psa_hash_compute() or
+ * with a multi-part hash operation. The correct hash algorithm to use can be determined
+ * using @ref PSA_ALG_GET_HASH().
+ *
+ * Alternatively, to hash and sign a message in a single call, use @ref psa_sign_message().
+ *
+ * @param key Identifier of the key to use for the operation. It must be an
+ * asymmetric key pair. The key must allow the usage @ref
+ * PSA_KEY_USAGE_SIGN_HASH.
+ * @param alg An asymmetric signature algorithm that separates the hash and sign
+ * operations: a value of type @ref psa_algorithm_t such that @ref
+ * PSA_ALG_IS_SIGN_HASH(@p alg) is true.
+ * @param hash The input to sign. This is usually the hash of a message. See the
+ * detailed description of this function and the description of
+ * individual signature algorithms for a detailed description of
+ * acceptable inputs.
+ * @param hash_length Size of the hash buffer in bytes.
+ * @param signature Buffer where the signature is to be written.
+ * @param signature_size Size of the signature buffer in bytes. This must be appropriate for
+ * the selected algorithm and key:
+ * - The required signature size is @ref PSA_SIGN_OUTPUT_SIZE(@p
+ * key_type, @p key_bits, @p alg) where @c key_type and @c key_bits
+ * are the type and bit-size respectively of @c key.
+ * - @ref PSA_SIGNATURE_MAX_SIZE evaluates to the maximum signature
+ * size of any supported signature algorithm.
+ * @param signature_length On success, the number of bytes that make up the returned signature
+ * value.
+ * @return @ref PSA_SUCCESS Success. The first @c (*signature_length) bytes of
+ * @c signature contain the signature value.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref PSA_KEY_USAGE_SIGN_HASH
+ * flag, or it does not permit the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the signature buffer is too small.
+ * @ref PSA_SIGN_OUTPUT_SIZE() or @ref
+ * PSA_SIGNATURE_MAX_SIZE can be used to determine a
+ * sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not an asymmetric signature algorithm.
+ * - @c key is not an asymmetric key pair, that is
+ * compatible with @c alg.
+ * - @c hash_length is not valid for the algorithm and key
+ * type.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not an asymmetric
+ * signature algorithm.
+ * - @c key is not supported for use with alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_sign_hash(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * @brief Sign a message with a private key. For hash-and-sign algorithms, this includes the
+ * hashing step.
+ *
+ * @note To perform a multi-part hash-and-sign signature algorithm, first use a multi-part hash
+ * operation and then pass the resulting hash to @ref psa_sign_hash().
+ * @ref PSA_ALG_GET_HASH(@p alg) can be used to determine the hash algorithm to use.
+ *
+ * @param key Identifier of the key to use for the operation. It must be an
+ * asymmetric key pair. The key must allow the usage @ref
+ * PSA_KEY_USAGE_SIGN_MESSAGE.
+ * @param alg An asymmetric signature algorithm: a value of type @ref
+ * psa_algorithm_t such that @ref PSA_ALG_IS_SIGN_MESSAGE(@p alg) is
+ * true.
+ * @param input The input message to sign.
+ * @param input_length Size of the input buffer in bytes.
+ * @param signature Buffer where the signature is to be written.
+ * @param signature_size Size of the signature buffer in bytes. This must be appropriate for
+ * the selected algorithm and key:
+ * - The required signature size is @ref PSA_SIGN_OUTPUT_SIZE
+ * (@p key_type, @p key_bits, @p alg) where @c key_type and
+ * @c key_bits are the type and bit-size respectively of @c key.
+ * - @ref PSA_SIGNATURE_MAX_SIZE evaluates to the maximum signature
+ * size of any supported signature algorithm.
+ * @param signature_length On success, the number of bytes that make up the returned signature
+ * value.
+ * @return @ref PSA_SUCCESS Success. The first @c (*signature_length) bytes of
+ * @c signature contain the signature value.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit
+ * the requested algorithm.
+ * @return @ref PSA_ERROR_BUFFER_TOO_SMALL The size of the signature buffer is too small.
+ * @ref PSA_SIGN_OUTPUT_SIZE() or @ref
+ * PSA_SIGNATURE_MAX_SIZE can be used to determine a
+ * sufficient buffer size.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not an asymmetric signature algorithm.
+ * - @c key is not an asymmetric key pair, that is
+ * compatible with @c alg.
+ * - @c input_length is too large for the algorithm and
+ * key type.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not an asymmetric
+ * signature algorithm.
+ * - @c key is not supported for use with @c alg.
+ * - @c input_length is too large for the implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_ENTROPY
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_sign_message(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * @brief Verify the signature of a hash or short message using a public key.
+ *
+ * @details With most signature mechanisms that follow the hash-and-sign paradigm, the hash input
+ * to this function is the hash of the message to sign. The hash algorithm is encoded in
+ * the signature algorithm.
+ *
+ * Some hash-and-sign mechanisms apply a padding or encoding to the hash. In such cases,
+ * the encoded hash must be passed to this function. The current version of this
+ * specification defines one such signature algorithm: @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW.
+ *
+ * @note To perform a hash-and-sign verification algorithm, the hash must be calculated before
+ * passing it to this function. This can be done by calling @ref psa_hash_compute() or
+ * with a multi-part hash operation. Alternatively, to hash and verify a message signature
+ * in a single call, use @ref psa_verify_message().
+ *
+ * @note When using secure elements as backends in this implementation, the key type can only be
+ * of type @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) and must be stored on a secure element.
+ * To use the public key of a previously generated key pair, please export the public key
+ * first and then import it as a separate key with its own attributes and identifier.
+ *
+ * @param key Identifier of the key to use for the operation. It must be a public key
+ * or an asymmetric key pair. The key must allow the usage @ref
+ * PSA_KEY_USAGE_VERIFY_HASH.
+ * @param alg An asymmetric signature algorithm that separates the hash and sign
+ * operations (PSA_ALG_XXX value such that @ref PSA_ALG_IS_SIGN_HASH(@p
+ * alg) is true), that is compatible with the type of key.
+ * @param hash The input whose signature is to be verified. This is usually the hash
+ * of a message. See the detailed description of this function and the
+ * description of individual signature algorithms for a detailed
+ * description of acceptable inputs.
+ * @param hash_length Size of the hash buffer in bytes.
+ * @param signature Buffer containing the signature to verify.
+ * @param signature_length Size of the signature buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success. The signature is valid.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_VERIFY_HASH flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE @c signature is not the result of signing hash with
+ * algorithm @c alg using the private key
+ * corresponding to @c key.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not an asymmetric signature algorithm.
+ * - @c key is not a public key or an asymmetric key
+ * pair, that is compatible with @c alg.
+ * - @c hash_length is not valid for the algorithm and
+ * key type.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not an asymmetric
+ * signature algorithm.
+ * - @c key is not supported for use with @c alg.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_verify_hash(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length);
+
+/**
+ * @brief Verify the signature of a message with a public key. For hash-and-sign algorithms,
+ * this includes the hashing step.
+ *
+ * @note To perform a multi-part hash-and-sign signature verification algorithm, first use a
+ * multi-part hash operation to hash the message and then pass the resulting hash to @ref
+ * psa_verify_hash(). @ref PSA_ALG_GET_HASH(@p alg) can be used to determine the hash
+ * algorithm to use.
+ *
+ * @param key Identifier of the key to use for the operation. It must be a public
+ * key or an asymmetric key pair. The key must allow the usage @ref
+ * PSA_KEY_USAGE_VERIFY_MESSAGE.
+ * @param alg An asymmetric signature algorithm: a value of type @ref
+ * psa_algorithm_t such that @ref PSA_ALG_IS_SIGN_MESSAGE(@p alg)
+ * is true.
+ * @param input The message whose signature is to be verified.
+ * @param input_length Size of the @c input buffer in bytes.
+ * @param signature Buffer containing the signature to verify.
+ * @param signature_length Size of the @c signature buffer in bytes.
+ *
+ * @return @ref PSA_SUCCESS Success. The signature is valid.
+ * @return @ref PSA_ERROR_BAD_STATE The library requires initializing by a call to @ref
+ * psa_crypto_init().
+ * @return @ref PSA_ERROR_INVALID_HANDLE @c key is not a valid key identifier.
+ * @return @ref PSA_ERROR_NOT_PERMITTED The key does not have the @ref
+ * PSA_KEY_USAGE_VERIFY_MESSAGE flag, or it does not
+ * permit the requested algorithm.
+ * @return @ref PSA_ERROR_INVALID_SIGNATURE @c signature is not the result of signing the input
+ * message with algorithm @c alg using the private key
+ * corresponding to @c key.
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The following conditions can result in this error:
+ * - @c alg is not an asymmetric signature algorithm.
+ * - @c key is not a public key or an asymmetric key
+ * pair, that is compatible with @c alg.
+ * - @c input_length is too large for the algorithm
+ * and key type.
+ * @return @ref PSA_ERROR_NOT_SUPPORTED The following conditions can result in this error:
+ * - @c alg is not supported or is not an asymmetric
+ * signature algorithm.
+ * - @c key is not supported for use with @c alg.
+ * - @c input_length is too large for the
+ * implementation.
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_STORAGE_FAILURE
+ * @return @ref PSA_ERROR_DATA_CORRUPT
+ * @return @ref PSA_ERROR_DATA_INVALID
+ */
+psa_status_t psa_verify_message(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *signature,
+ size_t signature_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_contexts.h b/sys/include/psa_crypto/psa/crypto_contexts.h
new file mode 100644
index 0000000000..246116316a
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_contexts.h
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file crypto_contexts.h
+ * @brief Context definitions for PSA Crypto
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H
+#define PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_defines.h"
+
+#include "psa/crypto_includes.h"
+
+
+#if IS_USED(MODULE_PSA_HASH)
+/**
+ * @brief Structure containing the hash contexts needed by the application.
+ */
+typedef union {
+#if IS_USED(MODULE_PSA_HASH_MD5) || defined(DOXYGEN)
+ psa_hashes_md5_ctx_t md5; /**< MD5 context */
+#endif
+#if IS_USED(MODULE_PSA_HASH_SHA_1) || defined(DOXYGEN)
+ psa_hashes_sha1_ctx_t sha1; /**< SHA-1 context */
+#endif
+#if IS_USED(MODULE_PSA_HASH_SHA_224) || defined(DOXYGEN)
+ psa_hashes_sha224_ctx_t sha224; /**< SHA-224 context */
+#endif
+#if IS_USED(MODULE_PSA_HASH_SHA_256) || defined(DOXYGEN)
+ psa_hashes_sha256_ctx_t sha256; /**< SHA-256 context */
+#endif
+#if IS_USED(MODULE_PSA_HASH_SHA_512) || defined(DOXYGEN)
+ psa_hashes_sha512_ctx_t sha512; /**< SHA-512 context */
+#endif
+} psa_hash_context_t;
+#endif
+
+#if IS_USED(MODULE_PSA_CIPHER)
+/**
+ * @brief Structure containing the cipher contexts needed by the application.
+ */
+typedef union {
+#if IS_USED(MODULE_PSA_CIPHER_AES_128_ECB) ||\
+ IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) ||\
+ defined(DOXYGEN)
+ psa_cipher_aes_128_ctx_t aes_128; /**< AES 128 context*/
+#endif
+#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || defined(DOXYGEN)
+ psa_cipher_aes_192_ctx_t aes_192; /**< AES 192 context*/
+#endif
+#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || defined(DOXYGEN)
+ psa_cipher_aes_256_ctx_t aes_256; /**< AES 256 context*/
+#endif
+} psa_cipher_context_t;
+#endif
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+/**
+ * @brief Structure containing the secure element specific cipher contexts needed by the
+ * application.
+ */
+typedef struct {
+ psa_encrypt_or_decrypt_t direction; /**< Direction of this cipher operation */
+ /** Structure containing a driver specific cipher context */
+ union driver_context {
+ unsigned dummy; /**< Make the union non-empty even with no supported algorithms. */
+ #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
+ atca_aes_cbc_ctx_t atca_aes_cbc; /**< ATCA AES CBC context*/
+ #endif
+ } drv_ctx; /**< SE specific cipher operation context */
+} psa_se_cipher_context_t;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_includes.h b/sys/include/psa_crypto/psa/crypto_includes.h
new file mode 100644
index 0000000000..128602ea4c
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_includes.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @brief Files to include in the build of PSA Crypto
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H
+#define PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_defines.h"
+
+#if IS_USED(MODULE_CRYPTO)
+#include "crypto/psa/riot_ciphers.h"
+#endif
+
+#if IS_USED(MODULE_PSA_RIOT_HASHES_HMAC_SHA256) || IS_USED(MODULE_PSA_RIOT_HASHES_MD5) || \
+ IS_USED(MODULE_PSA_RIOT_HASHES_SHA_1) || IS_USED(MODULE_PSA_RIOT_HASHES_SHA_224) || \
+ IS_USED(MODULE_PSA_RIOT_HASHES_SHA_256)
+#include "hashes/psa/riot_hashes.h"
+#endif
+
+#if IS_USED(MODULE_PERIPH_CIPHER_AES_128_CBC)
+#include "psa_periph_aes_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_512)
+#include "psa_periph_hashes_ctx.h"
+#endif
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
+#include "atca_params.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_se_config.h b/sys/include/psa_crypto/psa/crypto_se_config.h
new file mode 100644
index 0000000000..a8df8bbceb
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_se_config.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file
+ * @brief Define structures für SE slot configurations
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H
+#define PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
+#include "atca.h"
+#endif
+
+/**
+ * @brief Structure containing device specific configuration data.
+ *
+ * This will be stored in the driver's persistent data to
+ * manage the device.
+ */
+typedef union {
+ #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
+ psa_atca_slot_config_t slots[16];
+ #endif
+} psa_se_config_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_sizes.h b/sys/include/psa_crypto/psa/crypto_sizes.h
new file mode 100644
index 0000000000..701aec16f2
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_sizes.h
@@ -0,0 +1,1004 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file crypto_sizes.h
+ * @brief Size definitions for PSA Crypto
+ *
+ * @author Lena Boeckmann
+ *
+ * @note Some of the macros in this file have already been copied here from
+ * the PSA API specification, but are not implemented, yet.
+ * They are marked by comments that either say "specification-defined"
+ * or "implementation-defined".
+ * These macros will be implemented successively in the future.
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_SIZES_H
+#define PSA_CRYPTO_PSA_CRYPTO_SIZES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_defines.h"
+#include "crypto_values.h"
+
+/**
+ * @brief Functions to convert bits to bytes
+ *
+ * @param bits
+ *
+ * @return Number of bytes contained in bits
+ */
+#define PSA_BITS_TO_BYTES(bits) (size_t)(((bits) + 7) / 8)
+
+/**
+ * @brief Functions to convert bytes to bits
+ *
+ * @param bytes
+ *
+ * @return Number of bits contained in bytes
+ */
+#define PSA_BYTES_TO_BITS(bytes) ((bytes) * 8)
+
+/**
+ * @brief Maximum key size determined by the build system.
+ *
+ * @details The maximum key size is set automatically, depending on
+ * the features chosen at compile-time. They should not be
+ * changed manually.
+ */
+#ifndef CONFIG_PSA_MAX_KEY_SIZE
+#if (IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1) || \
+ 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))
+#define CONFIG_PSA_MAX_KEY_SIZE 32
+#elif (IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || \
+ IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1))
+#define CONFIG_PSA_MAX_KEY_SIZE 24
+#elif (IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)) || \
+ (IS_USED(MODULE_PSA_CIPHER_AES_128_ECB))
+#define CONFIG_PSA_MAX_KEY_SIZE 16
+#else
+#define CONFIG_PSA_MAX_KEY_SIZE 0
+#endif
+#endif
+
+/**
+ * @brief Number of required allocated asymmetric key pair slots.
+ *
+ * @details These should be defined by the developer to
+ * fit their requirements. The default number is 5.
+ */
+#ifndef CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT
+#if (IS_USED(MODULE_PSA_ASYMMETRIC))
+#define CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT 5
+#else
+#define CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT 0
+#endif
+#endif
+
+/**
+ * @brief Number of required allocated single key slots.
+ *
+ * @details These should be defined by the developer to
+ * fit their requirements. The default number is 5.
+ */
+#ifndef CONFIG_PSA_SINGLE_KEY_COUNT
+#if (IS_USED(MODULE_PSA_KEY_SLOT_MGMT))
+#define CONFIG_PSA_SINGLE_KEY_COUNT 5
+#else
+#define CONFIG_PSA_SINGLE_KEY_COUNT 0
+#endif
+#endif
+
+/**
+ * @brief Number of required allocated protected key slots.
+ *
+ * @details These should be defined by the developer to
+ * fit their requirements. The default number is 5.
+ */
+#ifndef CONFIG_PSA_PROTECTED_KEY_COUNT
+#if (IS_USED(MODULE_PSA_SE_MGMT))
+#define CONFIG_PSA_PROTECTED_KEY_COUNT 5
+#else
+#define CONFIG_PSA_PROTECTED_KEY_COUNT 0
+#endif
+#endif
+
+/**
+ * @brief A sufficient plaintext buffer size for @ref psa_aead_decrypt(),
+ * for any of the supported key types and AEAD algorithms.
+ *
+ * @details If the size of the plaintext buffer is at least this large,
+ * it is guaranteed that @ref psa_aead_decrypt() will not fail due
+ * to an insufficient buffer size.
+ *
+ * See also @ref PSA_AEAD_DECRYPT_OUTPUT_SIZE().
+ *
+ * @param ciphertext_length Size of the ciphertext in bytes.
+ */
+#define PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE(ciphertext_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient plaintext buffer size for @ref psa_aead_decrypt(), in bytes.
+ *
+ * @details If the size of the plaintext buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_decrypt() will not fail due to an insufficient buffer size. Depending on
+ * the algorithm, the actual size of the plaintext might be smaller.
+ *
+ * See also @ref PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t
+ * such that @ref PSA_ALG_IS_AEAD(@p alg) is true.
+ * @param ciphertext_length Size of the ciphertext in bytes.
+ *
+ * @return The AEAD plaintext size for the specified key type and algorithm.
+ * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters
+ * are incompatible.
+ */
+#define PSA_AEAD_DECRYPT_OUTPUT_SIZE(key_type, alg, ciphertext_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient ciphertext buffer size for @ref psa_aead_encrypt(),
+ * for any of the supported key types and AEAD algorithms.
+ *
+ * @details If the size of the ciphertext buffer is at least this large,
+ * it is guaranteed that @ref psa_aead_encrypt() will not fail due to an insufficient
+ * buffer size.
+ *
+ * See also @ref PSA_AEAD_ENCRYPT_OUTPUT_SIZE().
+ *
+ * @param plaintext_length Size of the plaintext in bytes.
+ */
+#define PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE(plaintext_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient ciphertext buffer size for @ref psa_aead_encrypt(), in bytes.
+ *
+ * @details If the size of the ciphertext buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_encrypt() will not fail due to an insufficient buffer size. Depending on
+ * the algorithm, the actual size of the ciphertext might be smaller.
+ *
+ * See also @ref PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such
+ * that @ref PSA_ALG_IS_AEAD(alg) is true.
+ * @param plaintext_length Size of the plaintext in bytes.
+ *
+ * @return The AEAD ciphertext size for the specified key type and algorithm.
+ * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters
+ * are incompatible.
+ */
+#define PSA_AEAD_ENCRYPT_OUTPUT_SIZE(key_type, alg, plaintext_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient ciphertext buffer size for @ref psa_aead_finish(),
+ * for any of the supported key types and AEAD algorithms.
+ *
+ * @details If the size of the ciphertext buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_finish() will not fail due to an insufficient ciphertext buffer size.
+ *
+ * See also @ref PSA_AEAD_FINISH_OUTPUT_SIZE().
+ */
+#define PSA_AEAD_FINISH_OUTPUT_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient ciphertext buffer size for @ref psa_aead_finish().
+ *
+ * @details If the size of the ciphertext buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_finish() will not fail due to an insufficient ciphertext buffer size. The
+ * actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_AEAD_FINISH_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true.
+ *
+ * @return A sufficient ciphertext buffer size for the specified key type and algorithm.
+ * If the key type or AEAD algorithm is not recognized, or the parameters are incompatible,
+ * return 0. An implementation can return either 0 or a correct size for a key type and
+ * AEAD algorithm that it recognizes, but does not support.
+ */
+#define PSA_AEAD_FINISH_OUTPUT_SIZE(key_type, alg) \
+/* implementation-defined value */
+
+/**
+ * @brief The default nonce size for an AEAD algorithm, in bytes.
+ *
+ * @details If the size of the nonce buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_generate_nonce() will not fail due to an insufficient buffer size.
+ *
+ * For most AEAD algorithms, @ref PSA_AEAD_NONCE_LENGTH() evaluates to the exact size of
+ * the nonce generated by @ref psa_aead_generate_nonce().
+ *
+ * See also @ref PSA_AEAD_NONCE_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true.
+ *
+ * @return The default nonce size for the specified key type and algorithm.
+ * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters
+ * are incompatible.
+ */
+#define PSA_AEAD_NONCE_LENGTH(key_type, alg) /* implementation-defined value */
+
+/**
+ * @brief A sufficient buffer size for storing the nonce generated by
+ * @ref psa_aead_generate_nonce(), for any of the supported key types and AEAD algorithms.
+ *
+ * @details If the size of the nonce buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_generate_nonce() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_AEAD_NONCE_LENGTH().
+ */
+#define PSA_AEAD_NONCE_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief The length of a tag for an AEAD algorithm, in bytes.
+ *
+ * @details This is the size of the tag output from @ref psa_aead_finish().
+ * If the size of the tag buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_finish() will not fail due to an insufficient tag buffer size.
+ *
+ * See also @ref PSA_AEAD_TAG_MAX_SIZE.
+ *
+ * @param key_type The type of the AEAD key.
+ * @param key_bits The size of the AEAD key in bits.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true.
+ *
+ * @return The tag length for the specified algorithm and key.
+ * 0 if the AEAD algorithm does not have an identified tag that can be distinguished from
+ * the rest of the ciphertext.
+ * 0 if the AEAD algorithm is not recognized or not supported.
+ */
+#define PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient buffer size for storing the tag output by @ref psa_aead_finish(),
+ * for any of the supported key types and AEAD algorithms.
+ *
+ * @details If the size of the tag buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_finish() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_AEAD_TAG_LENGTH().
+ */
+#define PSA_AEAD_TAG_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_aead_update(), for any of the supported key
+ * types and AEAD algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_update() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_AEAD_UPDATE_OUTPUT_SIZE().
+ *
+ * @param input_length Size of the input in bytes.
+ */
+#define PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(input_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_aead_update().
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_update() will not fail due to an insufficient buffer size. The actual
+ * size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true.
+ * @param input_length Size of the input in bytes.
+ *
+ * @return A sufficient output buffer size for the specified key type and algorithm.
+ * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters
+ * are incompatible.
+ */
+#define PSA_AEAD_UPDATE_OUTPUT_SIZE(key_type, alg, input_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_aead_update(), for any of the supported key
+ * types and AEAD algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_update() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_AEAD_UPDATE_OUTPUT_SIZE().
+ *
+ * @param input_length Size of the input in bytes.
+ */
+#define PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient plaintext buffer size for @ref psa_aead_verify(), in bytes.
+ *
+ * @details If the size of the plaintext buffer is at least this large, it is guaranteed that
+ * @ref psa_aead_verify() will not fail due to an insufficient plaintext buffer size. The
+ * actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true.
+ *
+ * @return A sufficient plaintext buffer size for the specified key type and algorithm.
+ * 0 if the key type or AEAD algorithm is not recognized, not supported or the parameters
+ * are incompatible.
+ */
+#define PSA_AEAD_VERIFY_OUTPUT_SIZE(key_type, alg) \
+/* implementation-defined value */
+
+/**
+ * @brief Maximum size of a hash supported by this implementation, in bytes.
+ *
+ * See also @ref PSA_HASH_LENGTH().
+ */
+#define PSA_HASH_MAX_SIZE (64)
+
+/**
+ * @brief The input block size of a hash algorithm, in bytes.
+ *
+ * @details Hash algorithms process their input data in blocks. Hash operations will retain any
+ * partial blocks until they have enough input to fill the block or until the operation
+ * is finished.
+ *
+ * This affects the output from @ref psa_hash_suspend().
+ *
+ * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p alg) is true.
+ *
+ * @return The block size in bytes for the specified hash algorithm. If the hash algorithm is not
+ * recognized, return 0. An implementation can return either 0 or the correct size for a
+ * hash algorithm that it recognizes, but does not support.
+ */
+#define PSA_HASH_BLOCK_LENGTH(alg) /* implementation-defined value */
+
+/**
+ * @brief The size of the output of @ref psa_hash_compute() and @ref psa_hash_finish(), in bytes.
+ *
+ * @details This is also the hash length that @ref psa_hash_compare() and @ref psa_hash_verify()
+ * expect.
+ *
+ * See also @ref PSA_HASH_MAX_SIZE.
+ *
+ * @param alg A hash algorithm or an HMAC algorithm: a value of type @ref psa_algorithm_t such
+ * that (@ref PSA_ALG_IS_HASH(@p alg) || @ref PSA_ALG_IS_HMAC(@p alg)) is true.
+ *
+ * @return The hash length for the specified hash algorithm.
+ * 0 if the hash algorithm is not recognized or not supported.
+ */
+#define PSA_HASH_LENGTH(alg) \
+ ( \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD2 ? 16 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD4 ? 16 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_MD5 ? 16 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_RIPEMD160 ? 20 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_1 ? 20 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_224 ? 28 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_256 ? 32 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_384 ? 48 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512 ? 64 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512_224 ? 28 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA_512_256 ? 32 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_224 ? 28 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_256 ? 32 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_384 ? 48 : \
+ PSA_ALG_HMAC_GET_HASH(alg) == PSA_ALG_SHA3_512 ? 64 : \
+ 0)
+
+/**
+ * @brief The size of the output of @ref psa_mac_compute() and @ref psa_mac_sign_finish(),
+ * in bytes.
+ *
+ * @details If the size of the MAC buffer is at least this large, it is guaranteed that
+ * @ref psa_mac_compute() and @ref psa_mac_sign_finish() will not fail due to an
+ * insufficient buffer size.
+ *
+ * This is also the MAC length that @ref psa_mac_verify() and @ref psa_mac_verify_finish()
+ * expect.
+ *
+ * See also @ref PSA_MAC_MAX_SIZE.
+ *
+ * @param key_type The type of the MAC key.
+ * @param key_bits The size of the MAC key in bits.
+ * @param alg A MAC algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_MAC(@p alg) is true.
+ *
+ * @return The MAC length for the specified algorithm with the specified key parameters.
+ * 0 if the MAC algorithm is not recognized or not supported.
+ * Unspecified if the key parameters are not consistent with the algorithm.
+ */
+#define PSA_MAC_LENGTH(key_type, key_bits, alg) \
+ ((PSA_ALG_IS_HMAC(alg)) ? PSA_HASH_LENGTH(PSA_ALG_HMAC_GET_HASH(alg)) : \
+ PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) : \
+ ((void)(key_type), (void)(key_bits), 0))
+
+/**
+ * @brief A sufficient buffer size for storing the MAC output by @ref psa_mac_verify() and
+ * @ref psa_mac_verify_finish(), for any of the supported key types and MAC algorithms.
+ *
+ * @details If the size of the MAC buffer is at least this large, it is guaranteed that
+ * @ref psa_mac_verify() and @ref psa_mac_verify_finish() will not fail due to an
+ * insufficient buffer size.
+ *
+ * See also @ref PSA_MAC_LENGTH().
+ */
+#define PSA_MAC_MAX_SIZE (PSA_HASH_MAX_SIZE)
+
+/**
+ * @brief The block size of a block cipher.
+ *
+ * @note It is possible to build stream cipher algorithms on top of a block cipher,
+ * for example CTR mode (@ref PSA_ALG_CTR). This macro only takes the key type
+ * into account, so it cannot be used to determine the size of the data that
+ * @ref psa_cipher_update() might buffer for future processing in general.
+ *
+ * @param type A cipher key type (value of type @ref psa_key_type_t).
+ *
+ * @return The block size for a block cipher, or 1 for a stream cipher.
+ */
+#define PSA_BLOCK_CIPHER_BLOCK_LENGTH(type) \
+ (1u << (((type) >> 8) & 7))
+
+/**
+ * @brief The maximum block size of a block cipher supported by the implementation.
+ *
+ * @details See also @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ */
+#define PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_cipher_decrypt(), for any of the supported
+ * key types and cipher algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_cipher_decrypt() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_CIPHER_DECRYPT_OUTPUT_SIZE().
+ *
+ * @param input_length Size of the input in bytes.
+ */
+#define PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE(input_length) \
+ (input_length)
+
+/**
+ * @brief The maximum size of the output of @ref psa_cipher_decrypt(), in bytes.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed
+ * that @ref psa_cipher_decrypt() will not fail due to an insufficient buffer size.
+ * Depending on the algorithm, the actual size of the output might be smaller.
+ *
+ * See also @ref PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg A cipher algorithm (PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_CIPHER(@p alg) is true).
+ * @param input_length Size of the input in bytes.
+ *
+ * @return A sufficient output size for the specified key type and algorithm.
+ * 0 if the key type or cipher algorithm is not recognized, or the parameters
+ * are incompatible.
+ */
+#define PSA_CIPHER_DECRYPT_OUTPUT_SIZE(key_type, alg, input_length) \
+ (input_length - PSA_CIPHER_IV_LENGTH(key_type, alg))
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_cipher_encrypt(), for any of the supported
+ * key types and cipher algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_cipher_encrypt() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_CIPHER_ENCRYPT_OUTPUT_SIZE().
+ *
+ * @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))
+
+/**
+ * @brief The maximum size of the output of @ref psa_cipher_encrypt(), in bytes.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed
+ * that @ref psa_cipher_encrypt() will not fail due to an insufficient buffer size.
+ * Depending on the algorithm, the actual size of the output might be smaller.
+ *
+ * See also @ref PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg A cipher algorithm (PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_CIPHER(@p alg) is true).
+ * @param input_length Size of the input in bytes.
+ *
+ * @return A sufficient output size for the specified key type and algorithm.
+ * 0 if the key type or cipher algorithm is not recognized, not supported or the
+ * parameters are incompatible.
+ */
+#define PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(key_type, alg, input_length) \
+ (input_length + PSA_CIPHER_IV_LENGTH(key_type, alg))
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_cipher_finish(), for any of the supported
+ * key types and cipher algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_cipher_finish() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_CIPHER_FINISH_OUTPUT_SIZE().
+ */
+#define PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_cipher_finish().
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_cipher_finish() will not fail due to an insufficient buffer size.
+ * The actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg A cipher algorithm: a value of type psa_algorithm_t such that
+ * @ref PSA_ALG_IS_CIPHER(@p alg) is true.
+ *
+ * @return A sufficient output size for the specified key type and algorithm.
+ * 0 if the key type or cipher algorithm is not recognized, not supported or the
+ * parameters are incompatible.
+ */
+#define PSA_CIPHER_FINISH_OUTPUT_SIZE(key_type, alg) \
+/* implementation-defined value */
+
+/**
+ * @brief The default IV size for a cipher algorithm, in bytes.
+ *
+ * @details The IV that is generated as part of a call to @ref psa_cipher_encrypt() is always
+ * the default IV length for the algorithm.
+ *
+ * This macro can be used to allocate a buffer of sufficient size to
+ * store the IV output from @ref psa_cipher_generate_iv() when using
+ * a multi-part cipher operation.
+ *
+ * See also @ref PSA_CIPHER_IV_MAX_SIZE.
+ *
+ * @warning This macro may evaluate its arguments multiple times or
+ * zero times, so you should not pass arguments that contain
+ * side effects.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ *
+ * @param alg A cipher algorithm (PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_CIPHER(@p alg) is true)
+ *
+ * @return The default IV size for the specified key type and algorithm.
+ * 0, if the algorithm does not use an IV, if key type or cipher
+ * algorithm are not recognized or if the parameters are not compatible.
+ *
+ */
+#define PSA_CIPHER_IV_LENGTH(key_type, alg) \
+ (PSA_BLOCK_CIPHER_BLOCK_LENGTH(key_type) > 1 && \
+ ((alg) == PSA_ALG_CBC_NO_PADDING) ? 16 : 0)
+
+/**
+ * @brief A sufficient buffer size for storing the IV generated by @ref psa_cipher_generate_iv(),
+ * for any of the supported key types and cipher algorithms.
+ *
+ * @details If the size of the IV buffer is at least this large, it is guaranteed that
+ * @ref psa_cipher_generate_iv() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_CIPHER_IV_LENGTH().
+ */
+#define PSA_CIPHER_IV_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_cipher_update(),
+ * for any of the supported key types and cipher algorithms.
+ *
+ * @details If the size of the output buffer is at least this large,
+ * it is guaranteed that @ref psa_cipher_update() will not fail
+ * due to an insufficient buffer size.
+ *
+ * See also @ref PSA_CIPHER_UPDATE_OUTPUT_SIZE().
+ *
+ * @param input_length Size of the input in bytes.
+ */
+#define PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE(input_length) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_cipher_update().
+ *
+ * @details If the size of the output buffer is at least this large,
+ * it is guaranteed that @ref psa_cipher_update() will not fail
+ * due to an insufficient buffer size. The actual size of the
+ * output might be smaller in any given call.
+ *
+ * See also @ref PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A symmetric key type that is compatible with algorithm alg.
+ * @param alg A cipher algorithm (PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_CIPHER(alg) is true).
+ * @param input_length Size of the input in bytes.
+ *
+ * @return A sufficient output size for the specified key type and algorithm.
+ * 0 if the key type or cipher algorithm is not recognized, not supported or the parameters
+ * are incompatible.
+ */
+#define PSA_CIPHER_UPDATE_OUTPUT_SIZE(key_type, alg, input_length) \
+/* implementation-defined value */
+
+/**
+ * @brief The size of the algorithm field that is part of the output of @ref psa_hash_suspend(),
+ * in bytes.
+ *
+ * @details Applications can use this value to unpack the hash suspend state that is output by
+ * @ref psa_hash_suspend().
+ */
+#define PSA_HASH_SUSPEND_ALGORITHM_FIELD_LENGTH ((size_t)4)
+
+/**
+ * @brief The size of the hash-state field that is part of the output of @ref psa_hash_suspend(),
+ * in bytes.
+ *
+ * @details Applications can use this value to unpack the hash suspend state that is output by
+ * @ref psa_hash_suspend().
+ *
+ * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p alg) is true.
+ *
+ * @return The size, in bytes, of the hash-state field of the hash suspend state for the specified
+ * hash algorithm.
+ * 0 if the hash algorithm is not recognized or not supported.
+ */
+#define PSA_HASH_SUSPEND_HASH_STATE_FIELD_LENGTH(alg) \
+/* specification-defined value */
+
+/**
+ * @brief The size of the input-length field that is part of the output of
+ * @ref psa_hash_suspend(), in bytes.
+ *
+ * @details Applications can use this value to unpack the hash suspend state that is output
+ * by @ref psa_hash_suspend().
+ *
+ * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p alg) is true.
+ *
+ * @return The size, in bytes, of the input-length field of the hash suspend state for the
+ * specified hash algorithm.
+ * 0 i f the hash algorithm is not recognized or not supported.
+ */
+#define PSA_HASH_SUSPEND_INPUT_LENGTH_FIELD_LENGTH(alg) \
+/* specification-defined value */
+
+/**
+ * @brief A sufficient hash suspend state buffer size for @ref psa_hash_suspend(),
+ * for any supported hash algorithms.
+ *
+ * @details If the size of the hash state buffer is at least this large, it is guaranteed that
+ * @ref psa_hash_suspend() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_HASH_SUSPEND_OUTPUT_SIZE().
+ */
+#define PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief A sufficient hash suspend state buffer size for @ref psa_hash_suspend(), in bytes.
+ *
+ * @details If the size of the hash state buffer is at least this large, it is guaranteed that
+ * @ref psa_hash_suspend() will not fail due to an insufficient buffer size. The actual
+ * size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE.
+ *
+ * @param alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(alg) is true.
+ *
+ * @return A sufficient output size for the algorithm.
+ * 0 if the hash algorithm is not recognized, or is not supported by
+ * @ref psa_hash_suspend().
+ *
+ * For a supported hash algorithm alg, the following expression is true:
+ * @code
+ * PSA_HASH_SUSPEND_OUTPUT_SIZE(alg) == PSA_HASH_SUSPEND_ALGORITHM_FIELD_LENGTH +
+ * PSA_HASH_SUSPEND_INPUT_LENGTH_FIELD_LENGTH(alg) +
+ * PSA_HASH_SUSPEND_HASH_STATE_FIELD_LENGTH(alg) +
+ * PSA_HASH_BLOCK_LENGTH(alg) - 1
+ * @endcode
+ */
+#define PSA_HASH_SUSPEND_OUTPUT_SIZE(alg) /* specification-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_asymmetric_decrypt(),
+ * for any of the supported key types and asymmetric encryption algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_asymmetric_decrypt() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE().
+ */
+#define PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE \
+/* implementation-defined value */
+
+/**
+ * @brief Sufficient output buffer size for @ref psa_asymmetric_decrypt().
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_asymmetric_decrypt() will not fail due to an insufficient buffer size.
+ * The actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type An asymmetric key type, either a key pair or a public key.
+ * @param key_bits The size of the key in bits.
+ * @param alg An asymmetric encryption algorithm: a value of type psa_algorithm_t such
+ * that @ref PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(@p alg) is true.
+ *
+ * @return A sufficient output buffer size for the specified asymmetric encryption algorithm
+ * and key parameters.
+ * 0 if the asymmetric encryption algorithm and key parameters are not supported.
+ * Unspecified if the parameters are not valid.
+ */
+#define PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient output buffer size for @ref psa_asymmetric_encrypt(),
+ * for any of the supported key types and asymmetric encryption algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_asymmetric_encrypt() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE().
+ */
+#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief Sufficient output buffer size for @ref psa_asymmetric_encrypt().
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_asymmetric_encrypt() will not fail due to an insufficient buffer size.
+ * The actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type An asymmetric key type, either a key pair or a public key.
+ * @param key_bits The size of the key in bits.
+ * @param alg An asymmetric encryption algorithm: a value of type psa_algorithm_t
+ * such that @ref PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(@p alg) is true.
+ *
+ * @return A sufficient output buffer size for the specified asymmetric encryption algorithm
+ * and key parameters.
+ * 0 if the asymmetric encryption algorithm and key parameters are not supported.
+ * Unspecified if the parameters are not valid.
+ */
+#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \
+/* implementation-defined value */
+
+/**
+ * @brief Sufficient output buffer size for @ref psa_export_key().
+ *
+ * @details The following code illustrates how to allocate enough memory to export a key by
+ * querying the key type and size at runtime.
+ *
+ * @code
+ * @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT;
+ * @ref psa_status_t status;
+ * status = @ref psa_get_key_attributes(key, &attributes);
+ * if (status != @ref PSA_SUCCESS)
+ * handle_error(...);
+ * @ref psa_key_type_t key_type = @ref psa_get_key_type(&attributes);
+ * size_t key_bits = @ref psa_get_key_bits(&attributes);
+ * size_t buffer_size = @ref PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits);
+ * @ref psa_reset_key_attributes(&attributes);
+ * uint8_t *buffer = malloc(buffer_size);
+ * if (buffer == NULL)
+ * handle_error(...);
+ * size_t buffer_length;
+ * status = @ref psa_export_key(key, buffer, buffer_size, &buffer_length);
+ * if (status != @ref PSA_SUCCESS)
+ * handle_error(...);
+ * @endcode
+ *
+ * See also @ref PSA_EXPORT_KEY_PAIR_MAX_SIZE and @ref PSA_EXPORT_PUBLIC_KEY_MAX_SIZE.
+ *
+ * @param key_type A supported key type.
+ * @param key_bits The size of the key in bits.
+ *
+ * @return If the parameters are valid and supported, return a buffer size in bytes that
+ * guarantees that @ref psa_export_key() or @ref psa_export_public_key() will not fail
+ * with @ref PSA_ERROR_BUFFER_TOO_SMALL.
+ * 0 if the parameters are a valid combination that is not supported by the implementation.
+ * Unspecified if the parameters are not valid.
+ */
+#define PSA_EXPORT_KEY_OUTPUT_SIZE(key_type, key_bits) \
+ /* implementation-defined value */
+
+/**
+ * @brief Check whether the key size is a valid ECC size.
+ *
+ * @param bits Key size of type @ref psa_key_bits_t
+ */
+#define PSA_ECC_KEY_SIZE_IS_VALID(bits) \
+ (bits == 128 || \
+ bits == 192 || \
+ bits == 224 || \
+ bits == 256 || \
+ bits == 384)
+
+/**
+ * @brief The maximum size of an asymmetric private key.
+ */
+#define PSA_MAX_PRIV_KEY_SIZE (PSA_BYTES_TO_BITS(CONFIG_PSA_MAX_KEY_SIZE))
+
+/**
+ * @brief Sufficient buffer size for exporting any asymmetric key pair.
+ *
+ * @details This value must be a sufficient buffer size when calling @ref psa_export_key() to
+ * export any asymmetric key pair that is supported by the implementation, regardless of
+ * the exact key type and key size.
+ *
+ * See also @ref PSA_EXPORT_KEY_OUTPUT_SIZE().
+ */
+#define PSA_EXPORT_KEY_PAIR_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief Maximum size of the export encoding of an ECC public key.
+ *
+ * @details The representation of an ECC public key is:
+ * - The byte 0x04;
+ * - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
+ * - `y_P` as a `ceiling(m/8)`-byte string, big-endian;
+ * - where m is the bit size associated with the curve.
+ * - 1 byte + 2 * point size.
+ */
+#define PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) \
+ ((size_t)(2 * PSA_BITS_TO_BYTES(key_bits) + 1))
+
+/**
+ * @brief Sufficient output buffer size for @ref psa_export_public_key().
+ *
+ * @details This macro returns a compile-time constant if its arguments are
+ * compile-time constants.
+ *
+ * @warning This macro may evaluate its arguments multiple times or
+ * zero times, so you should not pass arguments that contain
+ * side effects.
+ *
+ * The following code illustrates how to allocate enough memory to export
+ * a public key by querying the key type and size at runtime.
+ *
+ * @code
+ * @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT;
+ * @ref psa_status_t status;
+ * status = @ref psa_get_key_attributes(key, &attributes);
+ * if (status != @ref PSA_SUCCESS) handle_error(...);
+ * @ref psa_key_type_t key_type = @ref psa_get_key_type(&attributes);
+ * size_t key_bits = @ref psa_get_key_bits(&attributes);
+ * size_t buffer_size = @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits);
+ * @ref psa_reset_key_attributes(&attributes);
+ * uint8_t *buffer = malloc(buffer_size);
+ * if (buffer == NULL) handle_error(...);
+ * size_t buffer_length;
+ * status = @ref psa_export_public_key(key, buffer, buffer_size, &buffer_length);
+ * if (status != @ref PSA_SUCCESS) handle_error(...);
+ * @endcode
+ *
+ * @param key_type A public key or key pair key type.
+ * @param key_bits The size of the key in bits.
+ *
+ * @return A buffer size in bytes that guarantees that @ref psa_export_public_key() will not fail
+ * with @ref PSA_ERROR_BUFFER_TOO_SMALL.
+ * 0 if the parameters are a valid combination that is not supported.
+ * Unspecified if the parameters are not valid, the return value is unspecified.
+ * If the parameters are valid and supported, return the same result as
+ * @ref PSA_EXPORT_KEY_OUTPUT_SIZE(
+ * @ref PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(@p key_type), @p key_bits).
+ */
+#define PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(key_type, key_bits) \
+ (PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \
+ 0)
+
+/**
+ * @brief Sufficient buffer size for exporting any asymmetric public key.
+ *
+ * @details This macro expands to a compile-time constant integer. This value is
+ * a sufficient buffer size when calling @ref psa_export_key() or
+ * @ref psa_export_public_key() to export any asymmetric public key,
+ * regardless of the exact key type and key size.
+ *
+ * See also @ref PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(@p key_type, @p key_bits).
+ */
+#define PSA_EXPORT_PUBLIC_KEY_MAX_SIZE \
+ (PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(PSA_MAX_PRIV_KEY_SIZE))
+
+/**
+ * @brief The maximum size of an asymmetric private key buffer. If only a secure element driver is
+ * present, the private key will always be stored in a key slot and PSA Crypto will only
+ * allocate memory for an 8 Byte key slot number.
+ */
+#define PSA_MAX_PRIV_KEY_BUFFER_SIZE (PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE))
+
+/**
+ * @brief The maximum size of an asymmetric private key pair.
+ */
+#define PSA_MAX_ASYMMETRIC_KEYPAIR_SIZE (PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE) + \
+ PSA_EXPORT_PUBLIC_KEY_MAX_SIZE)
+
+/**
+ * @brief The maximum size of the used key data.
+ */
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC) || IS_USED(MODULE_PSA_ASYMMETRIC)
+#define PSA_MAX_KEY_DATA_SIZE (PSA_EXPORT_PUBLIC_KEY_MAX_SIZE)
+#else
+#define PSA_MAX_KEY_DATA_SIZE (CONFIG_PSA_MAX_KEY_SIZE)
+#endif
+
+/**
+ * @brief The maximum size of an unstructured key.
+ */
+#define PSA_MAX_UNSTRUCTURED_KEY_SIZE (CONFIG_PSA_MAX_KEY_SIZE)
+
+/**
+ * @brief ECDSA signature size for a given curve bit size
+ *
+ * @note This macro returns a compile-time constant if its argument is one.
+ *
+ * @param curve_bits Curve size in bits.
+ *
+ * @return Signature size in bytes.
+ */
+#define PSA_ECDSA_SIGNATURE_SIZE(curve_bits) \
+ ((size_t)(PSA_BITS_TO_BYTES(curve_bits) * 2))
+
+/**
+ * @brief Sufficient signature buffer size for @ref psa_sign_message() and @ref psa_sign_hash().
+ *
+ * @details If the size of the signature buffer is at least this large, it is guaranteed that
+ * @ref psa_sign_message() and @ref psa_sign_hash() will not fail due to an insufficient
+ * buffer size. The actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_SIGNATURE_MAX_SIZE.
+ *
+ * @param key_type An asymmetric key type. This can be a key pair type or a public key type.
+ * @param key_bits The size of the key in bits.
+ * @param alg The signature algorithm.
+ *
+ * @return A sufficient signature buffer size for the specified asymmetric signature algorithm and
+ * key parameters.
+ * 0 if algorithm and key parameters are not supported.
+ * If the parameters are not valid, the return value is unspecified.
+ */
+#define PSA_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \
+ (PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \
+ ((void)alg, 0))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_SIZES_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_struct.h b/sys/include/psa_crypto/psa/crypto_struct.h
new file mode 100644
index 0000000000..830c9722b0
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_struct.h
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file crypto_struct.h
+ * @brief Structure definitions for PSA Crypto
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_STRUCT_H
+#define PSA_CRYPTO_PSA_CRYPTO_STRUCT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crypto_types.h"
+#include "crypto_sizes.h"
+#include "crypto_contexts.h"
+
+/**
+ * @brief Structure containing a hash context and algorithm
+ */
+struct psa_hash_operation_s {
+ psa_algorithm_t alg; /**< Operation algorithm */
+#if IS_USED(MODULE_PSA_HASH)
+ psa_hash_context_t ctx; /**< Operation hash context */
+#endif
+};
+
+/**
+ * @brief This macro returns a suitable initializer for a hash operation object of type
+ * @ref psa_hash_operation_t.
+ */
+#define PSA_HASH_OPERATION_INIT { 0 }
+
+/**
+ * @brief Return an initial value for a hash operation object.
+ *
+ * @return struct psa_hash_operation_s
+ */
+static inline struct psa_hash_operation_s psa_hash_operation_init(void)
+{
+ const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT;
+
+ return v;
+}
+
+/**
+ * @brief Structure storing the key usage policies
+ */
+struct psa_key_policy_s {
+ psa_key_usage_t usage; /**< Key usage policy */
+ psa_algorithm_t alg; /**< Algorithm for key usage */
+};
+
+/**
+ * @brief Type for key usage policies.
+ */
+typedef struct psa_key_policy_s psa_key_policy_t;
+
+/**
+ * @brief Structure storing key attributes
+ */
+struct psa_key_attributes_s {
+ psa_key_type_t type; /**< Type of key */
+ psa_key_bits_t bits; /**< Size of key in bits */
+ psa_key_lifetime_t lifetime; /**< Lifetime of key */
+ psa_key_id_t id; /**< Key identifier */
+ psa_key_policy_t policy; /**< Key usage policy */
+};
+
+/**
+ * @brief This macro returns a suitable initializer for a key attribute object of
+ * type @ref psa_key_attributes_t.
+ */
+#define PSA_KEY_ATTRIBUTES_INIT { 0 }
+
+/**
+ * @brief Return an initial value for a key attribute object.
+ *
+ * @return struct psa_key_attributes_s
+ */
+static inline struct psa_key_attributes_s psa_key_attributes_init(void)
+{
+ const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT;
+
+ return v;
+}
+
+/**
+ * @brief Structure storing an AEAD operation context
+ *
+ * @note Not implemented, yet
+ */
+struct psa_aead_operation_s {
+ int dummy; /**< Not implemented, yet */
+};
+
+/**
+ * @brief This macro returns a suitable initializer for an AEAD operation object of type
+ * @ref psa_aead_operation_t.
+ */
+#define PSA_AEAD_OPERATION_INIT { 0 }
+
+/**
+ * @brief Return an initial value for an AEAD operation object.
+ *
+ * @return psa_aead_operation_s
+ */
+static inline struct psa_aead_operation_s psa_aead_operation_init(void)
+{
+ const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT;
+
+ return v;
+}
+
+/**
+ * @brief Structure storing a cipher operation context
+ */
+struct psa_cipher_operation_s {
+ uint8_t iv_required : 1; /**< True if algorithm requires IV */
+ 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*/
+ /** Union containing cipher contexts for the executing backend */
+ union cipher_context {
+#if IS_USED(MODULE_PSA_CIPHER)
+ psa_cipher_context_t cipher_ctx; /**< Cipher context */
+#endif
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
+ psa_se_cipher_context_t se_ctx; /**< SE Cipher context */
+#endif
+ } backend_ctx; /**< Backend specific cipher context */
+};
+
+/**
+ * @brief This macro returns a suitable initializer for a cipher operation
+ * object of type @ref psa_cipher_operation_t.
+ */
+#define PSA_CIPHER_OPERATION_INIT { 0 }
+
+/**
+ * @brief Return an initial value for a cipher operation object.
+ *
+ * @return psa_cipher_operation_s
+ */
+static inline struct psa_cipher_operation_s psa_cipher_operation_init(void)
+{
+ const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT;
+
+ return v;
+}
+
+/**
+ * @brief This macro returns a suitable initializer for a key derivation operation object of
+ * type @ref psa_key_derivation_operation_t.
+ */
+#define PSA_KEY_DERIVATION_OPERATION_INIT { 0 }
+
+/**
+ * @brief Structure storing a key derivation context
+ *
+ * @note Not yet implemented
+ */
+struct psa_key_derivation_operation_s {
+ int dummy; /**< Not implemented yet */
+};
+
+/**
+ * @brief Return an initial value for a key derivation operation object.
+ *
+ * @return psa_key_derivation_operation_s
+ */
+static inline struct psa_key_derivation_operation_s psa_key_derivation_operation_init(void)
+{
+ const struct psa_key_derivation_operation_s v = PSA_KEY_DERIVATION_OPERATION_INIT;
+
+ return v;
+}
+
+/**
+ * @brief This macro returns a suitable initializer for a MAC operation object of type
+ * @ref psa_mac_operation_t.
+ */
+#define PSA_MAC_OPERATION_INIT { 0 }
+
+/**
+ * @brief Structure storing a MAC operation context
+ *
+ * @note Not yet implemented
+ */
+struct psa_mac_operation_s {
+ int dummy; /**< Not yet implemented */
+};
+
+/**
+ * @brief Return an initial value for a MAC operation object.
+ *
+ * @return psa_mac_operation_s
+ */
+static inline struct psa_mac_operation_s psa_mac_operation_init(void)
+{
+ const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT;
+
+ return v;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_STRUCT_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_types.h b/sys/include/psa_crypto/psa/crypto_types.h
new file mode 100644
index 0000000000..fa343e7a5d
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_types.h
@@ -0,0 +1,503 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file crypto_types.h
+ * @brief Type definitions for PSA Crypto
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_TYPES_H
+#define PSA_CRYPTO_PSA_CRYPTO_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+/**
+ * @brief For encrypt-decrypt functions, whether the operation is an encryption
+ * or a decryption.
+ */
+typedef enum {
+ PSA_CRYPTO_DRIVER_DECRYPT,
+ PSA_CRYPTO_DRIVER_ENCRYPT
+} psa_encrypt_or_decrypt_t;
+
+/**
+ * @brief Encoding of a cryptographic algorithm.
+ *
+ * @details For algorithms that can be applied to multiple key types, this identifier does not
+ * encode the key type. For example, for symmetric ciphers based on a block cipher,
+ * @ref psa_algorithm_t encodes the block cipher mode and the padding mode while the
+ * block cipher itself is encoded via @ref psa_key_type_t.
+ */
+typedef uint32_t psa_algorithm_t;
+
+/**
+ * @brief The type of PSA finite-field Diffie-Hellman group family identifiers.
+ *
+ * @details The group family identifier is required to create a finite-field Diffie-Hellman
+ * key using the @ref PSA_KEY_TYPE_DH_KEY_PAIR() or @ref PSA_KEY_TYPE_DH_PUBLIC_KEY()
+ * macros.
+ *
+ * The specific Diffie-Hellman group within a family is identified by the @c key_bits
+ * attribute of the key.
+ */
+typedef uint8_t psa_dh_family_t;
+
+/**
+ * @brief The type of PSA elliptic curve family identifiers.
+ *
+ * @details The curve identifier is required to create an ECC key using the
+ * @ref PSA_KEY_TYPE_ECC_KEY_PAIR() or @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY()
+ * macros.
+ *
+ * The specific ECC curve within a family is identified by the @c key_bits
+ * attribute of the key.
+ */
+typedef uint8_t psa_ecc_family_t;
+
+/**
+ * @brief The type of the state object for key derivation operations.
+ *
+ * @details Before calling any function on a key derivation operation object, the application must
+ * initialize it by any of the following means:
+ * - Set the object to all-bits-zero, for example:
+ * @code
+ * @ref psa_key_derivation_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * @endcode
+ * - Initialize the object to logical zero values by declaring the object as static or
+ * global without an explicit initializer, for example:
+ * @code
+ * static @ref psa_key_derivation_operation_t operation;
+ * @endcode
+ * - Initialize the object to the initializer @ref PSA_KEY_DERIVATION_OPERATION_INIT,
+ * for example:
+ * @code
+ * @ref psa_key_derivation_operation_t operation =
+ * @ref PSA_KEY_DERIVATION_OPERATION_INIT;
+ * @endcode
+ * - Assign the result of the function @ref psa_key_derivation_operation_init() to
+ * the object, for example:
+ * @code
+ * @ref psa_key_derivation_operation_t operation;
+ * operation = @ref psa_key_derivation_operation_init();
+ * @endcode
+ * This is an implementation-defined type. Applications that make assumptions about the
+ * content of this object will result in in implementation-specific behavior, and are
+ * non-portable.
+ */
+typedef struct psa_key_derivation_operation_s psa_key_derivation_operation_t;
+
+/**
+ * @brief Encoding of the step of a key derivation.
+ */
+typedef uint16_t psa_key_derivation_step_t;
+
+/**
+ * @brief Key identifier.
+ *
+ * @details A key identifier can be a permanent name for a persistent key, or a transient reference
+ * to volatile key.
+ */
+typedef uint32_t psa_key_id_t;
+
+/**
+ * @brief Encoding of key lifetimes.
+ *
+ * @details The lifetime of a key indicates where it is stored and which application and system
+ * actions will create and destroy it.
+ *
+ * Lifetime values have the following structure:
+ * - Bits[7:0]: Persistence level
+ * This value indicates what device management actions can cause it to be destroyed.
+ * In particular, it indicates whether the key is volatile or persistent.
+ * See @ref psa_key_persistence_t for more information.
+ * @ref PSA_KEY_LIFETIME_GET_PERSISTENCE(@p lifetime) returns the persistence level for
+ * a key lifetime value.
+ * - Bits[31:8]: Location indicator
+ * This value indicates where the key material is stored (or at least where it is
+ * accessible in cleartext) and where operations on the key are performed. See
+ * @ref psa_key_location_t for more information.
+ * @ref PSA_KEY_LIFETIME_GET_LOCATION(@p lifetime) returns the location indicator for a
+ * key lifetime value.
+ *
+ * Volatile keys are automatically destroyed when the application instance terminates or
+ * on a power reset of the device. Persistent keys are preserved until the application
+ * explicitly destroys them or until an implementation-specific device management event
+ * occurs, for example, a factor reset.
+ *
+ * Persistent keys have a key identifier of type @ref psa_key_id_t. This identifier
+ * remains valid throughout the lifetime of the key, even if the application instance
+ * that created the key terminates.
+ *
+ * This specification defines two basic lifetime values:
+ * - Keys with the lifetime @ref PSA_KEY_LIFETIME_VOLATILE are volatile. All
+ * implementations should support this lifetime.
+ * - Keys with the lifetime @ref PSA_KEY_LIFETIME_PERSISTENT are persistent. All
+ * implementations that have access to persistent storage with appropriate security
+ * guarantees should support this lifetime.
+ */
+typedef uint32_t psa_key_lifetime_t;
+
+/**
+ * @brief Encoding of key location indicators.
+ *
+ * @details If an implementation of this API can make calls to external cryptoprocessors such as
+ * secure elements, the location of a key indicates which secure element performs the
+ * operations on the key. If the key material is not stored persistently inside the secure
+ * element, it must be stored in a wrapped form such that only the secure element can
+ * access the key material in cleartext.
+ *
+ * @note Key location indicators are 24-bit values. Key management interfaces operate on
+ * lifetimes (type @ref psa_key_lifetime_t), and encode the location as the upper 24 bits
+ * of a 32-bit value.
+ *
+ * Values for location indicators defined by this specification are shown below:
+ * - @c 0: Primary local storage.
+ * All implementations should support this value. The primary local storage is
+ * typically the same storage area that contains the key metadata.
+ * - @c 1: Primary secure element.
+ * @note As of now, this value is not supported by this implementation.
+ * Use the vendor-defined location values.
+ *
+ * Implementations should support this value if there is a secure element
+ * attached to the operating environment. As a guideline, secure elements may
+ * provide higher resistance against side channel and physical attacks than the
+ * primary local storage, but may have restrictions on supported key types,
+ * sizes, policies and operations and may have different performance
+ * characteristics.
+ * - @c 2–0x7fffff: Other locations defined by a PSA specification.
+ * The PSA Cryptography API does not currently assign any meaning to
+ * these locations, but future versions of this specification or other
+ * PSA specifications may do so.
+ * - @c 0x800000–0xffffff: Vendor-defined locations. No PSA specification will assign a
+ * meaning to locations in this range.
+ */
+typedef uint32_t psa_key_location_t;
+
+/**
+ * @brief Encoding of key persistence levels.
+ *
+ * @details What distinguishes different persistence levels is which device management events can
+ * cause keys to be destroyed. For example, power reset, transfer of device ownership,
+ * or a factory reset are device management events that can affect keys at different
+ * persistence levels. The specific management events which affect persistent keys at
+ * different levels is outside the scope of the PSA Cryptography specification.
+ *
+ * @note Key persistence levels are 8-bit values. Key management interfaces operate on lifetimes
+ * (type @ref psa_key_lifetime_t), and encode the persistence value as the lower 8 bits of
+ * a 32-bit value.
+ *
+ * Values for persistence levels defined by this specification are shown below:
+ * - @c 0 = @ref PSA_KEY_PERSISTENCE_VOLATILE : Volatile key.
+ * A volatile key is automatically destroyed by the implementation when the
+ * application instance terminates. In particular, a volatile key is
+ * automatically destroyed on a power reset of the device.
+ * - @c 1 = @ref PSA_KEY_PERSISTENCE_DEFAULT : Persistent key with a default lifetime.
+ * Implementations should support this value if they support persistent keys
+ * at all. Applications should use this value if they have no specific needs
+ * that are only met by implementation-specific features.
+ * - @c 2–127: Persistent key with a PSA-specified lifetime. The PSA Cryptography
+ * specification does not define the meaning of these values, but other PSA
+ * specifications may do so.
+ * - @c 128–254: Persistent key with a vendor-specified lifetime. No PSA specification
+ * will define the meaning of these values, so implementations may choose
+ * the meaning freely. As a guideline, higher persistence levels should
+ * cause a key to survive more management events than lower levels.
+ * - @c 255 = @ref PSA_KEY_PERSISTENCE_READ_ONLY : Read-only or write-once key.
+ * A key with this persistence level cannot be destroyed. Implementations that
+ * support such keys may either allow their creation through the PSA
+ * Cryptography API, preferably only to applications with the appropriate
+ * privilege, or only expose keys created through implementation-specific
+ * means such as a factory ROM engraving process.
+ * @note Keys that are read-only due to policy restrictions rather than
+ * due to physical limitations should not have this persistence level.
+ */
+typedef uint8_t psa_key_persistence_t;
+
+/**
+ * @brief Encoding of a key type.
+ *
+ * @details This is a structured bitfield that identifies the category and type of key. The range
+ * of key type values is divided as follows:
+ * - @ref PSA_KEY_TYPE_NONE == @c 0:
+ * Reserved as an invalid key type.
+ * - @c 0x0001–0x7fff:
+ * Specification-defined key types. Key types defined by this standard always have bit
+ * 15 clear. Unallocated key type values in this range are reserved for future use.
+ * - @c 0x8000–0xffff:
+ * Implementation-defined key types. Implementations that define additional key types
+ * must use an encoding with bit 15 set.
+ */
+typedef uint16_t psa_key_type_t;
+
+/**
+ * @brief Encoding of permitted usage on a key.
+ */
+typedef uint32_t psa_key_usage_t;
+
+/**
+ * @brief Public interfaces use @c size_t, but internally we use a smaller type.
+ */
+typedef uint16_t psa_key_bits_t;
+
+/* These are all temporarily defined as some numeric type to prevent errors at compile time.*/
+/**
+ * @brief The type of the state object for multi-part AEAD operations.
+ *
+ * @details Before calling any function on an AEAD operation object, the application must
+ * initialize it by any of the following means:
+ * - Set the object to all-bits-zero, for example:
+ * @code
+ * @ref psa_aead_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * @endcode
+ * - Initialize the object to logical zero values by declaring the object as static
+ * or global without an explicit initializer, for example:
+ * @code
+ * static @ref psa_aead_operation_t operation;
+ * @endcode
+ * - Initialize the object to the initializer @ref PSA_AEAD_OPERATION_INIT, for example:
+ * @code
+ * @ref psa_aead_operation_t operation = @ref PSA_AEAD_OPERATION_INIT;
+ * @endcode
+ * - Assign the result of the function @ref psa_aead_operation_init() to the object,
+ * for example:
+ * @code
+ * @ref psa_aead_operation_t operation;
+ * operation = @ref psa_aead_operation_init();
+ * @endcode
+ *
+ * This is an implementation-defined type. Applications that make assumptions about the
+ * content of this object will result in in implementation-specific behavior, and are
+ * non-portable.
+ */
+typedef struct psa_aead_operation_s psa_aead_operation_t;
+
+/**
+ * @brief The type of the state object for multi-part MAC operations.
+ *
+ * @details Before calling any function on a MAC operation object, the application must initialize
+ * it by any of the following means:
+ * - Set the object to all-bits-zero, for example:
+ * @code
+ * @ref psa_mac_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * @endcode
+ * - Initialize the object to logical zero values by declaring the object as static or
+ * global without an explicit initializer, for example:
+ * @code
+ * static @ref psa_mac_operation_t operation;
+ * @endcode
+ * - Initialize the object to the initializer @ref PSA_MAC_OPERATION_INIT, for example:
+ * @code
+ * @ref psa_mac_operation_t operation = @ref PSA_MAC_OPERATION_INIT;
+ * @endcode
+ * - Assign the result of the function @ref psa_mac_operation_init() to the object,
+ * for example:
+ * @code
+ * @ref psa_mac_operation_t operation;
+ * operation = @ref psa_mac_operation_init();
+ * @endcode
+ * This is an implementation-defined type. Applications that make assumptions about the
+ * content of this object will result in in implementation-specific behavior, and are
+ * non-portable.
+ */
+typedef struct psa_mac_operation_s psa_mac_operation_t;
+
+/**
+ * @brief Function return status.
+ *
+ * @details This is either @ref PSA_SUCCESS, which is zero, indicating success; or a small
+ * negative value indicating that an error occurred. Errors are encoded as one of
+ * the @c PSA_ERROR_xxx values defined here.
+ */
+typedef int32_t psa_status_t;
+
+/**
+ * @brief The type of the state data structure for multipart hash operations.
+ *
+ * @details Before calling any function on a hash operation object, the application must
+ * initialize it by any of the following means:
+ * - Set the structure to all-bits-zero, for example:
+ * @code
+ * @ref psa_hash_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * @endcode
+ * - Initialize the structure to logical zero values, for example:
+ * @code
+ * @ref psa_hash_operation_t operation = {0};
+ * @endcode
+ * - Initialize the structure to the initializer @ref PSA_HASH_OPERATION_INIT,
+ * for example:
+ * @code
+ * @ref psa_hash_operation_t operation = @ref PSA_HASH_OPERATION_INIT;
+ * @endcode
+ * - Assign the result of the function @ref psa_hash_operation_init()
+ * to the structure, for example:
+ * @code
+ * @ref psa_hash_operation_t operation;
+ * operation = @ref psa_hash_operation_init();
+ * @endcode
+ *
+ * This is an implementation-defined struct. Applications should not
+ * make any assumptions about the content of this structure except
+ * as directed by the documentation of a specific implementation.
+ */
+typedef struct psa_hash_operation_s psa_hash_operation_t;
+
+/**
+ * @brief The type of an object containing key attributes.
+ *
+ * @details This is the object that represents the metadata of a key object. Metadata that can be
+ * stored in attributes includes:
+ * - The location of the key in storage, indicated by its key identifier and its lifetime.
+ * - The key’s policy, comprising usage flags and a specification of the permitted
+ * algorithm(s).
+ * - Information about the key itself: the key type and its size.
+ * - Implementations can define additional attributes.
+ *
+ * The actual key material is not considered an attribute of a key. Key attributes do not
+ * contain information that is generally considered highly confidential.
+ *
+ * @note Implementations are recommended to define the attribute object as a simple data
+ * structure, with fields corresponding to the individual key attributes. In such an
+ * implementation, each function @c psa_set_key_xxx() sets a field and the corresponding
+ * function @c psa_get_key_xxx() retrieves the value of the field.
+ * An implementation can report attribute values that are equivalent to the original one,
+ * but have a different encoding. For example, an implementation can use a more compact
+ * representation for types where many bit-patterns are invalid or not supported, and
+ * store all values that it does not support as a special marker value. In such an
+ * implementation, after setting an invalid value, the corresponding get function returns
+ * an invalid value which might not be the one that was originally stored.
+ *
+ * This is an implementation-defined type. Applications that make assumptions about the
+ * content of this object will result in in implementation-specific behavior, and are
+ * non-portable.
+ *
+ * An attribute object can contain references to auxiliary resources, for example pointers
+ * to allocated memory or indirect references to pre-calculated values. In order to free
+ * such resources, the application must call @ref psa_reset_key_attributes(). As an
+ * exception, calling @ref psa_reset_key_attributes() on an attribute object is optional
+ * if the object has only been modified by the following functions since it was
+ * initialized or last reset with @ref psa_reset_key_attributes():
+ * - @ref psa_set_key_id()
+ * - @ref psa_set_key_lifetime()
+ * - @ref psa_set_key_type()
+ * - @ref psa_set_key_bits()
+ * - @ref psa_set_key_usage_flags()
+ * - @ref psa_set_key_algorithm()
+ * Before calling any function on a key attribute object, the application must initialize
+ * it by any of the following means:
+ * - Set the object to all-bits-zero, for example:
+ * @code
+ * @ref psa_key_attributes_t attributes;
+ * memset(&attributes, 0, sizeof(attributes));
+ * @endcode
+ * - Initialize the object to logical zero values by declaring the object as static or
+ * global without an explicit initializer, for example:
+ * @code
+ * static @ref psa_key_attributes_t attributes;
+ * @endcode
+ * - Initialize the object to the initializer @ref PSA_KEY_ATTRIBUTES_INIT, for example:
+ * @code
+ * @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT;
+ * @endcode
+ * - Assign the result of the function @ref psa_key_attributes_init() to the object,
+ * for example:
+ * @code
+ * @ref psa_key_attributes_t attributes;
+ * attributes = @ref psa_key_attributes_init();
+ * @endcode
+ *
+ * A freshly initialized attribute object contains the following values:
+ * - lifetime: @ref PSA_KEY_LIFETIME_VOLATILE.
+ * - key identifier: @ref PSA_KEY_ID_NULL — which is not a valid key identifier.
+ * - type: @ref PSA_KEY_TYPE_NONE — meaning that the type is unspecified.
+ * - key size: @c 0 — meaning that the size is unspecified.
+ * - usage flags: @c 0 — which allows no usage except exporting a public key.
+ * - algorithm: @ref PSA_ALG_NONE — which does not allow cryptographic usage,
+ * but allows exporting.
+ *
+ * ## Usage
+ * A typical sequence to create a key is as follows:
+ * -# Create and initialize an attribute object.
+ * -# If the key is persistent, call @ref psa_set_key_id(). Also call @ref
+ * psa_set_key_lifetime() to place the key in a non-default location.
+ * -# Set the key policy with @ref psa_set_key_usage_flags() and @ref
+ * psa_set_key_algorithm().
+ * -# Set the key type with @ref psa_set_key_type(). Skip this step if copying an existing
+ * key with @ref psa_copy_key().
+ * -# When generating a random key with @ref psa_generate_key() or deriving a key with
+ * @ref psa_key_derivation_output_key(), set the desired key size with @ref
+ * psa_set_key_bits().
+ * -# Call a key creation function: @ref psa_import_key(), @ref psa_generate_key(),
+ * @ref psa_key_derivation_output_key() or @ref psa_copy_key(). This function reads the
+ * attribute object, creates a key with these attributes, and outputs an identifier for
+ * the newly created key.
+ * -# Optionally call @ref psa_reset_key_attributes(), now that the attribute object is no
+ * longer needed. Currently this call is not required as the attributes defined in this
+ * specification do not require additional resources beyond the object itself.
+ *
+ * A typical sequence to query a key’s attributes is as follows:
+ * -# Call @ref psa_get_key_attributes().
+ * -# Call @c psa_get_key_xxx() functions to retrieve the required attribute(s).
+ * -# Call @ref psa_reset_key_attributes() to free any resources that can be used by the
+ * attribute object.
+ *
+ * Once a key has been created, it is impossible to change its attributes.
+ */
+typedef struct psa_key_attributes_s psa_key_attributes_t;
+
+/**
+ * @brief The type of the state object for multi-part cipher operations.
+ *
+ * @details Before calling any function on a cipher operation object, the application must
+ * initialize it by any of the following means:
+ * - Set the object to all-bits-zero, for example:
+ * @code
+ * @ref psa_cipher_operation_t operation;
+ * memset(&operation, 0, sizeof(operation));
+ * @endcode
+ * - Initialize the object to logical zero values by declaring the object as static or
+ * global without an explicit initializer, for example:
+ * @code
+ * static @ref psa_cipher_operation_t operation;
+ * @endcode
+ * - Initialize the object to the initializer @ref PSA_CIPHER_OPERATION_INIT, for example:
+ * @code
+ * @ref psa_cipher_operation_t operation = @ref PSA_CIPHER_OPERATION_INIT;
+ * @endcode
+ * - Assign the result of the function @ref psa_cipher_operation_init() to the object,
+ * for example:
+ * @code
+ * @ref psa_cipher_operation_t operation;
+ * operation = @ref psa_cipher_operation_init();
+ * @endcode
+ *
+ * This is an implementation-defined type. Applications that make assumptions about the
+ * content of this object will result in in implementation-specific behavior, and are
+ * non-portable.
+ */
+typedef struct psa_cipher_operation_s psa_cipher_operation_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_TYPES_H */
+/** @} */
diff --git a/sys/include/psa_crypto/psa/crypto_values.h b/sys/include/psa_crypto/psa/crypto_values.h
new file mode 100644
index 0000000000..8a35b8a9d7
--- /dev/null
+++ b/sys/include/psa_crypto/psa/crypto_values.h
@@ -0,0 +1,3486 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file crypto_values.h
+ * @brief Value definitions for PSA Crypto.
+ *
+ * @author Lena Boeckmann
+ *
+ * @note Some of the macros in this file have already been copied here from
+ * the PSA API specification, but are not implemented, yet.
+ * They are marked by comments that either say "specification-defined"
+ * or "implementation-defined".
+ * These macros will be implemented successively in the future.
+ */
+
+#ifndef PSA_CRYPTO_PSA_CRYPTO_VALUES_H
+#define PSA_CRYPTO_PSA_CRYPTO_VALUES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crypto_types.h"
+
+/**
+ * @brief PSA algorithm category mask
+ */
+#define PSA_ALG_CATEGORY_MASK ((psa_algorithm_t)0x7f000000)
+
+/**
+ * @brief Category for hash algorithms
+ */
+#define PSA_ALG_CATEGORY_HASH ((psa_algorithm_t)0x02000000)
+/**
+ * @brief Category for MAC algorithms
+ */
+#define PSA_ALG_CATEGORY_MAC ((psa_algorithm_t)0x03000000)
+/**
+ * @brief Category for cipher algorithms
+ */
+#define PSA_ALG_CATEGORY_CIPHER ((psa_algorithm_t)0x04000000)
+/**
+ * @brief Category for AEAD algorithms
+ */
+#define PSA_ALG_CATEGORY_AEAD ((psa_algorithm_t)0x05000000)
+/**
+ * @brief Category for signature algorithms
+ */
+#define PSA_ALG_CATEGORY_SIGN ((psa_algorithm_t)0x06000000)
+/**
+ * @brief Category for asymmetric encryption algorithms
+ */
+#define PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION ((psa_algorithm_t)0x07000000)
+/**
+ * @brief Category for key derivation algorithms
+ */
+#define PSA_ALG_CATEGORY_KEY_DERIVATION ((psa_algorithm_t)0x08000000)
+/**
+ * @brief Category for key agreement algorithms
+ */
+#define PSA_ALG_CATEGORY_KEY_AGREEMENT ((psa_algorithm_t)0x09000000)
+
+/**
+ * @brief Macro to build an AEAD minimum-tag-length wildcard algorithm.
+ *
+ * @details A key with a minimum-tag-length AEAD wildcard algorithm as permitted algorithm policy
+ * can be used with all AEAD algorithms sharing the same base algorithm, and where the tag
+ * length of the specific algorithm is equal to or larger then the minimum tag length
+ * specified by the wildcard algorithm.
+ *
+ * @note When setting the minimum required tag length to less than the smallest tag length
+ * allowed by the base algorithm, this effectively becomes an ‘any-tag-length-allowed’
+ * policy for that base algorithm.
+ *
+ * The AEAD algorithm with a default length tag can be recovered using
+ * @ref PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG().
+ *
+ * @param aead_alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p aead_alg) is true.
+ * @param min_tag_length Desired minimum length of the authentication tag in bytes. This must be
+ * at least 1 and at most the largest allowed tag length of the algorithm.
+ *
+ * @return The corresponding AEAD wildcard algorithm with the specified minimum tag length
+ * Unspecified if @c aead_alg is not a supported AEAD algorithm or if @c min_tag_length is
+ * less than 1 or too large for the specified AEAD algorithm.
+ */
+#define PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(aead_alg, min_tag_length) \
+ /* specification-defined value */
+
+/**
+ * @brief An AEAD algorithm with the default tag length.
+ *
+ * @details This macro can be used to construct the AEAD algorithm with default tag length from an
+ * AEAD algorithm with a shortened tag. See also @ref PSA_ALG_AEAD_WITH_SHORTENED_TAG().
+ *
+ * @b Compatible @b key @b types:
+ * The resulting AEAD algorithm is compatible with the same key types as the
+ * AEAD algorithm used to construct it.
+ */
+#define PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(aead_alg) \
+ ((((aead_alg) & ~0x003f0000) == 0x05400100) ? PSA_ALG_CCM : \
+ (((aead_alg) & ~0x003f0000) == 0x05400200) ? PSA_ALG_GCM : \
+ (((aead_alg) & ~0x003f0000) == 0x05000500) ? PSA_ALG_CHACHA20_POLY1305 : \
+ PSA_ALG_NONE)
+
+/**
+ * @brief Macro to build a AEAD algorithm with a shortened tag.
+ *
+ * @details An AEAD algorithm with a shortened tag is similar to the corresponding AEAD algorithm,
+ * but has an authentication tag that consists of fewer bytes. Depending on the algorithm,
+ * the tag length might affect the calculation of the ciphertext.
+ *
+ * The AEAD algorithm with a default length tag can be recovered using
+ * @ref PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG().
+ *
+ * @b Compatible @b key @b types:
+ * The resulting AEAD algorithm is compatible with the same key types as the AEAD
+ * algorithm used to construct it.
+ *
+ * @param aead_alg An AEAD algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_AEAD(@p aead_alg) is true.
+ * @param tag_length Desired length of the authentication tag in bytes.
+ *
+ * @return The corresponding AEAD algorithm with the specified tag length.
+ * Unspecified if @c aead_alg is not a supported AEAD algorithm or if @c tag_length is not
+ * valid for the specified AEAD algorithm.
+ */
+#define PSA_ALG_AEAD_WITH_SHORTENED_TAG(aead_alg, tag_length) \
+ ((psa_algorithm_t)(((aead_alg) & ~0x003f0000) | (((tag_length) & 0x3f) << 16)))
+
+/**
+ * @brief When setting a hash-and-sign algorithm in a key policy, permit any hash algorithm.
+ *
+ * @details This value can be used to form the permitted algorithm attribute of a key policy for a
+ * signature algorithm that is parametrized by a hash. A key with this policy can then be
+ * used to perform operations using the same signature algorithm parametrized with any
+ * supported hash. A signature algorithm created using this macro is a wildcard algorithm,
+ * and @ref PSA_ALG_IS_WILDCARD() will return true.
+ *
+ * This value must not be used to build other algorithms that are parametrized over a
+ * hash. For any valid use of this macro to build an algorithm alg,
+ * @ref PSA_ALG_IS_HASH_AND_SIGN(alg) is true. This value must not be used to build an
+ * algorithm specification to perform an operation. It is only valid for setting the
+ * permitted algorithm in a key policy.
+ *
+ * @b Usage:
+ * For example, suppose that @c PSA_xxx_SIGNATURE is one of the following macros:
+ * - @ref PSA_ALG_RSA_PKCS1V15_SIGN
+ * - @ref PSA_ALG_RSA_PSS
+ * - @ref PSA_ALG_RSA_PSS_ANY_SALT
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ *
+ * The following sequence of operations shows how @ref PSA_ALG_ANY_HASH can be used in a
+ * key policy:
+ * -# Set the key usage flags using @ref PSA_ALG_ANY_HASH, for example:
+ * @code
+ * @ref psa_set_key_usage_flags(@p &attributes, @ref PSA_KEY_USAGE_SIGN_MESSAGE);
+ * // or VERIFY_MESSAGE
+ * @ref psa_set_key_algorithm(@p &attributes,
+ * PSA_xxx_SIGNATURE(@ref PSA_ALG_ANY_HASH));
+ * @endcode
+ * -# Import or generate key material.
+ * -# Call @ref psa_sign_message() or @ref psa_verify_message(), passing an algorithm
+ * built from PSA_xxx_SIGNATURE and a specific hash. Each call to sign or verify a
+ * message can use a different hash algorithm.
+ * @code
+ * @ref psa_sign_message(@p key, PSA_xxx_SIGNATURE(@ref PSA_ALG_SHA_256), ...);
+ * @ref psa_sign_message(@p key, PSA_xxx_SIGNATURE(@ref PSA_ALG_SHA_512), ...);
+ * @ref psa_sign_message(@p key, PSA_xxx_SIGNATURE(@ref PSA_ALG_SHA3_256), ...);
+ * @endcode
+ */
+#define PSA_ALG_ANY_HASH ((psa_algorithm_t)0x020000ff)
+
+/**
+ * @brief Macro to build a MAC minimum-MAC-length wildcard algorithm.
+ *
+ * @details A key with a minimum-MAC-length MAC wildcard algorithm as permitted algorithm policy
+ * can be used with all MAC algorithms sharing the same base algorithm, and where the
+ * (potentially truncated) MAC length of the specific algorithm is equal to or larger then
+ * the wildcard algorithm’s minimum MAC length.
+ *
+ * @note When setting the minimum required MAC length to less than the smallest MAC length
+ * allowed by the base algorithm, this effectively becomes an ‘any-MAC-length-allowed’
+ * policy for that base algorithm.
+ *
+ * The untruncated MAC algorithm can be recovered using @ref PSA_ALG_FULL_LENGTH_MAC().
+ *
+ * @b Compatible @b key @b types
+ * The resulting wildcard MAC algorithm is compatible with the same key types as the MAC
+ * algorithm used to construct it.
+ *
+ * @param mac_alg A MAC algorithm: a value of type psa_algorithm_t such that
+ * @ref PSA_ALG_IS_MAC(alg) is true.
+ * This can be a truncated or untruncated MAC algorithm.
+ * @param min_mac_length Desired minimum length of the message authentication code in bytes.
+ * This must be at most the untruncated length of the MAC and must be at
+ * least 1.
+ * @return The corresponding MAC wildcard algorithm with the specified minimum MAC length.
+ * Unspecified if mac_alg is not a supported MAC algorithm or if min_mac_length is less
+ * than 1 or too large for the specified MAC algorithm.
+ */
+#define PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(mac_alg, min_mac_length) \
+ /* specification-defined value */
+
+/**
+ * @brief Deterministic ECDSA signature scheme, with hashing.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This is the deterministic ECDSA signature scheme defined by Deterministic Usage of the
+ * Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm
+ * (ECDSA) [RFC6979].
+ *
+ * The representation of a signature is the same as with @ref PSA_ALG_ECDSA().
+ *
+ * @note When based on the same hash algorithm, the verification operations for
+ * @ref PSA_ALG_ECDSA and @ref PSA_ALG_DETERMINISTIC_ECDSA are identical. A signature
+ * created using @ref PSA_ALG_ECDSA can be verified with the same key using either
+ * @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA. Similarly, a signature created
+ * using @ref PSA_ALG_DETERMINISTIC_ECDSA can be verified with the same key using
+ * either @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA.
+ *
+ * In particular, it is impossible to determine whether a signature was produced with
+ * deterministic ECDSA or with randomized ECDSA: it is only possible to verify that a
+ * signature was made with ECDSA with the private key corresponding to the public key used
+ * for the verification.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@p family)
+ * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@p family) (signature verification only)
+ *
+ * where family is a Weierstrass Elliptic curve family.
+ * That is, one of the following values:
+ * - PSA_ECC_FAMILY_SECT_XX
+ * - PSA_ECC_FAMILY_SECP_XX
+ * - @ref PSA_ECC_FAMILY_FRP
+ * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. This includes
+ * @ref PSA_ALG_ANY_HASH when specifying the algorithm in a key policy.
+ *
+ * @return The corresponding deterministic ECDSA signature algorithm.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_DETERMINISTIC_ECDSA(hash_alg) \
+ ((psa_algorithm_t)(0x06000700 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief Macro to construct the MAC algorithm with a full length MAC, from a truncated MAC
+ * algorithm.
+ *
+ * @details @b Compatible @b key @b types
+ * The resulting untruncated MAC algorithm is compatible with the same key types as the MAC
+ * algorithm used to construct it.
+ *
+ * @param mac_alg A MAC algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_MAC(@p mac_alg) is true.
+ * This can be a truncated or untruncated MAC algorithm.
+ *
+ * @return The corresponding MAC algorithm with a full length MAC.
+ * Unspecified if @c mac_alg is not a supported MAC algorithm. *
+ */
+#define PSA_ALG_FULL_LENGTH_MAC(mac_alg) \
+ ((psa_algorithm_t)((mac_alg) & ~0x003f0000))
+
+/**
+ * @brief Macro to build an HKDF algorithm.
+ *
+ * @details This is the HMAC-based Extract-and-Expand Key Derivation Function (HKDF) specified by
+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) [RFC5869].
+ *
+ * This key derivation algorithm uses the following inputs:
+ * - @ref PSA_KEY_DERIVATION_INPUT_SALT is the salt used in the “extract” step. It is
+ * optional; if omitted, the derivation uses an empty salt.
+ * - @ref PSA_KEY_DERIVATION_INPUT_INFO is the info string used in the “expand” step.
+ * - @ref PSA_KEY_DERIVATION_INPUT_SECRET is the secret key used in the “extract” step.
+ *
+ * If @ref PSA_KEY_DERIVATION_INPUT_SALT is provided, it must be before
+ * @ref PSA_KEY_DERIVATION_INPUT_SECRET. @ref PSA_KEY_DERIVATION_INPUT_INFO can be
+ * provided at any time after setup and before starting to generate output.
+ *
+ * Each input may only be passed once.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_DERIVE (for the secret key)
+ * - @ref PSA_KEY_TYPE_RAW_DATA (for the other inputs)
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true.
+ *
+ * @return The corresponding HKDF algorithm. For example, @ref PSA_ALG_HKDF(@ref PSA_ALG_SHA_256)
+ * is HKDF using HMAC-SHA-256.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_HKDF(hash_alg) \
+ ((psa_algorithm_t)(0x08000100 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief Get the hash used by a composite algorithm.
+ *
+ * The following composite algorithms require a hash algorithm:
+ * - @ref PSA_ALG_ECDSA()
+ * - @ref PSA_ALG_HKDF()
+ * - @ref PSA_ALG_HMAC()
+ * - @ref PSA_ALG_RSA_OAEP()
+ * - @ref PSA_ALG_IS_RSA_PKCS1V15_SIGN()
+ * - @ref PSA_ALG_RSA_PSS()
+ * - @ref PSA_ALG_RSA_PSS_ANY_SALT()
+ * - @ref PSA_ALG_TLS12_PRF()
+ * - @ref PSA_ALG_TLS12_PSK_TO_MS()
+ * - @ref PSA_ALG_PBKDF2_HMAC()
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return The underlying hash algorithm if alg is a composite algorithm that uses a hash algorithm
+ * @ref PSA_ALG_NONE if alg is not a composite algorithm that uses a hash.
+ */
+#define PSA_ALG_GET_HASH(alg) \
+ (((alg) & PSA_ALG_HASH_MASK) == \
+ 0 ? ((psa_algorithm_t)0) : PSA_ALG_CATEGORY_HASH | ((alg) & PSA_ALG_HASH_MASK))
+
+/**
+ * @brief HMAC Base
+ */
+#define PSA_ALG_HMAC_BASE (0x03800000)
+
+/**
+ * @brief Macro to build an HMAC message-authentication-code algorithm from an underlying hash
+ * algorithm.
+ *
+ * @details For example, @ref PSA_ALG_HMAC(@ref PSA_ALG_SHA_256) is HMAC-SHA-256.
+ * The HMAC construction is defined in HMAC: Keyed-Hashing for Message Authentication
+ * [RFC2104].
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_HMAC
+ *
+ * @param hash_alg A hash algorithm (PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true).
+ *
+ * @return The corresponding HMAC algorithm.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_HMAC(hash_alg) \
+ ((psa_algorithm_t)(PSA_ALG_HMAC_BASE | ((hash_alg) & PSA_ALG_HASH_MASK)))
+
+/**
+ * @brief Whether the specified algorithm is a symmetric cipher algorithm.
+ *
+ * @param alg An algorithm identifier (value of type @ref psa_algorithm_t).
+ *
+ * @return 1 if alg is a symmetric cipher algorithm,
+ * 0 if algorithm is not recognized or not supported
+ */
+#define PSA_ALG_IS_CIPHER(alg) \
+ (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_CIPHER)
+
+/**
+ * @brief Whether the specified algorithm is an authenticated encryption with
+ * associated data (AEAD) algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an AEAD algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_AEAD(alg) \
+ (((alg) & PSA_ALG_CATEGORY_MASK) == 0x05000000)
+
+/**
+ * @brief Whether the specified algorithm is an AEAD mode on a block cipher.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an AEAD algorithm which is an AEAD mode based on a block cipher
+ * 0 otherwise.
+ */
+#define PSA_ALG_IS_AEAD_ON_BLOCK_CIPHER(alg) \
+ (((alg) & 0x7f400000) == 0x05400000)
+
+/**
+ * @brief Whether the specified algorithm is an asymmetric encryption algorithm, also known as
+ * public-key encryption algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an asymmetric encryption algorithm,
+ * 0 otherwise.
+ */
+#define PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg) \
+ (((alg) & PSA_ALG_CATEGORY_MASK) == 0x07000000)
+
+/**
+ * @brief Whether the specified algorithm is a MAC algorithm based on a block cipher.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a MAC algorithm based on a block cipher
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) \
+ (((alg) & 0x7fc00000) == 0x03c00000)
+
+/**
+ * @brief Whether the specified algorithm is deterministic ECDSA.
+ *
+ * See also @ref PSA_ALG_IS_ECDSA() and @ref PSA_ALG_IS_RANDOMIZED_ECDSA().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a deterministic ECDSA algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_DETERMINISTIC_ECDSA(alg) \
+ (((alg) & ~0x000000ff) == 0x06000700)
+
+/**
+ * @brief Whether the specified algorithm is an elliptic curve Diffie-Hellman algorithm.
+ *
+ * @details This includes the raw elliptic curve Diffie-Hellman algorithm as well as elliptic curve
+ * Diffie-Hellman followed by any supporter key derivation algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an elliptic curve Diffie-Hellman algorithm
+ * 0 otherwise.
+ */
+#define PSA_ALG_IS_ECDH(alg) \
+ (((alg) & 0x7fff0000) == 0x09020000)
+
+/**
+ * @brief Whether the specified algorithm is a finite field Diffie-Hellman algorithm.
+ *
+ * @details This includes the raw finite field Diffie-Hellman algorithm as well as finite-field
+ * Diffie-Hellman followed by any supported key derivation algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a finite field Diffie-Hellman algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_FFDH(alg) \
+ (((alg) & 0x7fff0000) == 0x09010000)
+
+/**
+ * @brief Whether the specified algorithm is ECDSA.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an ECDSA algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_ECDSA(alg) \
+ (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_SIGN)
+
+/**
+ * @brief Whether the specified algorithm is a hash algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a hash algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_HASH(alg) \
+ (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH)
+
+/**
+ * @brief Get the hash operation of a hmac algorithm
+ *
+ * @param hmac_alg HMAC algorithm
+ */
+#define PSA_ALG_HMAC_GET_HASH(hmac_alg) \
+ (PSA_ALG_CATEGORY_HASH | ((hmac_alg) & PSA_ALG_HASH_MASK))
+
+/**
+ * @brief Whether the specified algorithm is HashEdDSA.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a HashEdDSA algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_HASH_EDDSA(alg) \
+ (((alg) & ~0x000000ff) == 0x06000900)
+
+/**
+ * @brief Whether the specified algorithm is a hash-and-sign algorithm that signs exactly the hash
+ * value.
+ *
+ * @details This macro identifies algorithms that can be used with @ref psa_sign_hash() that use
+ * the exact message hash value as an input the signature operation.
+ * For example, if @ref PSA_ALG_IS_HASH_AND_SIGN(@p alg) is true, the following call
+ * sequence is equivalent to
+ * @ref psa_sign_message(@p key, @p alg, @p msg, @p msg_len, ...):
+ *
+ * @code
+ * @ref psa_hash_operation_t op = {0};
+ * uint8_t hash[@ref PSA_HASH_MAX_SIZE];
+ * size_t hash_len;
+ * @ref psa_hash_setup(&op, @ref PSA_ALG_GET_HASH(alg));
+ * @ref psa_hash_update(&op, msg, msg_len);
+ * @ref psa_hash_finish(&op, hash, sizeof(hash), &hash_len);
+ * @ref psa_sign_hash(key, alg, hash, hash_len, ...);
+ * @endcode
+ *
+ * This excludes hash-and-sign algorithms that require a encoded or modified hash for the
+ * signature step in the algorithm, such as @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW. For such
+ * algorithms, @ref PSA_ALG_IS_SIGN_HASH() is true but @ref PSA_ALG_IS_HASH_AND_SIGN() is
+ * false.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a hash-and-sign algorithm that signs exactly the hash value
+ * 0 otherwise
+ * A wildcard signature algorithm policy, using @ref PSA_ALG_ANY_HASH, returns the same
+ * value as the signature algorithm parameterised with a valid hash algorithm.
+ */
+#define PSA_ALG_IS_HASH_AND_SIGN(alg) \
+ (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || \
+ PSA_ALG_IS_ECDSA(alg) || PSA_ALG_IS_HASH_EDDSA(alg))
+
+/**
+ * @brief Whether the specified algorithm is an HKDF algorithm.
+ *
+ * @details HKDF is a family of key derivation algorithms that are based on a hash function and the
+ * HMAC construction.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an HKDF algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_HKDF(alg) \
+ (((alg) & ~0x000000ff) == 0x08000100)
+
+/**
+ * @brief Whether the specified algorithm is an HMAC algorithm.
+ *
+ * @details HMAC is a family of MAC algorithms that are based on a hash function.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an HMAC algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_HMAC(alg) \
+ (((alg) & 0x7fc0ff00) == 0x03800000)
+
+/**
+ * @brief Whether the specified algorithm is a key agreement algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a key agreement algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_KEY_AGREEMENT(alg) \
+ (((alg) & 0x7f000000) == 0x09000000)
+
+/**
+ * @brief Whether the specified algorithm is a key derivation algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a key derivation algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_KEY_DERIVATION(alg) \
+ (((alg) & 0x7f000000) == 0x08000000)
+
+/**
+ * @brief Whether the specified algorithm is a key-stretching or password-hashing algorithm.
+ *
+ * @details A key-stretching or password-hashing algorithm is a key derivation algorithm that is
+ * suitable for use with a low-entropy secret such as a password. Equivalently, it’s a key
+ * derivation algorithm that uses a @ref PSA_KEY_DERIVATION_INPUT_PASSWORD input step.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a key-stretching or password-hashing algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_KEY_DERIVATION_STRETCHING(alg) \
+ (((alg) & 0x7f800000) == 0x08800000)
+
+/**
+ * @brief Whether the specified algorithm is a MAC algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a MAC algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_MAC(alg) \
+ (((alg) & 0x7f000000) == 0x03000000)
+
+/**
+ * @brief Whether the specified algorithm is a PBKDF2-HMAC algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a PBKDF2-HMAC algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_PBKDF2_HMAC(alg) \
+ (((alg) & ~0x000000ff) == 0x08800100)
+
+/**
+ * @brief Whether the specified algorithm is randomized ECDSA.
+ *
+ * @details See also @ref PSA_ALG_IS_ECDSA() and @ref PSA_ALG_IS_DETERMINISTIC_ECDSA().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is arandomized ECDSA algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RANDOMIZED_ECDSA(alg) \
+ (((alg) & ~0x000000ff) == 0x06000600)
+
+/**
+ * @brief Whether the specified algorithm is a raw key agreement algorithm.
+ *
+ * @details A raw key agreement algorithm is one that does not specify a key derivation function.
+ * Usually, raw key agreement algorithms are constructed directly with a
+ * PSA_ALG_xxx macro while non-raw key agreement algorithms are constructed with
+ * @ref PSA_ALG_KEY_AGREEMENT().
+ *
+ * The raw key agreement algorithm can be extracted from a full key agreement algorithm
+ * identifier using @ref PSA_ALG_KEY_AGREEMENT_GET_BASE().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a raw key agreement algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RAW_KEY_AGREEMENT(alg) \
+ (((alg) & 0x7f00ffff) == 0x09000000)
+
+/**
+ * @brief Whether the specified algorithm is an RSA OAEP encryption algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a RSA OAEP algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RSA_OAEP(alg) \
+ (((alg) & ~0x000000ff) == 0x07000300)
+
+/**
+ * @brief Whether the specified algorithm is an RSA PKCS#1 v1.5 signature algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a RSA PKCS#1 v1.5 signature algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) \
+ (((alg) & ~0x000000ff) == 0x06000200)
+
+/**
+ * @brief Whether the specified algorithm is a RSA PSS signature algorithm.
+ *
+ * @details This macro returns 1 for algorithms constructed using either @ref PSA_ALG_RSA_PSS() or
+ * @ref PSA_ALG_RSA_PSS_ANY_SALT().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a RSA PSS signature algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RSA_PSS(alg) \
+ (((alg) & ~0x000000ff) == 0x06000300)
+
+/**
+ * @brief Whether the specified algorithm is an RSA PSS signature algorithm that permits any salt
+ * length.
+ *
+ * @details An RSA PSS signature algorithm that permits any salt length is constructed using
+ * @ref PSA_ALG_RSA_PSS_ANY_SALT().
+ *
+ * See also @ref PSA_ALG_IS_RSA_PSS() and @ref PSA_ALG_IS_RSA_PSS_STANDARD_SALT().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a RSA PSS signature algorithm that permits any salt length
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RSA_PSS_ANY_SALT(alg) \
+ (((alg) & ~0x000000ff) == 0x06001300)
+
+/**
+ * @brief Whether the specified algorithm is an RSA PSS signature algorithm that requires the
+ * standard salt length.
+ *
+ * @details An RSA PSS signature algorithm that requires the standard salt length is constructed
+ * using @ref PSA_ALG_RSA_PSS().
+ *
+ * See also @ref PSA_ALG_IS_RSA_PSS() and @ref PSA_ALG_IS_RSA_PSS_ANY_SALT().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an RSA PSS signature algorithm that requires the standard salt length
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_RSA_PSS_STANDARD_SALT(alg) \
+ (((alg) & ~0x000000ff) == 0x06000300)
+
+/**
+ * @brief Whether the specified algorithm is an asymmetric signature algorithm, also known as
+ * public-key signature algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is an asymmetric signature algorithm algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_SIGN(alg) \
+ (((alg) & 0x7f000000) == 0x06000000)
+
+/**
+ * @brief Whether the specified algorithm is a signature algorithm that can be used with
+ * @ref psa_sign_hash() and @ref psa_verify_hash().
+ *
+ * @details This includes all algorithms such that @ref PSA_ALG_IS_HASH_AND_SIGN() is true,
+ * as well as signature algorithms for which the input to @ref psa_sign_hash() or
+ * @ref psa_verify_hash() is not directly a hash, such as
+ * @ref PSA_ALG_IS_RSA_PKCS1V15_SIGN.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a signature algorithm that can be used to sign a hash.
+ * 0 if alg is a signature algorithm that can only be used to sign a message.
+ * 0 if alg is not a signature algorithm
+ */
+#define PSA_ALG_IS_SIGN_HASH(alg) \
+ PSA_ALG_IS_SIGN(alg)
+
+/**
+ * @brief Whether the specified algorithm is a signature algorithm that can be used with
+ * @ref psa_sign_message() and @ref psa_verify_message().
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a signature algorithm that can be used to sign a message.
+ * 0 if alg is a signature algorithm that can only be used to sign an already-calculated
+ * hash.
+ * 0 if alg is not a signature algorithm.
+ */
+#define PSA_ALG_IS_SIGN_MESSAGE(alg) \
+ (PSA_ALG_IS_SIGN(alg) && \
+ (alg) != PSA_ALG_ECDSA_ANY && (alg) != PSA_ALG_RSA_PKCS1V15_SIGN_RAW)
+
+/**
+ * @brief Whether the specified algorithm is a stream cipher.
+ *
+ * @details A stream cipher is a symmetric cipher that encrypts or decrypts messages by applying a
+ * bitwise-xor with a stream of bytes that is generated from a key.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a stream cipher
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_STREAM_CIPHER(alg) \
+ (((alg) & 0x7f800000) == 0x04800000)
+
+/**
+ * @brief Whether the specified algorithm is a TLS-1.2 PRF algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a TLS-1.2 PRF algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_TLS12_PRF(alg) \
+ (((alg) & ~0x000000ff) == 0x08000200)
+
+/**
+ * @brief Whether the specified algorithm is a TLS-1.2 PSK to MS algorithm.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a TLS-1.2 PSK to MS algorithm
+ * 0 otherwise
+ */
+#define PSA_ALG_IS_TLS12_PSK_TO_MS(alg) \
+ (((alg) & ~0x000000ff) == 0x08000300)
+
+/**
+ * @brief Whether the specified algorithm encoding is a wildcard.
+ *
+ * @details Wildcard algorithm values can only be used to set the permitted algorithm field in a
+ * key policy, wildcard values cannot be used to perform an operation.
+ *
+ * See @ref PSA_ALG_ANY_HASH for example of how a wildcard algorithm can be used in a key
+ * policy.
+ *
+ * @param alg An algorithm identifier: a value of type @ref psa_algorithm_t.
+ *
+ * @return 1 if alg is a wildcard algorithm encoding.
+ * 0 if alg is a non-wildcard algorithm encoding that is suitable for an operation.
+ */
+#define PSA_ALG_IS_WILDCARD(alg) \
+ (PSA_ALG_GET_HASH(alg) == PSA_ALG_HASH_ANY)
+
+/**
+ * @brief Macro to build a combined algorithm that chains a key agreement with a key derivation.
+ *
+ * @details A combined key agreement algorithm is used with a multi-part key derivation operation,
+ * using a call to @ref psa_key_derivation_key_agreement().
+ *
+ * The component parts of a key agreement algorithm can be extracted using
+ * @ref PSA_ALG_KEY_AGREEMENT_GET_BASE() and @ref PSA_ALG_KEY_AGREEMENT_GET_KDF().
+ *
+ * @b Compatible @b key @b types
+ * The resulting combined key agreement algorithm is compatible with the same key types as
+ * the raw key agreement algorithm used to construct it.
+ *
+ * @param ka_alg A key agreement algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_KEY_AGREEMENT(@p ka_alg) is true.
+ * @param kdf_alg A key derivation algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_KEY_DERIVATION(@p kdf_alg) is true.
+ *
+ * @return The corresponding key agreement and derivation algorithm.
+ * Unspecified if ka_alg is not a supported key agreement algorithm or kdf_alg is not a
+ * supported key derivation algorithm.
+ */
+#define PSA_ALG_KEY_AGREEMENT(ka_alg, kdf_alg) \
+ ((ka_alg) | (kdf_alg))
+
+/**
+ * @brief Get the raw key agreement algorithm from a full key agreement algorithm.
+ *
+ * @details See also @ref PSA_ALG_KEY_AGREEMENT() and @ref PSA_ALG_KEY_AGREEMENT_GET_KDF().
+ *
+ * @param alg A key agreement algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is true.
+ *
+ * @return The underlying raw key agreement algorithm if @c alg is a key agreement algorithm.
+ * Unspecified if alg is not a key agreement algorithm or if it is not supported by the
+ * implementation.
+ */
+#define PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) \
+ ((psa_algorithm_t)((alg) & 0xffff0000))
+
+/**
+ * @brief Get the key derivation algorithm used in a full key agreement algorithm.
+ *
+ * @details See also @ref PSA_ALG_KEY_AGREEMENT() and @ref PSA_ALG_KEY_AGREEMENT_GET_BASE().
+ *
+ * @param alg A key agreement algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_KEY_AGREEMENT(@p alg) is true.
+ *
+ * @return The underlying key derivation algorithm if @c alg is a key agreement algorithm.
+ * Unspecified if alg is not a key agreement algorithm or if it is not supported by the
+ * implementation.
+ */
+#define PSA_ALG_KEY_AGREEMENT_GET_KDF(alg) \
+ ((psa_algorithm_t)((alg) & 0xfe00ffff))
+
+/**
+ * @brief An invalid algorithm identifier value.
+ *
+ * @details Zero is not the encoding of any algorithm.
+ */
+#define PSA_ALG_NONE ((psa_algorithm_t)0)
+
+/**
+ * @brief Hash algorithm mask
+ */
+#define PSA_ALG_HASH_MASK ((psa_algorithm_t)0x000000ff)
+
+/**
+ * @brief The MD2 message-digest algorithm.
+ *
+ * @warning The MD2 hash is weak and deprecated and is only recommended
+ * for use in legacy protocols.
+ *
+ * @details MD2 is defined in *The MD2 Message-Digest Algorithm
+ * [RFC1319](https://tools.ietf.org/html/rfc1319.html)*.
+ */
+#define PSA_ALG_MD2 ((psa_algorithm_t)0x02000001)
+
+/**
+ * @brief The MD4 message-digest algorithm.
+ *
+ * @warning The MD4 hash is weak and deprecated and is only recommended
+ * for use in legacy protocols.
+ *
+ * @details MD4 is defined in *The MD4 Message-Digest Algorithm
+ * [RFC1320](https://tools.ietf.org/html/rfc1320.html)*.
+ */
+#define PSA_ALG_MD4 ((psa_algorithm_t)0x02000002)
+
+/**
+ * @brief The MD5 message-digest algorithm.
+ *
+ * @warning The MD5 hash is weak and deprecated and is only recommended
+ * for use in legacy protocols.
+ *
+ * @details MD5 is defined in *The MD5 Message-Digest Algorithm
+ * [RFC1321](https://tools.ietf.org/html/rfc1321.html)*.
+ */
+#define PSA_ALG_MD5 ((psa_algorithm_t)0x02000003)
+
+/**
+ * @brief The RIPEMD-160 message-digest algorithm.
+ *
+ * @details RIPEMD-160 is defined in *RIPEMD-160: A Strengthened Version of RIPEMD*,
+ * and also in *ISO/IEC 10118-3:2018 IT Security techniques — Hash-functions — Part 3:
+ * Dedicated hash-functions [ISO10118](https://www.iso.org/standard/67116.html)*.
+ */
+#define PSA_ALG_RIPEMD160 ((psa_algorithm_t)0x02000004)
+
+/**
+ * @brief The SHA-1 message-digest algorithm.
+ *
+ * @warning The SHA-1 hash is weak and deprecated and is only recommended
+ * for use in legacy protocols.
+ *
+ * @details SHA-1 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_1 ((psa_algorithm_t)0x02000005)
+
+/**
+ * @brief The SHA-224 message-digest algorithm.
+ *
+ * @details SHA-224 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_224 ((psa_algorithm_t)0x02000008) /** SHA-224 */
+
+/**
+ * @brief The SHA-256 message-digest algorithm.
+ *
+ * @details SHA-256 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_256 ((psa_algorithm_t)0x02000009) /** SHA-256 */
+
+/**
+ * @brief The SHA-384 message-digest algorithm.
+ *
+ * @details SHA-384 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_384 ((psa_algorithm_t)0x0200000a) /** SHA-384 */
+
+/**
+ * @brief The SHA-512 message-digest algorithm.
+ *
+ * @details SHA-512 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_512 ((psa_algorithm_t)0x0200000b) /** SHA-512 */
+
+/**
+ * @brief The SHA-512/224 message-digest algorithm.
+ *
+ * @details SHA-512-224 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_512_224 ((psa_algorithm_t)0x0200000c) /** SHA-512/224 */
+
+/**
+ * @brief The SHA-512/256 message-digest algorithm.
+ *
+ * @details SHA-512-256 is defined in FIPS Publication 180-4: Secure Hash Standard (SHS)
+ * [FIPS180-4](https://doi.org/10.6028/NIST.FIPS.180-4).
+ */
+#define PSA_ALG_SHA_512_256 ((psa_algorithm_t)0x0200000d) /** SHA-512/256 */
+
+/**
+ * @brief The SHA3-224 message-digest algorithm.
+ *
+ * @details SHA3-224 is defined in FIPS Publication 202: *SHA-3 Standard: Permutation-Based
+ * Hash and Extendable-Output Functions [FIPS202](https://doi.org/10.6028/NIST.FIPS.202)*.
+ */
+#define PSA_ALG_SHA3_224 ((psa_algorithm_t)0x02000010) /** SHA-3-224 */
+
+/**
+ * @brief The SHA3-256 message-digest algorithm.
+ *
+ * @details SHA3-256 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202).
+ */
+#define PSA_ALG_SHA3_256 ((psa_algorithm_t)0x02000011) /** SHA-3-256 */
+
+/**
+ * @brief The SHA3-384 message-digest algorithm.
+ *
+ * @details SHA3-384 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202).
+ */
+#define PSA_ALG_SHA3_384 ((psa_algorithm_t)0x02000012) /** SHA-3-384 */
+
+/**
+ * @brief The SHA3-512 message-digest algorithm.
+ *
+ * @details SHA3-512 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202).
+ */
+#define PSA_ALG_SHA3_512 ((psa_algorithm_t)0x02000013) /** SHA-3-512 */
+
+/**
+ * @brief The SM3 message-digest algorithm.
+ *
+ * @details SM3 is defined in *ISO/IEC 10118-3:2018 IT Security techniques — Hash-functions —
+ * Part 3: Dedicated hash-functions [ISO10118](https://www.iso.org/standard/67116.html)*,
+ * and also in *GM/T 0004-2012: SM3 cryptographic hash algorithm
+ * [CSTC0004](http://www.gmbz.org.cn/main/viewfile/20180108023812835219.html)
+ * (English version
+ * [CSTC0004/E](http://www.gmbz.org.cn/main/postDetail.html?id=20180724105928))*.
+ */
+#define PSA_ALG_SM3 ((psa_algorithm_t)0x02000014) /** SM3 */
+
+/**
+ * @brief The first 512 bits (64 bytes) of the SHAKE256 output.
+ *
+ * @details This is the prehashing for Ed448ph (see @ref PSA_ALG_ED448PH).
+ *
+ * SHAKE256 is defined in [FIPS202](https://doi.org/10.6028/NIST.FIPS.202).
+ *
+ * @note For other scenarios where a hash function based on SHA3 or SHAKE is required, SHA3-512
+ * is recommended. SHA3-512 has the same output size, and a theoretically higher security
+ * strength.
+ */
+#define PSA_ALG_SHAKE256_512 ((psa_algorithm_t)0x02000015)
+
+/**
+ * @brief The CBC-MAC message-authentication-code algorithm, constructed over a block cipher.
+ *
+ * @warning CBC-MAC is insecure in many cases. A more secure mode, such as @ref PSA_ALG_CMAC,
+ * is recommended.
+ *
+ * @details The CBC-MAC algorithm must be used with a key for a block cipher.
+ * For example, one of @ref PSA_KEY_TYPE_AES.
+ *
+ * CBC-MAC is defined as MAC Algorithm 1 in ISO/IEC 9797-1:2011 Information technology —
+ * Security techniques — Message Authentication Codes (MACs) — Part 1: Mechanisms using a
+ * block cipher
+ * [ISO9797](https://www.iso.org/standard/50375.html).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CBC_MAC ((psa_algorithm_t)0x03c00100)
+
+/**
+ * @brief The CMAC message-authentication-code algorithm, constructed over a block cipher.
+ *
+ * @details The CMAC algorithm must be used with a key for a block cipher. For example, when used
+ * with a key with type @ref PSA_KEY_TYPE_AES, the resulting operation is AES-CMAC.
+ *
+ * CMAC is defined in NIST Special Publication 800-38B: Recommendation for Block Cipher
+ * Modes of Operation: the CMAC Mode for Authentication
+ * [SP800-38B](https://doi.org/10.6028/NIST.SP.800-38B).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CMAC ((psa_algorithm_t)0x03c00200)
+
+/**
+ * @brief The Cipher Block Chaining (CBC) mode of a block cipher, with no padding.
+ *
+ * @details The underlying block cipher is determined by the key type. This symmetric cipher mode
+ * can only be used with messages whose lengths are a multiple of the block size of the
+ * chosen block cipher.
+ *
+ * CBC mode requires an initialization vector (IV) that is the same size as the cipher
+ * block length.
+ *
+ * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ *
+ * The CBC block cipher mode is defined in NIST Special Publication 800-38A:
+ * Recommendation for Block Cipher Modes of Operation: Methods and Techniques
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38B).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CBC_NO_PADDING ((psa_algorithm_t)0x04404000)
+
+/**
+ * @brief The Cipher Block Chaining (CBC) mode of a block cipher, with PKCS#7 padding.
+ *
+ * @details The underlying block cipher is determined by the key type.
+ *
+ * CBC mode requires an initialization vector (IV) that is the same size as the cipher
+ * block length.
+ *
+ * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ *
+ * The CBC block cipher mode is defined in NIST Special Publication 800-38A:
+ * Recommendation for Block Cipher Modes of Operation: Methods and Techniques
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38B).
+ * The padding operation is defined by PKCS #7: Cryptographic Message Syntax Version 1.5
+ * [RFC2315](https://tools.ietf.org/html/rfc2315.html) §10.3.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CBC_PKCS7 ((psa_algorithm_t)0x04404100)
+
+/**
+ * @brief The Electronic Codebook (ECB) mode of a block cipher, with no padding.
+ *
+ * @warning ECB mode does not protect the confidentiality of the encrypted data except in extremely
+ * narrow circumstances. It is recommended that applications only use ECB if they need to
+ * construct an operating mode that the implementation does not provide. Implementations
+ * are encouraged to provide the modes that applications need in preference to supporting
+ * direct access to ECB.
+ *
+ * @details The underlying block cipher is determined by the key type.
+ *
+ * This symmetric cipher mode can only be used with messages whose lengths are a multiple
+ * of the block size of the chosen block cipher.
+ *
+ * ECB mode does not accept an initialization vector (IV). When using a multi-part cipher
+ * operation with this algorithm, @ref psa_cipher_generate_iv() and
+ * @ref psa_cipher_set_iv() must not be called.
+ *
+ * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ *
+ * The ECB block cipher mode is defined in NIST Special Publication 800-38A:
+ * Recommendation for Block Cipher Modes of Operation: Methods and Techniques
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_ECB_NO_PADDING ((psa_algorithm_t)0x04404400)
+
+/**
+ * @brief The XEX with Ciphertext Stealing (XTS) cipher mode of a block cipher.
+ *
+ * @details XTS is a cipher mode which is built from a block cipher, designed for use in disk
+ * encryption. It requires at least one full cipher block length of input, but beyond this
+ * minimum the input does not need to be a whole number of blocks.
+ *
+ * XTS mode uses two keys for the underlying block cipher. These are provided by using a
+ * key that is twice the normal key size for the cipher. For example, to use AES-256-XTS
+ * the application must create a key with type @ref PSA_KEY_TYPE_AES and bit size 512.
+ *
+ * XTS mode requires an initialization vector (IV) that is the same size as the cipher
+ * block length. The IV for XTS is typically defined to be the sector number of the disk
+ * block being encrypted or decrypted.
+ *
+ * The XTS block cipher mode is defined in 1619-2018 --- IEEE Standard for Cryptographic
+ * Protection of Data on Block-Oriented Storage Devices
+ * [IEEE-XTS](https://ieeexplore.ieee.org/servlet/opac?punumber=8637986).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_XTS ((psa_algorithm_t)0x0440ff00)
+
+/**
+ * @brief A stream cipher built using the Counter (CTR) mode of a block cipher.
+ *
+ * @details CTR is a stream cipher which is built from a block cipher. The underlying block cipher
+ * is determined by the key type. For example, to use AES-128-CTR, use this algorithm with
+ * a key of type @ref PSA_KEY_TYPE_AES and a size of 128 bits (16 bytes).
+ *
+ * The CTR block cipher mode is defined in NIST Special Publication 800-38A:
+ * Recommendation for Block Cipher Modes of Operation: Methods and Techniques [SP800-38A].
+ *
+ * CTR mode requires a counter block which is the same size as the cipher block length.
+ * The counter block is updated for each block (or a partial final block) that is
+ * encrypted or decrypted.
+ *
+ * A counter block value must only be used once across all messages encrypted using the
+ * same key value. This is typically achieved by splitting the counter block into a nonce,
+ * which is unique among all message encrypted with the key, and a counter which is
+ * incremented for each block of a message.
+ *
+ * For example, when using AES-CTR encryption, which uses a 16-byte block, the application
+ * can provide a 12-byte nonce when setting the IV. This leaves 4 bytes for the counter,
+ * allowing up to 2^32 blocks (64GB) of message data to be encrypted in each message.
+ *
+ * The first counter block is constructed from the initialization vector (IV). The initial
+ * counter block is is constructed in the following ways:
+ * - A call to @ref psa_cipher_encrypt() will generate a random counter block value.
+ * This is the first block of output.
+ * - A call to @ref psa_cipher_decrypt() will use first block of the input buffer as the
+ * initial counter block value.
+ * - A call to @ref psa_cipher_generate_iv() on a multi-part cipher operation will
+ * generate and return a random counter block value.
+ * - A call to @ref psa_cipher_set_iv() on a multi-part cipher operation requires an IV
+ * that is between 1 and n bytes in length, where n is the cipher block length. The
+ * counter block is initialized using the IV, and padded with zero bytes up to the
+ * block length.
+ *
+ * During the counter block update operation, the counter block is treated as a single
+ * big-endian encoded integer and the update operation increments this integer by 1.
+ *
+ * This scheme meets the recommendations in Appendix B of
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A).
+ *
+ * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CTR ((psa_algorithm_t)0x04c01000)
+
+/**
+ * @brief A stream cipher built using the Cipher Feedback (CFB) mode of a block cipher.
+ *
+ * @details The underlying block cipher is determined by the key type. This is the variant of CFB
+ * where each iteration encrypts or decrypts a segment of the input that is the same
+ * length as the cipher block size. For example, using @ref PSA_ALG_CFB with a key of type
+ * @ref PSA_KEY_TYPE_AES will result in the AES-CFB-128 cipher.
+ *
+ * CFB mode requires an initialization vector (IV) that is the same size as the cipher
+ * block length.
+ *
+ * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ *
+ * The CFB block cipher mode is defined in NIST Special Publication 800-38A:
+ * Recommendation for Block Cipher Modes of Operation: Methods and Techniques
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A), using a segment size s equal
+ * to the block size b. The definition in
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A) is
+ * extended to allow an incomplete final block of input, in which case the algorithm
+ * discards the final bytes of the key stream when encrypting or decrypting the final
+ * partial block.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CFB ((psa_algorithm_t)0x04c01100)
+
+/**
+ * @brief A stream cipher built using the Output Feedback (OFB) mode of a block cipher.
+ *
+ * @details The underlying block cipher is determined by the key type.
+ *
+ * OFB mode requires an initialization vector (IV) that is the same size as the cipher
+ * block length. OFB mode requires that the IV is a nonce, and must be unique for each use
+ * of the mode with the same key.
+ *
+ * @note The cipher block length can be determined using @ref PSA_BLOCK_CIPHER_BLOCK_LENGTH().
+ *
+ * The OFB block cipher mode is defined in NIST Special Publication 800-38A:
+ * Recommendation for Block Cipher Modes of Operation: Methods and Techniques
+ * [SP800-38A](https://doi.org/10.6028/NIST.SP.800-38A).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_DES
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_OFB ((psa_algorithm_t)0x04c01200)
+
+/**
+ * @brief The stream cipher mode of a stream cipher algorithm.
+ *
+ * @details The underlying stream cipher is determined by the key type. The ARC4 and ChaCha20
+ * ciphers use this algorithm identifier.
+ *
+ * @b ARC4
+ * To use ARC4, use a key type of @ref PSA_KEY_TYPE_ARC4 and algorithm id
+ * @ref PSA_ALG_STREAM_CIPHER.
+ *
+ * @warning The ARC4 cipher is weak and deprecated and is only recommended for use in legacy
+ * protocols.
+ *
+ * The ARC4 cipher does not use an initialization vector (IV). When using a multi-part
+ * cipher operation with the @ref PSA_ALG_STREAM_CIPHER algorithm and an ARC4 key,
+ * @ref psa_cipher_generate_iv() and @ref psa_cipher_set_iv() must not be called.
+ *
+ * @b ChaCha20
+ * To use ChaCha20, use a key type of @ref PSA_KEY_TYPE_CHACHA20 and algorithm id
+ * @ref PSA_ALG_STREAM_CIPHER.
+ *
+ * Implementations must support the variant that is defined in ChaCha20 and Poly1305 for
+ * IETF Protocols [RFC7539](https://tools.ietf.org/html/rfc7539.html) §2.4, which has a
+ * 96-bit nonce and a 32-bit counter.
+ * Implementations can optionally also support the original variant, as defined in ChaCha,
+ * a variant of Salsa20 [CHACHA20](http://cr.yp.to/chacha/chacha-20080128.pdf),
+ * which has a 64-bit nonce and a 64-bit counter. Except where noted, the
+ * [RFC7539](https://tools.ietf.org/html/rfc7539.html) variant must be used.
+ *
+ * ChaCha20 defines a nonce and an initial counter to be provided to the encryption and
+ * decryption operations. When using a ChaCha20 key with the @ref PSA_ALG_STREAM_CIPHER
+ * algorithm, these values are provided using the initialization vector (IV) functions in
+ * the following ways:
+ * - A call to @ref psa_cipher_encrypt() will generate a random 12-byte nonce, and set
+ * the counter value to zero. The random nonce is output as a 12-byte IV value in the
+ * output.
+ * - A call to @ref psa_cipher_decrypt() will use first 12 bytes of the input buffer as
+ * the nonce and set the counter value to zero.
+ * - A call to @ref psa_cipher_generate_iv() on a multi-part cipher operation will
+ * generate and return a random 12-byte nonce and set the counter value to zero.
+ * - A call to @ref psa_cipher_set_iv() on a multi-part cipher operation can support
+ * the following IV sizes:
+ * - 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 is used as the nonce.
+ * - 8 bytes: the cipher operation uses the original
+ * [CHACHA20](http://cr.yp.to/chacha/chacha-20080128.pdf) 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.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ARC4
+ * - @ref PSA_KEY_TYPE_CHACHA20
+ */
+#define PSA_ALG_STREAM_CIPHER ((psa_algorithm_t)0x04800100)
+
+/**
+ * @brief The ChaCha20-Poly1305 AEAD algorithm.
+ *
+ * @details There are two defined variants of ChaCha20-Poly1305:
+ * - An implementation that supports ChaCha20-Poly1305 must support the variant defined
+ * by ChaCha20 and Poly1305 for IETF Protocols
+ * [RFC7539](https://tools.ietf.org/html/rfc7539.html), which has a 96-bit nonce and
+ * 32-bit counter.
+ * - An implementation can optionally also support the original variant defined by
+ * ChaCha, a variant of Salsa20
+ * [CHACHA20](http://cr.yp.to/chacha/chacha-20080128.pdf), which has a 64-bit nonce
+ * and 64-bit counter.
+ *
+ * The variant used for the AEAD encryption or decryption operation, depends on the nonce
+ * provided for an AEAD operation using @ref PSA_ALG_CHACHA20_POLY1305 :
+ * - A nonce provided in a call to @ref psa_aead_encrypt(), @ref psa_aead_decrypt() or
+ * @ref psa_aead_set_nonce() must be 8 or 12 bytes. The size of nonce will select the
+ * appropriate variant of the algorithm.
+ * - A nonce generated by a call to @ref psa_aead_generate_nonce() will be 12 bytes, and
+ * will use the [RFC7539](https://tools.ietf.org/html/rfc7539.html) variant.
+ *
+ * Implementations must support 16-byte tags. It is recommended that truncated tag sizes
+ * are rejected.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_CHACHA20
+ */
+#define PSA_ALG_CHACHA20_POLY1305 ((psa_algorithm_t)0x05100500)
+
+/**
+ * @brief The Counter with CBC-MAC (CCM) authenticated encryption algorithm.
+ *
+ * @details CCM is defined for block ciphers that have a 128-bit block size. The underlying block
+ * cipher is determined by the key type.
+ *
+ * To use @ref PSA_ALG_CCM with a multi-part AEAD operation, the application must call
+ * @ref psa_aead_set_lengths() before providing the nonce, the additional data and
+ * plaintext to the operation.
+ *
+ * CCM requires a nonce of between 7 and 13 bytes in length. The length of the nonce
+ * affects the `m` maximum length of the plaintext than can be encrypted or decrypted. If
+ * the nonce has length `N`, then the plaintext length `pLen` is encoded in `L = 15 - N`
+ * octets, this requires that `pLen < 28L`.
+ *
+ * The value for L that is used with PSA_ALG_CCM depends on the function used to provide
+ * the nonce:
+ * - A call to @ref psa_aead_encrypt(), @ref psa_aead_decrypt(), or @ref
+ * psa_aead_set_nonce() will set `L` to 15 - nonce_length. If the plaintext length
+ * cannot be encoded in `L` octets, then a @ref PSA_ERROR_INVALID_ARGUMENT error is
+ * returned.
+ * - A call to @ref psa_aead_generate_nonce() on a multi-part cipher operation will
+ * select `L` as the smallest integer `>= 2` where `pLen < 28L`, with `pLen` being the
+ * plaintext_length provided to @ref psa_aead_set_lengths(). The call to @ref
+ * psa_aead_generate_nonce() will generate and return a random nonce of length
+ * `15 - L` bytes.
+ *
+ * CCM supports authentication tag sizes of 4, 6, 8, 10, 12, 14, and 16 bytes. The default
+ * tag length is 16. Shortened tag lengths can be requested using
+ * @ref PSA_ALG_AEAD_WITH_SHORTENED_TAG(@ref PSA_ALG_CCM, @p tag_length),
+ * where @c tag_length is a valid CCM tag length.
+ *
+ * The CCM block cipher mode is defined in Counter with CBC-MAC (CCM)
+ * [RFC3610](https://tools.ietf.org/html/rfc3610).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_CCM ((psa_algorithm_t)0x05500100)
+
+/**
+ * @brief The Galois/Counter Mode (GCM) authenticated encryption algorithm.
+ *
+ * @details GCM is defined for block ciphers that have a 128-bit block size. The underlying block
+ * cipher is determined by the key type.
+ *
+ * GCM requires a nonce of at least 1 byte in length. The maximum supported nonce size is
+ * implementation defined. Calling @ref psa_aead_generate_nonce() will generate a random
+ * 12-byte nonce.
+ *
+ * GCM supports authentication tag sizes of 4, 8, 12, 13, 14, 15, and 16 bytes. The
+ * default tag length is 16. Shortened tag lengths can be requested using
+ * @ref PSA_ALG_AEAD_WITH_SHORTENED_TAG(@ref PSA_ALG_GCM, @p tag_length), where
+ * @c tag_length is a valid GCM tag length.
+ *
+ * The GCM block cipher mode is defined in NIST Special Publication 800-38D:
+ * Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC
+ * [SP800-38D](https://doi.org/10.6028/NIST.SP.800-38D).
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_AES
+ * - @ref PSA_KEY_TYPE_ARIA
+ * - @ref PSA_KEY_TYPE_CAMELLIA
+ * - @ref PSA_KEY_TYPE_SM4
+ */
+#define PSA_ALG_GCM ((psa_algorithm_t)0x05500200)
+
+/**
+ * @brief The PBKDF2-AES-CMAC-PRF-128 password-hashing or key-stretching algorithm.
+ *
+ * @details PBKDF2 is specified by PKCS #5: Password-Based Cryptography Specification Version 2.1
+ * [RFC8018](https://tools.ietf.org/html/rfc8018.html) §5.2. This algorithm specifies the
+ * PBKDF2 algorithm using the AES-CMAC-PRF-128 pseudo-random function specified by
+ * [RFC4615](https://tools.ietf.org/html/rfc4615.html).
+ *
+ * This key derivation algorithm uses the same inputs as @ref PSA_ALG_PBKDF2_HMAC() with
+ * the same constraints.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_DERIVE (for password input)
+ * - @ref PSA_KEY_TYPE_PASSWORD (for password input)
+ * - @ref PSA_KEY_TYPE_PEPPER (for salt input)
+ * - @ref PSA_KEY_TYPE_RAW_DATA (for salt input)
+ * - @ref PSA_KEY_TYPE_PASSWORD_HASH (for key verification)
+ */
+#define PSA_ALG_PBKDF2_AES_CMAC_PRF_128 ((psa_algorithm_t)0x08800200)
+
+/**
+ * @brief Macro to build a PBKDF2-HMAC password-hashing or key-stretching algorithm.
+ *
+ * @details PBKDF2 is specified by PKCS #5: Password-Based Cryptography Specification Version 2.1
+ * [RFC8018](https://tools.ietf.org/html/rfc8018.html) §5.2. This macro constructs a
+ * PBKDF2 algorithm that uses a pseudo-random function based on HMAC with the specified
+ * hash.
+ *
+ * This key derivation algorithm uses the following inputs, which must be provided in the
+ * following order:
+ * - @ref PSA_KEY_DERIVATION_INPUT_COST is the iteration count. This input step must be
+ * used exactly once.
+ * - @ref PSA_KEY_DERIVATION_INPUT_SALT is the salt. This input step must be used one or
+ * more times; if used several times, the inputs will be concatenated. This can be
+ * used to build the final salt from multiple sources, both public and secret (also
+ * known as pepper).
+ * - @ref PSA_KEY_DERIVATION_INPUT_PASSWORD is the password to be hashed. This input
+ * step must be used exactly once.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_DERIVE (for password input)
+ * - @ref PSA_KEY_TYPE_PASSWORD (for password input)
+ * - @ref PSA_KEY_TYPE_PEPPER (for salt input)
+ * - @ref PSA_KEY_TYPE_RAW_DATA (for salt input)
+ * - @ref PSA_KEY_TYPE_PASSWORD_HASH (for key verification)
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true.
+ *
+ * @return The corresponding `PBKDF2-HMAC-XXX` algorithm. For example,
+ * @ref PSA_ALG_PBKDF2_HMAC(@ref PSA_ALG_SHA_256) is the algorithm identifier for
+ * `PBKDF2-HMAC-SHA-256`.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_PBKDF2_HMAC(hash_alg) \
+ ((psa_algorithm_t)(0x08800100 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief The raw RSA PKCS#1 v1.5 signature algorithm, without hashing.
+ *
+ * @details This algorithm can be only used with the @ref psa_sign_hash() and @ref psa_verify_hash()
+ * functions.
+ * This signature scheme is defined by PKCS #1: RSA Cryptography Specifications Version 2.2
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.2 under the name
+ * RSASSA-PKCS1-v1_5.
+ *
+ * The hash parameter to @ref psa_sign_hash() or @ref psa_verify_hash() is used as `T`
+ * from step 3 onwards in the message encoding algorithm EMSA-PKCS1-V1_5-ENCODE() in
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §9.2.0 `T` is the DER encoding of
+ * the DigestInfo structure normally produced by step 2 in the message encoding algorithm.
+ *
+ * The wildcard key policy @ref PSA_ALG_RSA_PKCS1V15_SIGN(@ref PSA_ALG_ANY_HASH) also
+ * permits a key to be used with the @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW signature
+ * algorithm.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR
+ * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only)
+ */
+#define PSA_ALG_RSA_PKCS1V15_SIGN_RAW ((psa_algorithm_t)0x06000200)
+
+/**
+ * @brief Base of ECDSA algorithms
+ */
+#define PSA_ALG_ECDSA_BASE ((psa_algorithm_t)0x06000600)
+
+/**
+ * @brief Edwards-curve digital signature algorithm without prehashing (PureEdDSA),
+ * using standard parameters.
+ *
+ * @details This algorithm can be only used with the @ref psa_sign_message() and
+ * @ref psa_verify_message() functions.
+ *
+ * This is the PureEdDSA digital signature algorithm defined by Edwards-Curve Digital
+ * Signature Algorithm (EdDSA) [RFC8032](https://tools.ietf.org/html/rfc8032.html),
+ * using standard parameters.
+ *
+ * PureEdDSA requires an elliptic curve key on a twisted Edwards curve. The following
+ * curves are supported:
+ * - Edwards25519: the Ed25519 algorithm is computed. The output signature is a 64-byte
+ * string: the concatenation of R and S as defined by
+ * [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.1.6.
+ * - Edwards448: the Ed448 algorithm is computed with an empty string as the context.
+ * The output signature is a 114-byte string: the concatenation of R and S as defined
+ * by [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.2.6.
+ *
+ * @note Contexts are not supported in the current version of this specification because there
+ * is no suitable signature interface that can take the context as a parameter. A future
+ * version of this specification may add suitable functions and extend this algorithm to
+ * support contexts.
+ *
+ * @note To sign or verify the pre-computed hash of a message using EdDSA, the HashEdDSA
+ * algorithms (@ref PSA_ALG_ED25519PH and @ref PSA_ALG_ED448PH) can be used with
+ * @ref psa_sign_hash() and @ref psa_verify_hash().
+ * The signature produced by HashEdDSA is distinct from that produced by PureEdDSA.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS)
+ * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS) (signature
+ * verification only)
+ */
+#define PSA_ALG_PURE_EDDSA ((psa_algorithm_t)0x06000800)
+
+/**
+ * @brief The randomized ECDSA signature scheme, with hashing.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This algorithm is randomized: each invocation returns a different, equally valid
+ * signature.
+ *
+ * @note When based on the same hash algorithm, the verification operations for
+ * @ref PSA_ALG_ECDSA and @ref PSA_ALG_DETERMINISTIC_ECDSA are identical.
+ * A signature created using @ref PSA_ALG_ECDSA can be verified with the same key using
+ * either @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA.
+ * Similarly, a signature created using @ref PSA_ALG_DETERMINISTIC_ECDSA can be verified
+ * with the same key using either @ref PSA_ALG_ECDSA or @ref PSA_ALG_DETERMINISTIC_ECDSA.
+ *
+ * In particular, it is impossible to determine whether a signature was produced with
+ * deterministic ECDSA or with randomized ECDSA: it is only possible to verify that a
+ * signature was made with ECDSA with the private key corresponding to the public key used
+ * for the verification.
+ *
+ * This signature scheme is defined by SEC 1: Elliptic Curve Cryptography
+ * [SEC1](https://www.secg.org/sec1-v2.pdf), and also by Public Key Cryptography For The
+ * Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)
+ * [X9-62])(https://standards.globalspec.com/std/1955141/ANSI%20X9.62), with a random
+ * per-message secret number `k`.
+ *
+ * The representation of the signature as a byte string consists of the concatenation of
+ * the signature values `r` and `s`. Each of `r` and `s` is encoded as an `N`-octet
+ * string, where `N` is the length of the base point of the curve in octets. Each value is
+ * represented in big-endian order, with the most significant octet first.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(family)
+ * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(family) (signature verification only)
+ *
+ * where family is a Weierstrass Elliptic curve family. That is, one of the following
+ * values:
+ * - @c PSA_ECC_FAMILY_SECT_XX
+ * - @c PSA_ECC_FAMILY_SECP_XX
+ * - @ref PSA_ECC_FAMILY_FRP
+ * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. This includes
+ * @ref PSA_ALG_ANY_HASH when specifying the algorithm in a key policy.
+ *
+ * @return The corresponding randomized ECDSA signature algorithm.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_ECDSA(hash_alg) \
+ (PSA_ALG_ECDSA_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))
+
+/**
+ * @brief The randomized ECDSA signature scheme, without hashing.
+ *
+ * @details This algorithm can be only used with the @ref psa_sign_hash() and @ref psa_verify_hash()
+ * functions.
+ *
+ * This algorithm is randomized: each invocation returns a different, equally valid
+ * signature.
+ *
+ * This is the same signature scheme as @ref PSA_ALG_ECDSA(), but without specifying a hash
+ * algorithm, and skipping the message hashing operation.
+ *
+ * This algorithm is only recommended to sign or verify a sequence of bytes that are an
+ * already-calculated hash. Note that the input is padded with zeros on the left or
+ * truncated on the right as required to fit the curve size.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@p family)
+ * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@p family) (signature verification only)
+ *
+ * where @c family is a Weierstrass Elliptic curve family. That is, one of the following
+ * values:
+ * - @c PSA_ECC_FAMILY_SECT_XX
+ * - @c PSA_ECC_FAMILY_SECP_XX
+ * - @ref PSA_ECC_FAMILY_FRP
+ * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1
+ */
+#define PSA_ALG_ECDSA_ANY PSA_ALG_ECDSA_BASE
+
+/**
+ * @brief Edwards-curve digital signature algorithm with prehashing (HashEdDSA), using the
+ * Edwards25519 curve.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This computes the Ed25519ph algorithm as specified in Edwards-Curve Digital Signature
+ * Algorithm (EdDSA) [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.1, and
+ * requires an Edwards25519 curve key. An empty string is used as the context. The prehash
+ * function is SHA-512.
+ *
+ * @b Usage
+ * This is a hash-and-sign algorithm. To calculate a signature, use one of the following
+ * approaches:
+ * - Call @ref psa_sign_message() with the message.
+ * - Calculate the SHA-512 hash of the message with @ref psa_hash_compute(), or with a
+ * multi-part hash operation, using the hash algorithm @ref PSA_ALG_SHA_512. Then sign
+ * the calculated hash with @ref psa_sign_hash().
+ *
+ * Verifying a signature is similar, using @ref psa_verify_message() or
+ * @ref psa_verify_hash() instead of the signature function.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS)
+ * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS) (signature
+ * verification only)
+ */
+#define PSA_ALG_ED25519PH ((psa_algorithm_t)0x0600090B)
+
+/**
+ * @brief Edwards-curve digital signature algorithm with prehashing (HashEdDSA), using the
+ * Edwards448 curve.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This computes the Ed448ph algorithm as specified in Edwards-Curve Digital Signature
+ * Algorithm (EdDSA) [RFC8032](https://tools.ietf.org/html/rfc8032.html) §5.2, and
+ * requires an Edwards448 curve key. An empty string is used as the context. The prehash
+ * function is the first 64 bytes of the output from SHAKE256.
+ *
+ * @b Usage
+ * This is a hash-and-sign algorithm. To calculate a signature, use one of the following
+ * approaches:
+ * - Call @ref psa_sign_message() with the message.
+ * - Calculate the first 64 bytes of the SHAKE256 output of the message with
+ * @ref psa_hash_compute(), or with a multi-part hash operation, using the hash
+ * algorithm @ref PSA_ALG_SHAKE256_512. Then sign the calculated hash with
+ * @ref psa_sign_hash().
+ *
+ * Verifying a signature is similar, using @ref psa_verify_message() or
+ * @ref psa_verify_hash() instead of the signature function.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS)
+ * - @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY(@ref PSA_ECC_FAMILY_TWISTED_EDWARDS) (signature
+ * verification only)
+ */
+#define PSA_ALG_ED448PH ((psa_algorithm_t)0x06000915)
+
+/**
+ * @brief The RSA PKCS#1 v1.5 asymmetric encryption algorithm.
+ *
+ * @details This encryption scheme is defined by PKCS #1: RSA Cryptography Specifications
+ * Version 2.2 [RFC8017](https://tools.ietf.org/html/rfc8017.html) §7.2 under the
+ * name RSAES-PKCS-v1_5.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR
+ * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (asymmetric encryption only)
+ */
+#define PSA_ALG_RSA_PKCS1V15_CRYPT ((psa_algorithm_t)0x07000200)
+
+/**
+ * @brief The finite-field Diffie-Hellman (DH) key agreement algorithm.
+ *
+ * @details This algorithm can be used directly in a call to @ref psa_raw_key_agreement(),
+ * or combined with a key derivation operation using @ref PSA_ALG_KEY_AGREEMENT() for use
+ * with @ref psa_key_derivation_key_agreement().
+ *
+ * When used as a key’s permitted algorithm policy, the following uses are permitted:
+ * - In a call to @ref psa_raw_key_agreement(), with algorithm @ref PSA_ALG_FFDH.
+ * - In a call to @ref psa_key_derivation_key_agreement(), with any combined key
+ * agreement and key derivation algorithm constructed with @ref PSA_ALG_FFDH.
+ *
+ * When used as part of a multi-part key derivation operation, this implements a
+ * Diffie-Hellman key agreement scheme using a single Diffie-Hellman key-pair for each
+ * participant. This includes the `dhEphem`, `dhOneFlow`, and `dhStatic` schemes.
+ * The input step @ref PSA_KEY_DERIVATION_INPUT_SECRET is used when providing the secret
+ * and peer keys to the operation.
+ *
+ * The shared secret produced by this key agreement algorithm is `g^{ab}` in big-endian
+ * format. It is `ceiling(m / 8)` bytes long where `m` is the size of the prime `p` in
+ * bits.
+ *
+ * This key agreement scheme is defined by NIST Special Publication 800-56A:
+ * Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm
+ * Cryptography [SP800-56A](https://doi.org/10.6028/NIST.SP.800-56Ar3) §5.7.1.1
+ * under the name FFC DH.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_DH_KEY_PAIR()
+ */
+#define PSA_ALG_FFDH ((psa_algorithm_t)0x09010000)
+
+/**
+ * @brief The elliptic curve Diffie-Hellman (ECDH) key agreement algorithm.
+ *
+ * @details This algorithm can be used directly in a call to @ref psa_raw_key_agreement(), or
+ * combined with a key derivation operation using @ref PSA_ALG_KEY_AGREEMENT() for use
+ * with @ref psa_key_derivation_key_agreement().
+ *
+ * When used as a key’s permitted algorithm policy, the following uses are permitted:
+ * - In a call to @ref psa_raw_key_agreement(), with algorithm @ref PSA_ALG_ECDH.
+ * - In a call to @ref psa_key_derivation_key_agreement(), with any combined key
+ * agreement and key derivation algorithm constructed with @ref PSA_ALG_ECDH.
+ *
+ * When used as part of a multi-part key derivation operation, this implements a
+ * Diffie-Hellman key agreement scheme using a single elliptic curve key-pair for each
+ * participant. This includes the Ephemeral unified model, the Static unified model, and
+ * the One-pass Diffie-Hellman schemes. The input step
+ * @ref PSA_KEY_DERIVATION_INPUT_SECRET is used when providing the secret and peer keys
+ * to the operation.
+ *
+ * The shared secret produced by key agreement is the x-coordinate of the shared secret
+ * point. It is always `ceiling(m / 8)` bytes long where `m` is the bit size associated
+ * with the curve, i.e. the bit size of the order of the curve’s coordinate field. When
+ * `m` is not a multiple of 8, the byte containing the most significant bit of the shared
+ * secret is padded with zero bits. The byte order is either little-endian or big-endian
+ * depending on the curve type.
+ *
+ * - For Montgomery curves (curve family @ref PSA_ECC_FAMILY_MONTGOMERY), the shared
+ * secret is the x-coordinate of `Z = d_A Q_B = d_B Q_A` in little-endian byte order.
+ * - For Curve25519, this is the X25519 function defined in Curve25519: new
+ * Diffie-Hellman speed records
+ * [Curve25519](https://www.iacr.org/archive/pkc2006/39580209/39580209.pdf).
+ * The bit size `m` is 255.
+ * - For Curve448, this is the X448 function defined in Ed448-Goldilocks, a new
+ * elliptic curve [Curve448](https://eprint.iacr.org/2015/625.pdf).
+ * The bit size `m` is 448.
+ * - For Weierstrass curves (curve families @c PSA_ECC_FAMILY_SECP_XX,
+ * @c PSA_ECC_FAMILY_SECT_XX, @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 and
+ * @ref PSA_ECC_FAMILY_FRP) the shared secret is the x-coordinate of
+ * `Z = h d_A Q_B = h d_B Q_A` in big-endian byte order. This is the Elliptic Curve
+ * Cryptography Cofactor Diffie-Hellman primitive defined by SEC 1: Elliptic Curve
+ * Cryptography [SEC1](https://www.secg.org/sec1-v2.pdf) §3.3.2 as, and also as ECC
+ * CDH by NIST Special Publication 800-56A: Recommendation for Pair-Wise
+ * Key-Establishment Schemes Using Discrete Logarithm Cryptography
+ * [SP800-56A](https://doi.org/10.6028/NIST.SP.800-56Ar3) §5.7.1.2.
+ * - Over prime fields (curve families @c PSA_ECC_FAMILY_SECP_XX,
+ * @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1 and @ref PSA_ECC_FAMILY_FRP),
+ * the bit size is `m = ceiling(log_2(p))` for the field `F_p`.
+ * - Over binary fields (curve families @c PSA_ECC_FAMILY_SECT_XX), the bit size
+ * is `m` for the field `F_{2^m}`.
+ *
+ * @note The cofactor Diffie-Hellman primitive is equivalent to the standard elliptic curve
+ * Diffie-Hellman calculation `Z = d_A Q_B = d_B Q_A`
+ * ([SEC1](https://www.secg.org/sec1-v2.pdf) §3.3.1) for curves where the cofactor `h`
+ * is 1. This is true for all curves in the @c PSA_ECC_FAMILY_SECP_XX,
+ * @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1, and @ref PSA_ECC_FAMILY_FRP families.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_ECC_KEY_PAIR(@p family)
+ *
+ * where @p family is a Weierstrass or Montgomery Elliptic curve family. That is, one of
+ * the following values:
+ * - @c PSA_ECC_FAMILY_SECT_XX
+ * - @c PSA_ECC_FAMILY_SECP_XX
+ * - @ref PSA_ECC_FAMILY_FRP
+ * - @ref PSA_ECC_FAMILY_BRAINPOOL_P_R1
+ * - @ref PSA_ECC_FAMILY_MONTGOMERY
+ */
+#define PSA_ALG_ECDH ((psa_algorithm_t)0x09020000)
+
+/**
+ * @brief The RSA OAEP asymmetric encryption algorithm.
+ *
+ * @details This encryption scheme is defined by
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §7.1 under the name RSAES-OAEP,
+ * with the following options:
+ * - The mask generation function MGF1 defined in
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) Appendix B.2.1.
+ * - The specified hash algorithm is used to hash the label, and for the mask generation
+ * function.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR
+ * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (asymmetric encryption only)
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. The hash algorithm is used for
+ * MGF1.
+ *
+ * @return The corresponding RSA OAEP encryption algorithm.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_RSA_OAEP(hash_alg) \
+ ((psa_algorithm_t)(0x07000300 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief The RSA PKCS#1 v1.5 message signature scheme, with hashing.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This signature scheme is defined by PKCS #1: RSA Cryptography Specifications Version 2.2
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.2 under the name
+ * RSASSA-PKCS1-v1_5.
+ *
+ * When used with @ref psa_sign_hash() or @ref psa_verify_hash(), the provided hash
+ * parameter is used as `H` from step 2 onwards in the message encoding algorithm
+ * EMSA-PKCS1-V1_5-ENCODE() in [RFC8017](https://tools.ietf.org/html/rfc8017.html) §9.2.
+ * `H` is usually the message digest, using the @c hash_alg hash algorithm.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR
+ * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only)
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true. This includes
+ * @ref PSA_ALG_ANY_HASH when specifying the algorithm in a key policy.
+ *
+ * @return The corresponding RSA PKCS#1 v1.5 signature algorithm.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_RSA_PKCS1V15_SIGN(hash_alg) \
+ ((psa_algorithm_t)(0x06000200 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief The RSA PSS message signature scheme, with hashing.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This algorithm is randomized: each invocation returns a different, equally valid
+ * signature.
+ *
+ * This is the signature scheme defined by
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.1 under the name RSASSA-PSS,
+ * with the following options:
+ * - The mask generation function is MGF1 defined by
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) Appendix B.
+ * - When creating a signature, the salt length is equal to the length of the hash, or
+ * the largest possible salt length for the algorithm and key size if that is smaller
+ * than the hash length.
+ * - When verifying a signature, the salt length must be equal to the length of the
+ * hash, or the largest possible salt length for the algorithm and key size if that is
+ * smaller than the hash length.
+ * - The specified hash algorithm is used to hash the input message, to create the
+ * salted hash, and for the mask generation.
+ *
+ * @note The @ref PSA_ALG_RSA_PSS_ANY_SALT() algorithm is equivalent to @ref PSA_ALG_RSA_PSS()
+ * when creating a signature, but permits any salt length when verifying a signature.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR
+ * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only)
+ */
+#define PSA_ALG_RSA_PSS(hash_alg) \
+ ((psa_algorithm_t)(0x06000300 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief The RSA PSS message signature scheme, with hashing. This variant permits any salt length
+ * for signature verification.
+ *
+ * @details This algorithm can be used with both the message and hash signature functions.
+ *
+ * This algorithm is randomized: each invocation returns a different, equally valid
+ * signature.
+ *
+ * This is the signature scheme defined by
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) §8.1 under the name RSASSA-PSS,
+ * with the following options:
+ * - The mask generation function is MGF1 defined by
+ * [RFC8017](https://tools.ietf.org/html/rfc8017.html) Appendix B.
+ * - When creating a signature, the salt length is equal to the length of the hash, or
+ * the largest possible salt length for the algorithm and key size if that is smaller
+ * than the hash length.
+ * - When verifying a signature, any salt length permitted by the RSASSA-PSS signature
+ * algorithm is accepted.
+ * - The specified hash algorithm is used to hash the input message, to create the
+ * salted hash, and for the mask generation.
+ *
+ * @note The @ref PSA_ALG_RSA_PSS() algorithm is equivalent to @ref PSA_ALG_RSA_PSS_ANY_SALT()
+ * when creating a signature, but is strict about the permitted salt length when verifying
+ * a signature.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_RSA_KEY_PAIR
+ * - @ref PSA_KEY_TYPE_RSA_PUBLIC_KEY (signature verification only)
+ */
+#define PSA_ALG_RSA_PSS_ANY_SALT(hash_alg) \
+ ((psa_algorithm_t)(0x06001300 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief Macro to build a TLS-1.2 PRF algorithm.
+ *
+ * @details TLS 1.2 uses a custom pseudorandom function (PRF) for key schedule, specified in
+ * The Transport Layer Security (TLS) Protocol Version 1.2
+ * [RFC5246](https://tools.ietf.org/html/rfc5246.html) §5. It is based on
+ * HMAC and can be used with either SHA-256 or SHA-384.
+ *
+ * This key derivation algorithm uses the following inputs, which must be passed in the
+ * order given here:
+ * - @ref PSA_KEY_DERIVATION_INPUT_SEED is the seed.
+ * - @ref PSA_KEY_DERIVATION_INPUT_SECRET is the secret key.
+ * - @ref PSA_KEY_DERIVATION_INPUT_LABEL is the label.
+ *
+ * Each input may only be passed once.
+ *
+ * For the application to TLS-1.2 key expansion:
+ * - The seed is the concatenation of @c ServerHello.Random + @c ClientHello.Random.
+ * - The label is `key expansion`.
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_DERIVE (for the secret key)
+ * - @ref PSA_KEY_TYPE_RAW_DATA (for the other inputs)
+ *
+ * @param hash_alg A hash algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_HASH(@p hash_alg) is true.
+ *
+ * @return The corresponding TLS-1.2 PRF algorithm. For example,
+ * @ref PSA_ALG_TLS12_PRF(@p PSA_ALG_SHA_256) represents the TLS 1.2 PRF using
+ * HMAC-SHA-256.
+ * Unspecified if @c hash_alg is not a supported hash algorithm.
+ */
+#define PSA_ALG_TLS12_PRF(hash_alg) \
+ ((psa_algorithm_t)(0x08000200 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief Macro to build a TLS-1.2 PSK-to-MasterSecret algorithm.
+ *
+ * @details In a pure-PSK handshake in TLS 1.2, the master secret (MS) is derived from the
+ * pre-shared key (PSK) through the application of padding (Pre-Shared Key Ciphersuites
+ * for Transport Layer Security (TLS) [RFC4279](https://tools.ietf.org/html/rfc4279.html)
+ * §2) and the TLS-1.2 PRF (The Transport Layer Security (TLS) Protocol Version 1.2
+ * [RFC5246](https://tools.ietf.org/html/rfc5246.html) §5). The latter is based on HMAC
+ * and can be used with either SHA-256 or SHA-384.
+ *
+ * This key derivation algorithm uses the following inputs, which must be passed in the
+ * order given here:
+ * - @ref PSA_KEY_DERIVATION_INPUT_SEED is the seed.
+ * - @ref PSA_KEY_DERIVATION_INPUT_SECRET is the PSK. The PSK must not be larger than
+ * @ref PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE.
+ * - @ref PSA_KEY_DERIVATION_INPUT_LABEL is the label.
+ *
+ * Each input may only be passed once.
+ *
+ * For the application to TLS-1.2:
+ * - The seed, which is forwarded to the TLS-1.2 PRF, is the concatenation of the
+ * @c ClientHello.Random + @c ServerHello.Random.
+ * - The label is "master secret" or "extended master secret".
+ *
+ * @b Compatible @b key @b types
+ * - @ref PSA_KEY_TYPE_DERIVE (for the PSK)
+ * - @ref PSA_KEY_TYPE_RAW_DATA (for the other inputs)
+ */
+#define PSA_ALG_TLS12_PSK_TO_MS(hash_alg) \
+ ((psa_algorithm_t)(0x08000300 | ((hash_alg) & 0x000000ff)))
+
+/**
+ * @brief Macro to build a truncated MAC algorithm.
+ *
+ * @details A truncated MAC algorithm is identical to the corresponding MAC algorithm except that
+ * the MAC value for the truncated algorithm consists of only the first mac_length bytes
+ * of the MAC value for the untruncated algorithm.
+ *
+ * @note This macro might allow constructing algorithm identifiers that are not valid, either
+ * because the specified length is larger than the untruncated MAC or because the
+ * specified length is smaller than permitted by the implementation.
+ *
+ * @note It is implementation-defined whether a truncated MAC that is truncated to the same
+ * length as the MAC of the untruncated algorithm is considered identical to the
+ * untruncated algorithm for policy comparison purposes.
+ *
+ * The untruncated MAC algorithm can be recovered using @ref PSA_ALG_FULL_LENGTH_MAC().
+ *
+ * @b Compatible @b key @b types
+ * The resulting truncated MAC algorithm is compatible with the same key types as the MAC
+ * algorithm used to construct it.
+ *
+ * @param mac_alg A MAC algorithm: a value of type @ref psa_algorithm_t such that
+ * @ref PSA_ALG_IS_MAC(@p mac_alg) is true. This can be a truncated or
+ * untruncated MAC algorithm.
+ * @param mac_length Desired length of the truncated MAC in bytes. This must be at most the
+ * untruncated length of the MAC and must be at least an
+ * implementation-specified minimum. The implementation-specified minimum must
+ * not be zero.
+ *
+ * @return The corresponding MAC algorithm with the specified length.
+ * Unspecified if @c mac_alg is not a supported MAC algorithm or if @c mac_length is too
+ * small or too large for the specified MAC algorithm.
+ */
+#define PSA_ALG_TRUNCATED_MAC(mac_alg, mac_length) \
+ ((psa_algorithm_t)(((mac_alg) & ~0x003f0000) | (((mac_length) & 0x3f) << 16)))
+
+/**
+ * @brief Finite-field Diffie-Hellman groups defined for TLS in RFC 7919.
+ *
+ * @details This family includes groups with the following key sizes (in bits): 2048, 3072, 4096,
+ * 6144, 8192. An implementation can support all of these sizes or only a subset.
+ *
+ * Keys is this group can only be used with the @ref PSA_ALG_FFDH key agreement algorithm.
+ *
+ * These groups are defined by Negotiated Finite Field Diffie-Hellman Ephemeral Parameters
+ * for Transport Layer Security (TLS) [RFC7919](https://tools.ietf.org/html/rfc7919.html)
+ * Appendix A.
+ */
+#define PSA_DH_FAMILY_RFC7919 ((psa_dh_family_t)0x03)
+
+/**
+ * @brief Brainpool `P` random curves.
+ *
+ * @details This family comprises the following curves:
+ * - `brainpoolP160r1` : @c key_bits = 160 (Deprecated)
+ * - `brainpoolP192r1` : @c key_bits = 192
+ * - `brainpoolP224r1` : @c key_bits = 224
+ * - `brainpoolP256r1` : @c key_bits = 256
+ * - `brainpoolP320r1` : @c key_bits = 320
+ * - `brainpoolP384r1` : @c key_bits = 384
+ * - `brainpoolP512r1` : @c key_bits = 512
+ *
+ * They are defined in Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and
+ * Curve Generation [RFC5639](https://tools.ietf.org/html/rfc5639.html).
+ *
+ * @warning The 160-bit curve `brainpoolP160r1` is weak and deprecated and is only recommended for
+ * use in legacy protocols.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_BRAINPOOL_P_R1 ((psa_ecc_family_t)0x30)
+
+/**
+ * @brief Curve used primarily in France and elsewhere in Europe.
+ *
+ * @details This family comprises one 256-bit curve:
+ * - `FRP256v1` : @c key_bits = 256
+ *
+ * This is defined by Publication d'un paramétrage de courbe elliptique visant des
+ * applications de passeport électronique et de l'administration électronique française
+ * [FRP](https://www.ssi.gouv.fr/agence/rayonnement-scientifique/
+ * publications-scientifiques/articles-ouvrages-actes).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_FRP ((psa_ecc_family_t)0x33)
+
+/**
+ * @brief Montgomery curves.
+ *
+ * @details This family comprises the following Montgomery curves:
+ * - `Curve25519` : @c key_bits = 255
+ * - `Curve448` : @c key_bits = 448
+ *
+ * `Curve25519` is defined in Curve25519: new Diffie-Hellman speed records
+ * [Curve25519](https://www.iacr.org/archive/pkc2006/39580209/39580209.pdf).
+ * `Curve448` is defined in Ed448-Goldilocks, a new elliptic curve
+ * [Curve448](https://eprint.iacr.org/2015/625.pdf).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_MONTGOMERY ((psa_ecc_family_t)0x41)
+
+/**
+ * @brief SEC Koblitz curves over prime fields.
+ *
+ * @details This family comprises the following curves:
+ * - `secp192k1` : @c key_bits = 192
+ * - `secp224k1` : @c key_bits = 225
+ * - `secp256k1` : @c key_bits = 256
+ *
+ * They are defined in SEC 2: Recommended Elliptic Curve Domain Parameters
+ * [SEC2](https://www.secg.org/sec2-v2.pdf).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_SECP_K1 ((psa_ecc_family_t)0x17)
+
+/**
+ * @brief SEC random curves over prime fields.
+ *
+ * @details This family comprises the following curves:
+ * - `secp192r1` : @c key_bits = 192
+ * - `secp224r1` : @c key_bits = 224
+ * - `secp256r1` : @c key_bits = 256
+ * - `secp384r1` : @c key_bits = 384
+ * - `secp521r1` : @c key_bits = 521
+ *
+ * They are defined in [SEC2](https://www.secg.org/sec2-v2.pdf).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_SECP_R1 ((psa_ecc_family_t)0x12)
+
+/**
+ * @warning This family of curves is weak and deprecated.
+ *
+ * @details This family comprises the following curves:
+ * - `secp160r2` : @c key_bits = 160 (Deprecated)
+ *
+ * It is defined in the superseded SEC 2: Recommended Elliptic Curve Domain Parameters,
+ * Version 1.0 [SEC2v1](https://www.secg.org/SEC2-Ver-1.0.pdf).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_SECP_R2 ((psa_ecc_family_t)0x1b)
+
+/**
+ * @brief SEC Koblitz curves over binary fields.
+ *
+ * @details This family comprises the following curves:
+ * - `sect163k1` : @c key_bits = 163 (Deprecated)
+ * - `sect233k1` : @c key_bits = 233
+ * - `sect239k1` : @c key_bits = 239
+ * - `sect283k1` : @c key_bits = 283
+ * - `sect409k1` : @c key_bits = 409
+ * - `sect571k1` : @c key_bits = 571
+ *
+ * They are defined in [SEC2](https://www.secg.org/sec2-v2.pdf).
+ *
+ * @warning The 163-bit curve `sect163k1` is weak and deprecated and is only recommended for use in
+ * legacy protocols.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_SECT_K1 ((psa_ecc_family_t)0x27)
+
+/**
+ * @brief SEC random curves over binary fields.
+ *
+ * @details This family comprises the following curves:
+ * - `sect163r1` : @c key_bits = 163 (Deprecated)
+ * - `sect233r1` : @c key_bits = 233
+ * - `sect283r1` : @c key_bits = 283
+ * - `sect409r1` : @c key_bits = 409
+ * - `sect571r1` : @c key_bits = 571
+ *
+ * They are defined in [SEC2](https://www.secg.org/sec2-v2.pdf).
+ *
+ * @warning The 163-bit curve `sect163r1` is weak and deprecated and is only recommended for use in
+ * legacy protocols.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_SECT_R1 ((psa_ecc_family_t)0x22)
+
+/**
+ * @brief SEC additional random curves over binary fields.
+ *
+ * @details This family comprises the following curves:
+ * - `sect163r2` : @c key_bits = 163 (Deprecated)
+ *
+ * It is defined in [SEC2](https://www.secg.org/sec2-v2.pdf).
+ *
+ * @warning The 163-bit curve `sect163r2` is weak and deprecated and is only recommended for use in
+ * legacy protocols.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_DETERMINISTIC_ECDSA
+ * - @ref PSA_ALG_ECDSA
+ * - @ref PSA_ALG_ECDSA_ANY
+ * - @ref PSA_ALG_ECDH (key pair only)
+ */
+#define PSA_ECC_FAMILY_SECT_R2 ((psa_ecc_family_t)0x2b)
+
+/**
+ * @brief Twisted Edwards curves.
+ *
+ * @details This family comprises the following twisted Edwards curves:
+ * - `Edwards25519` : @c key_bits = 255. This curve is birationally equivalent to
+ * `Curve25519`.
+ * - `Edwards448` : @c key_bits = 448. This curve is birationally equivalent to `Curve448`.
+ *
+ * Edwards25519 is defined in Twisted Edwards curves
+ * [Ed25519](https://eprint.iacr.org/2008/013.pdf). Edwards448 is defined in
+ * Ed448-Goldilocks, a new elliptic curve [Curve448](https://eprint.iacr.org/2015/625.pdf).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_PURE_EDDSA
+ * - @ref PSA_ALG_ED25519PH (Edwards25519 only)
+ * - @ref PSA_ALG_ED448PH (Edwards448 only)
+ */
+#define PSA_ECC_FAMILY_TWISTED_EDWARDS ((psa_ecc_family_t)0x42)
+
+/**
+ * @brief A context for key derivation.
+ *
+ * @details This is typically a direct input. It can also be a key of type
+ * @ref PSA_KEY_TYPE_RAW_DATA.
+ */
+#define PSA_KEY_DERIVATION_INPUT_CONTEXT /* implementation-defined value */
+
+/**
+ * @brief A cost parameter for password hashing or key stretching.
+ *
+ * @details This must be a direct input, passed to @ref psa_key_derivation_input_integer().
+ */
+#define PSA_KEY_DERIVATION_INPUT_COST /* implementation-defined value */
+
+/**
+ * @brief An information string for key derivation.
+ *
+ * @details This is typically a direct input. It can also be a key of type
+ * @ref PSA_KEY_TYPE_RAW_DATA.
+ */
+#define PSA_KEY_DERIVATION_INPUT_INFO /* implementation-defined value */
+
+/**
+ * @brief A label for key derivation.
+ *
+ * @details This is typically a direct input. It can also be a key of type
+ * @ref PSA_KEY_TYPE_RAW_DATA.
+ */
+#define PSA_KEY_DERIVATION_INPUT_LABEL /* implementation-defined value */
+
+/**
+ * @brief A low-entropy secret input for password hashing or key stretching.
+ *
+ * @details This is usually a key of type @ref PSA_KEY_TYPE_PASSWORD passed to
+ * @ref psa_key_derivation_input_key() or a direct input passed to
+ * @ref psa_key_derivation_input_bytes() that is a password or passphrase. It can also be
+ * high-entropy secret, for example, a key of type @ref PSA_KEY_TYPE_DERIVE, or the shared
+ * secret resulting from a key agreement.
+ *
+ * If the secret is a direct input, the derivation operation cannot be used to derive
+ * keys: the operation will not allow a call to @ref psa_key_derivation_output_key().
+ */
+#define PSA_KEY_DERIVATION_INPUT_PASSWORD /* implementation-defined value */
+
+/**
+ * @brief A salt for key derivation.
+ *
+ * @details This is typically a direct input. It can also be a key of type
+ * @ref PSA_KEY_TYPE_RAW_DATA or @ref PSA_KEY_TYPE_PEPPER.
+ */
+#define PSA_KEY_DERIVATION_INPUT_SALT /* implementation-defined value */
+
+/**
+ * @brief A high-entropy secret input for key derivation.
+ *
+ * @details This is typically a key of type @ref PSA_KEY_TYPE_DERIVE passed to
+ * @ref psa_key_derivation_input_key(), or the shared secret resulting from a key
+ * agreement obtained via @ref psa_key_derivation_key_agreement().
+ *
+ * The secret can also be a direct input passed to @ref psa_key_derivation_input_bytes().
+ * In this case, the derivation operation cannot be used to derive keys: the operation
+ * will not allow a call to @ref psa_key_derivation_output_key().
+ */
+#define PSA_KEY_DERIVATION_INPUT_SECRET /* implementation-defined value */
+
+/**
+ * @brief A seed for key derivation.
+ *
+ * @details This is typically a direct input. It can also be a key of type
+ * @ref PSA_KEY_TYPE_RAW_DATA.
+ */
+#define PSA_KEY_DERIVATION_INPUT_SEED /* implementation-defined value */
+
+/**
+ * @brief Use the maximum possible capacity for a key derivation operation.
+ *
+ * @details Use this value as the capacity argument when setting up a key derivation to specify
+ * that the operation will use the maximum possible capacity. The value of the maximum
+ * possible capacity depends on the key derivation algorithm.
+ */
+#define PSA_KEY_DERIVATION_UNLIMITED_CAPACITY \
+/* implementation-defined value */
+
+/**
+ * @brief The null key identifier.
+ *
+ * @details The null key identifier is always invalid, except when used without in a call to
+ * @ref psa_destroy_key() which will return @ref PSA_SUCCESS.
+ */
+#define PSA_KEY_ID_NULL ((psa_key_id_t)0)
+
+/**
+ * @brief The maximum value for a key identifier chosen by the application.
+ */
+#define PSA_KEY_ID_USER_MAX ((psa_key_id_t)0x3fffffff)
+
+/**
+ * @brief The minimum value for a key identifier chosen by the application.
+ */
+#define PSA_KEY_ID_USER_MIN ((psa_key_id_t)0x00000001)
+
+/**
+ * @brief The maximum value for a key identifier chosen by the implementation.
+ */
+#define PSA_KEY_ID_VENDOR_MAX ((psa_key_id_t)0x7fffffff)
+
+/**
+ * @brief The minimum value for a key identifier chosen by the implementation.
+ */
+#define PSA_KEY_ID_VENDOR_MIN ((psa_key_id_t)0x40000000)
+
+/**
+ * @brief Construct a lifetime from a persistence level and a location.
+ *
+ * @param persistence The persistence level: a value of type @ref psa_key_persistence_t.
+ * @param location The location indicator: a value of type @ref psa_key_location_t.
+ *
+ * @return The constructed lifetime value.
+ */
+#define PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location) \
+ ((location) << 8 | (persistence))
+
+/**
+ * @brief Extract the location indicator from a key lifetime.
+ *
+ * @param lifetime The lifetime value to query: a value of type @ref psa_key_lifetime_t.
+ */
+#define PSA_KEY_LIFETIME_GET_LOCATION(lifetime) \
+ ((psa_key_location_t)((lifetime) >> 8))
+
+/**
+ * @brief Extract the persistence level from a key lifetime.
+ *
+ * @param lifetime The lifetime value to query: a value of type @ref psa_key_lifetime_t.
+ */
+#define PSA_KEY_LIFETIME_GET_PERSISTENCE(lifetime) \
+ ((psa_key_persistence_t)((lifetime) & 0x000000ff))
+
+/**
+ * @brief Whether a key lifetime indicates that the key is volatile.
+ *
+ * A volatile key is automatically destroyed by the implementation when the application
+ * instance terminates. In particular, a volatile key is automatically destroyed on a
+ * power reset of the device.
+ *
+ * A key that is not volatile is persistent. Persistent keys are preserved until the
+ * application explicitly destroys them or until an implementation-specific device
+ * management event occurs, for example, a factory reset.
+ *
+ * @param lifetime The lifetime value to query: a value of type @ref psa_key_lifetime_t.
+ *
+ * @return 1 if the key is volatile, otherwise 0.
+ */
+#define PSA_KEY_LIFETIME_IS_VOLATILE(lifetime) \
+ (PSA_KEY_LIFETIME_GET_PERSISTENCE(lifetime) == PSA_KEY_PERSISTENCE_VOLATILE)
+
+/**
+ * @brief The default lifetime for persistent keys.
+ *
+ * @details A persistent key remains in storage until it is explicitly destroyed or until the
+ * corresponding storage area is wiped. This specification does not define any mechanism
+ * to wipe a storage area. Implementations are permitted to provide their own mechanism,
+ * for example, to perform a factory reset, to prepare for device refurbishment, or to
+ * uninstall an application.
+ *
+ * This lifetime value is the default storage area for the calling application.
+ * Implementations can offer other storage areas designated by other lifetime values as
+ * implementation-specific extensions.
+ */
+#define PSA_KEY_LIFETIME_PERSISTENT ((psa_key_lifetime_t)0x00000001)
+
+/**
+ * @brief The default lifetime for volatile keys.
+ *
+ * @details A volatile key only exists as long as its identifier is not destroyed. The key material
+ * is guaranteed to be erased on a power reset.
+ *
+ * A key with this lifetime is typically stored in the RAM area of the PSA Crypto
+ * subsystem. However this is an implementation choice. If an implementation stores data
+ * about the key in a non-volatile memory, it must release all the resources associated
+ * with the key and erase the key material if the calling application terminates.
+ */
+#define PSA_KEY_LIFETIME_VOLATILE ((psa_key_lifetime_t)0x00000000)
+
+/**
+ * @brief The local storage area for persistent keys.
+ *
+ * @details This storage area is available on all systems that can store persistent keys without
+ * delegating the storage to a third-party cryptoprocessor.
+ *
+ * See @ref psa_key_location_t for more information.
+ */
+#define PSA_KEY_LOCATION_LOCAL_STORAGE ((psa_key_location_t)0x000000)
+
+/**
+ * @brief The default secure element storage area for persistent keys.
+ *
+ * @details This storage location is available on systems that have one or more secure elements
+ * that are able to store keys.
+ *
+ * Vendor-defined locations must be provided by the system for storing keys in additional
+ * secure elements.
+ *
+ * See @ref psa_key_location_t for more information.
+ */
+#define PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT ((psa_key_location_t)0x000001)
+
+/**
+ * @brief Mark vendor defined key locations
+ */
+#define PSA_KEY_LOCATION_VENDOR_FLAG ((psa_key_location_t)0x800000)
+
+/**
+ * @brief Minimum location value for secure elements
+ */
+#define PSA_KEY_LOCATION_SE_MIN (PSA_KEY_LOCATION_VENDOR_FLAG)
+
+/**
+ * @brief Maximum location value for secure elements
+ */
+#define PSA_KEY_LOCATION_SE_MAX ((psa_key_location_t)0x8000ff)
+
+/**
+ * @brief The default persistence level for persistent keys.
+ *
+ * @details See @ref psa_key_persistence_t for more information.
+ */
+#define PSA_KEY_PERSISTENCE_DEFAULT ((psa_key_persistence_t)0x01)
+
+/**
+ * @brief A persistence level indicating that a key is never destroyed.
+ *
+ * @details See @ref psa_key_persistence_t for more information.
+ */
+#define PSA_KEY_PERSISTENCE_READ_ONLY ((psa_key_persistence_t)0xff)
+
+/**
+ * @brief The persistence level of volatile keys.
+ *
+ * @details See @ref psa_key_persistence_t for more information.
+ */
+#define PSA_KEY_PERSISTENCE_VOLATILE ((psa_key_persistence_t)0x00)
+
+/**
+ * @brief Vendor-defined key type flag.
+ *
+ * @details Key types defined by this standard will never have the
+ * @ref PSA_KEY_TYPE_VENDOR_FLAG bit set. Vendors who define additional key types
+ * must use an encoding with the @ref PSA_KEY_TYPE_VENDOR_FLAG bit set and should
+ * respect the bitwise structure used by standard encodings whenever practical.
+ */
+#define PSA_KEY_TYPE_VENDOR_FLAG ((psa_key_type_t)0x8000)
+
+/**
+ * @brief Mask for key type categories
+ */
+#define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x7000)
+
+/**
+ * @brief Raw key data type
+ */
+#define PSA_KEY_TYPE_CATEGORY_RAW ((psa_key_type_t)0x1000)
+
+/**
+ * @brief Symmetric key type
+ */
+#define PSA_KEY_TYPE_CATEGORY_SYMMETRIC ((psa_key_type_t)0x2000)
+
+/**
+ * @brief Asymmetric public key type
+ */
+#define PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY ((psa_key_type_t)0x4000)
+
+/**
+ * @brief Asymmetric key pair type
+ */
+#define PSA_KEY_TYPE_CATEGORY_KEY_PAIR ((psa_key_type_t)0x7000)
+
+/**
+ * @brief Asymmetric key pair flag
+ */
+#define PSA_KEY_TYPE_CATEGORY_FLAG_PAIR ((psa_key_type_t)0x3000)
+
+/**
+ * @brief Key for a cipher, AEAD or MAC algorithm based on the AES block cipher.
+ *
+ * @details The size of the key is related to the AES algorithm variant. For algorithms except the
+ * XTS block cipher mode, the following key sizes are used:
+ * - AES-128 uses a 16-byte key : @c key_bits = 128
+ * - AES-192 uses a 24-byte key : @c key_bits = 192
+ * - AES-256 uses a 32-byte key : @c key_bits = 256
+ *
+ * For the XTS block cipher mode (@ref PSA_ALG_XTS), the following key sizes are used:
+ * - AES-128-XTS uses two 16-byte keys : @c key_bits = 256
+ * - AES-192-XTS uses two 24-byte keys : @c key_bits = 384
+ * - AES-256-XTS uses two 32-byte keys : @c key_bits = 512
+ *
+ * The AES block cipher is defined in FIPS Publication 197: Advanced Encryption Standard
+ * (AES) [FIPS197](https://doi.org/10.6028/NIST.FIPS.197).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_CBC_MAC
+ * - @ref PSA_ALG_CMAC
+ * - @ref PSA_ALG_CTR
+ * - @ref PSA_ALG_CFB
+ * - @ref PSA_ALG_OFB
+ * - @ref PSA_ALG_XTS
+ * - @ref PSA_ALG_CBC_NO_PADDING
+ * - @ref PSA_ALG_CBC_PKCS7
+ * - @ref PSA_ALG_ECB_NO_PADDING
+ * - @ref PSA_ALG_CCM
+ * - @ref PSA_ALG_GCM
+ */
+#define PSA_KEY_TYPE_AES ((psa_key_type_t)0x2400)
+
+/**
+ * @brief Key for the ARC4 stream cipher.
+ *
+ * @warning The ARC4 cipher is weak and deprecated and is only recommended for use in legacy
+ * protocols.
+ *
+ * @details The ARC4 cipher supports key sizes between 40 and 2048 bits, that are multiples of 8.
+ * (5 to 256 bytes)
+ *
+ * Use algorithm @ref PSA_ALG_STREAM_CIPHER to use this key with the ARC4 cipher.
+ */
+#define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x2002)
+
+/**
+ * @brief Key for a cipher, AEAD or MAC algorithm based on the ARIA block cipher.
+ *
+ * The size of the key is related to the ARIA algorithm variant. For algorithms except the
+ * XTS block cipher mode, the following key sizes are used:
+ * - ARIA-128 uses a 16-byte key : @c key_bits = 128
+ * - ARIA-192 uses a 24-byte key : @c key_bits = 192
+ * - ARIA-256 uses a 32-byte key : @c key_bits = 256
+ *
+ * For the XTS block cipher mode (@ref PSA_ALG_XTS), the following key sizes are used:
+ * - ARIA-128-XTS uses two 16-byte keys : @c key_bits = 256
+ * - ARIA-192-XTS uses two 24-byte keys : @c key_bits = 384
+ * - ARIA-256-XTS uses two 32-byte keys : @c key_bits = 512
+ *
+ * The ARIA block cipher is defined in A Description of the ARIA Encryption Algorithm
+ * [RFC5794](https://datatracker.ietf.org/doc/html/rfc5794).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_CBC_MAC
+ * - @ref PSA_ALG_CMAC
+ * - @ref PSA_ALG_CTR
+ * - @ref PSA_ALG_CFB
+ * - @ref PSA_ALG_OFB
+ * - @ref PSA_ALG_XTS
+ * - @ref PSA_ALG_CBC_NO_PADDING
+ * - @ref PSA_ALG_CBC_PKCS7
+ * - @ref PSA_ALG_ECB_NO_PADDING
+ * - @ref PSA_ALG_CCM
+ * - @ref PSA_ALG_GCM
+ */
+#define PSA_KEY_TYPE_ARIA ((psa_key_type_t)0x2406)
+
+/**
+ * @brief Key for a cipher, AEAD or MAC algorithm based on the Camellia block cipher.
+ *
+ * @details The size of the key is related to the Camellia algorithm variant. For algorithms except
+ * the XTS block cipher mode, the following key sizes are used:
+ * - Camellia-128 uses a 16-byte key : @c key_bits = 128
+ * - Camellia-192 uses a 24-byte key : @c key_bits = 192
+ * - Camellia-256 uses a 32-byte key : @c key_bits = 256
+ *
+ * For the XTS block cipher mode (@ref PSA_ALG_XTS), the following key sizes are used:
+ * - Camellia-128-XTS uses two 16-byte keys : @c key_bits = 256
+ * - Camellia-192-XTS uses two 24-byte keys : @c key_bits = 384
+ * - Camellia-256-XTS uses two 32-byte keys : @c key_bits = 512
+ *
+ * The Camellia block cipher is defined in Specification of Camellia — a 128-bit Block
+ * Cipher [NTT-CAM](https://info.isl.ntt.co.jp/crypt/eng/camellia/specifications) and
+ * also described in A Description of the Camellia Encryption
+ * Algorithm [RFC3713](https://tools.ietf.org/html/rfc3713).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_CBC_MAC
+ * - @ref PSA_ALG_CMAC
+ * - @ref PSA_ALG_CTR
+ * - @ref PSA_ALG_CFB
+ * - @ref PSA_ALG_OFB
+ * - @ref PSA_ALG_XTS
+ * - @ref PSA_ALG_CBC_NO_PADDING
+ * - @ref PSA_ALG_CBC_PKCS7
+ * - @ref PSA_ALG_ECB_NO_PADDING
+ * - @ref PSA_ALG_CCM
+ * - @ref PSA_ALG_GCM
+ */
+#define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x2403)
+
+/**
+ * @brief Key for the ChaCha20 stream cipher or the ChaCha20-Poly1305 AEAD algorithm.
+ *
+ * @details The ChaCha20 key size is 256 bits (32 bytes).
+ * - Use algorithm @ref PSA_ALG_STREAM_CIPHER to use this key with the ChaCha20 cipher for
+ * unauthenticated encryption. See @ref PSA_ALG_STREAM_CIPHER for details of this
+ * algorithm.
+ * - Use algorithm @ref PSA_ALG_CHACHA20_POLY1305 to use this key with the ChaCha20 cipher
+ * and Poly1305 authenticator for AEAD. See @ref PSA_ALG_CHACHA20_POLY1305 for details
+ * of this algorithm.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_STREAM_CIPHER
+ * - @ref PSA_ALG_CHACHA20_POLY1305
+ */
+#define PSA_KEY_TYPE_CHACHA20 ((psa_key_type_t)0x2004)
+
+/**
+ * @brief A secret for key derivation.
+ *
+ * @details This key type is for high-entropy secrets only. For low-entropy secrets,
+ * @ref PSA_KEY_TYPE_PASSWORD should be used instead.
+ *
+ * These keys can be used in the @ref PSA_KEY_DERIVATION_INPUT_SECRET or
+ * @ref PSA_KEY_DERIVATION_INPUT_PASSWORD input step of key derivation algorithms.
+ *
+ * The key policy determines which key derivation algorithm the key can be used for.
+ *
+ * The bit size of a secret for key derivation must be a non-zero multiple of 8. The
+ * maximum size of a secret for key derivation is implementation defined.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_HKDF (secret input)
+ * - @ref PSA_ALG_TLS12_PRF (secret input)
+ * - @ref PSA_ALG_TLS12_PSK_TO_MS (secret input)
+ */
+#define PSA_KEY_TYPE_DERIVE ((psa_key_type_t)0x1200)
+
+/**
+ * @brief Key for a cipher or MAC algorithm based on DES or 3DES (Triple-DES).
+ *
+ * @details The size of the key determines which DES algorithm is used:
+ * - Single DES uses an 8-byte key : @c key_bits = 64
+ * - 2-key 3DES uses a 16-byte key : @c key_bits = 128
+ * - 3-key 3DES uses a 24-byte key : @c key_bits = 192
+ *
+ * @warning Single DES and 2-key 3DES are weak and strongly deprecated and are only recommended for
+ * decrypting legacy data.
+ * 3-key 3DES is weak and deprecated and is only recommended for use in legacy protocols.
+ *
+ * The DES and 3DES block ciphers are defined in NIST Special Publication 800-67:
+ * Recommendation for the Triple Data Encryption Algorithm (TDEA) Block Cipher
+ * [SP800-67](https://doi.org/10.6028/NIST.SP.800-67r2).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_CBC_MAC
+ * - @ref PSA_ALG_CMAC
+ * - @ref PSA_ALG_CTR
+ * - @ref PSA_ALG_CFB
+ * - @ref PSA_ALG_OFB
+ * - @ref PSA_ALG_XTS
+ * - @ref PSA_ALG_CBC_NO_PADDING
+ * - @ref PSA_ALG_CBC_PKCS7
+ * - @ref PSA_ALG_ECB_NO_PADDING
+ */
+#define PSA_KEY_TYPE_DES ((psa_key_type_t)0x2301)
+
+/**
+ * @brief Extract the group family from a Diffie-Hellman key type.
+ *
+ * @param type A Diffie-Hellman key type: a value of type @ref psa_key_type_t such that
+ * @ref PSA_KEY_TYPE_IS_DH(@p type) is true.
+ *
+ * @return The Diffie-Hellman group family id, if type is a supported Diffie-Hellman key.
+ * Unspecified if type is not a supported Diffie-Hellman key.
+ */
+#define PSA_KEY_TYPE_DH_GET_FAMILY(type) \
+ ((psa_dh_family_t)((type) & 0x00ff))
+
+/**
+ * @brief Finite-field Diffie-Hellman key pair: both the private key and public key.
+ *
+ * @details @b Compatible @b algorithms
+ * - @ref PSA_ALG_FFDH
+ *
+ * @param group A value of type @ref psa_dh_family_t that identifies the Diffie-Hellman group
+ * family to be used.
+ */
+#define PSA_KEY_TYPE_DH_KEY_PAIR(group) \
+ ((psa_key_type_t)(0x7200 | (group)))
+
+/**
+ * @brief Finite-field Diffie-Hellman public key.
+ *
+ * @details @b Compatible @b algorithms
+ * None. Finite-field Diffie-Hellman public keys are exported to use in a key agreement
+ * algorithm, and the peer key is provided to the @ref PSA_ALG_FFDH key agreement
+ * algorithm as a buffer of key data.
+ *
+ * @param group A value of type @ref psa_dh_family_t that identifies the Diffie-Hellman group
+ * family to be used.
+ */
+#define PSA_KEY_TYPE_DH_PUBLIC_KEY(group) \
+ ((psa_key_type_t)(0x4200 | (group)))
+
+/**
+ * @brief Extract the curve family from an elliptic curve key type.
+ *
+ * @param type An elliptic curve key type: a value of type @ref psa_key_type_t such that
+ * @ref PSA_KEY_TYPE_IS_ECC(@p type) is true.
+ *
+ * @return The elliptic curve family id, if type is a supported elliptic curve key.
+ * Unspecified if type is not a supported elliptic curve key.
+ */
+#define PSA_KEY_TYPE_ECC_GET_FAMILY(type) \
+ ((psa_ecc_family_t)((type) & 0x00ff))
+
+/**
+ * @brief Base value for ECC public keys
+ */
+#define PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE ((psa_key_type_t)0x4100)
+
+/**
+ * @brief Base value for ECC key pairs
+ */
+#define PSA_KEY_TYPE_ECC_KEY_PAIR_BASE ((psa_key_type_t)0x7100)
+
+/**
+ * @brief Mask for ECC curves
+ */
+#define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x00ff)
+
+/**
+ * @brief Elliptic curve key pair: both the private and public key.
+ *
+ * @details The size of an elliptic curve key is the bit size associated with the curve, that is,
+ * the bit size of q for a curve over a field Fq. See the documentation of each Elliptic
+ * curve family for details.
+ *
+ * @b Compatible @b algorithms
+ * - Elliptic curve key pairs can be used in Asymmetric signature and Key agreement
+ * algorithms.
+ * - The set of compatible algorithms depends on the Elliptic curve key family. See the
+ * Elliptic curve family for details.
+ *
+ * @param curve A value of type @ref psa_ecc_family_t that identifies the ECC curve to be used.
+ */
+#define PSA_KEY_TYPE_ECC_KEY_PAIR(curve) \
+ (PSA_KEY_TYPE_ECC_KEY_PAIR_BASE | (curve))
+
+/**
+ * @brief Extract group family of an elliptic curve key pair
+ *
+ * @param type A an ECC key pair type: a value of type @ref psa_key_type_t such that
+ * @ref PSA_KEY_TYPE_IS_ECC(@p type) is true.
+ *
+ * @return The elliptic curve family id, if type is a supported elliptic curve key.
+ * Unspecified if type is not a supported elliptic curve key.
+ */
+#define PSA_KEY_TYPE_ECC_GET_CURVE(type) \
+ (type & ~PSA_KEY_TYPE_ECC_KEY_PAIR_BASE)
+
+/**
+ * @brief Elliptic curve public key.
+ *
+ * @details The size of an elliptic curve public key is the same as the corresponding private key.
+ * See @ref PSA_KEY_TYPE_ECC_KEY_PAIR() and the documentation of each Elliptic curve
+ * family for details.
+ *
+ * @b Compatible @b algorithms
+ * Elliptic curve public keys can be used for verification in asymmetric signature
+ * algorithms.
+ * The set of compatible algorithms depends on the elliptic curve key family. See each
+ * elliptic curve family for details.
+ *
+ * @param curve A value of type @ref psa_ecc_family_t that identifies the ECC curve to be used.
+ */
+#define PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) \
+ (PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE | (curve))
+
+/**
+ * @brief Elliptic curve public key.
+ */
+#define PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) \
+ (PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE | (curve))
+
+/**
+ * @brief Whether a key type is an elliptic curve key, either a key pair or a public key.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_ECC(type) \
+ ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) & 0xff00) == 0x4100)
+
+/**
+ * @brief Whether a key type is an elliptic curve key pair.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type) \
+ (((type) & 0xff00) == 0x7100)
+
+/**
+ * @brief Whether a key type is an elliptic curve public key.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(type) \
+ (((type) & 0xff00) == 0x4100)
+
+/**
+ * @brief The public key type corresponding to a key pair type.
+ * You may also pass a key pair type as type, it will be left unchanged.
+ *
+ * @param type A public key type or key pair type.
+ *
+ * @return The corresponding public key type.
+ * If type is not a public key or a key pair, the return value is undefined.
+ */
+#define PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) \
+ ((psa_key_type_t)((type) & ~0x3000))
+
+/**
+ * @brief HMAC key.
+ *
+ * @details The key policy determines which underlying hash algorithm the key can be used for.
+ *
+ * The bit size of an HMAC key must be a non-zero multiple of 8. An HMAC key is typically
+ * the same size as the output of the underlying hash algorithm. An HMAC key that is
+ * longer than the block size of the underlying hash algorithm will be hashed before use.
+ *
+ * When an HMAC key is created that is longer than the block size, it is implementation
+ * defined whether the implementation stores the original HMAC key, or the hash of the
+ * HMAC key. If the hash of the key is stored, the key size reported by
+ * @ref psa_get_key_attributes() will be the size of the hashed key.
+ *
+ * @note @ref PSA_HASH_LENGTH(@p alg) provides the output size of hash algorithm @c alg,
+ * in bytes.
+ * @ref PSA_HASH_BLOCK_LENGTH(@p alg) provides the block size of hash algorithm
+ * @c alg, in bytes.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_HMAC
+ */
+#define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x1100)
+
+/**
+ * @brief Whether a key type is asymmetric: either a key pair or a public key.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \
+ (((type) & 0x4000) == 0x4000)
+
+/**
+ * @brief Whether a key type is a Diffie-Hellman key, either a key pair or a public key.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_DH(type) \
+ ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) & 0xff00) == 0x4200)
+
+/**
+ * @brief Whether a key type is a Diffie-Hellman key pair.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_DH_KEY_PAIR(type) \
+ (((type) & 0xff00) == 0x7200)
+
+/**
+ * @brief Whether a key type is a Diffie-Hellman public key.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(type) \
+ (((type) & 0xff00) == 0x4200)
+
+/**
+ * @brief Whether a key type is a key pair containing a private part and a public part.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_KEY_PAIR(type) \
+ (((type) & 0x7000) == 0x7000)
+
+/**
+ * @brief Whether a key type is the public part of a key pair.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+
+#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \
+ (((type) & 0x7000) == 0x4000)
+
+/**
+ * @brief Whether a key type is an RSA key. This includes both key pairs and public keys.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_RSA(type) \
+ (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) == 0x4001)
+
+/**
+ * @brief Whether a key type is an unstructured array of bytes.
+ * This encompasses both symmetric keys and non-key data.
+ *
+ * @param type A key type: a value of type @ref psa_key_type_t.
+ */
+#define PSA_KEY_TYPE_IS_UNSTRUCTURED(type) \
+ (((type) & 0x7000) == 0x1000 || ((type) & 0x7000) == 0x2000)
+
+/**
+ * @brief The key pair type corresponding to a public key type.
+ *
+ * @details If type is a key pair type, it will be left unchanged.
+ *
+ * @param type A public key type or key pair type.
+ *
+ * @return The corresponding key pair type. If type is not a public key or a key pair, the return
+ * value is undefined.
+ */
+#define PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(type) \
+ ((psa_key_type_t)((type) | 0x3000))
+
+/**
+ * @brief An invalid key type value.
+ *
+ * @details Zero is not the encoding of any key type.
+ */
+#define PSA_KEY_TYPE_NONE ((psa_key_type_t)0x0000)
+
+/**
+ * @brief A low-entropy secret for password hashing or key derivation.
+ *
+ * @details This key type is suitable for passwords and passphrases which are typically intended to
+ * be memorizable by humans, and have a low entropy relative to their size. It can be used
+ * for randomly generated or derived keys with maximum or near-maximum entropy, but
+ * @ref PSA_KEY_TYPE_DERIVE is more suitable for such keys. It is not suitable for
+ * passwords with extremely low entropy, such as numerical PINs.
+ *
+ * These keys can be used in the @ref PSA_KEY_DERIVATION_INPUT_PASSWORD input step of key
+ * derivation algorithms. Algorithms that accept such an input were designed to accept
+ * low-entropy secret and are known as password hashing or key stretching algorithms.
+ *
+ * These keys cannot be used in the @ref PSA_KEY_DERIVATION_INPUT_SECRET input step of key
+ * derivation algorithms, as the algorithms expect such an input to have high entropy.
+ *
+ * The key policy determines which key derivation algorithm the key can be used for, among
+ * the permissible subset defined above.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_PBKDF2_HMAC() (password input)
+ * - @ref PSA_ALG_PBKDF2_AES_CMAC_PRF_128 (password input)
+ */
+#define PSA_KEY_TYPE_PASSWORD ((psa_key_type_t)0x1203)
+
+/**
+ * @brief A secret value that can be used to verify a password hash.
+ *
+ * @details The key policy determines which key derivation algorithm the key can be used for, among
+ * the same permissible subset as for @ref PSA_KEY_TYPE_PASSWORD.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_PBKDF2_HMAC() (key output and verification)
+ * - @ref PSA_ALG_PBKDF2_AES_CMAC_PRF_128 (key output and verification)
+ */
+#define PSA_KEY_TYPE_PASSWORD_HASH ((psa_key_type_t)0x1205)
+
+/**
+ * @brief A secret value that can be used when computing a password hash.
+ *
+ * @details The key policy determines which key derivation algorithm the key can be used for, among
+ * the subset of algorithms that can use pepper.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_PBKDF2_HMAC() (salt input)
+ * - @ref PSA_ALG_PBKDF2_AES_CMAC_PRF_128 (salt input)
+ */
+#define PSA_KEY_TYPE_PEPPER ((psa_key_type_t)0x1206)
+
+/**
+ * @brief Raw data.
+ *
+ * @details A “key” of this type cannot be used for any cryptographic operation. Applications can
+ * use this type to store arbitrary data in the keystore.
+ *
+ * The bit size of a raw key must be a non-zero multiple of 8. The maximum size of a raw
+ * key is implementation defined.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_HKDF (non-secret inputs)
+ * - @ref PSA_ALG_TLS12_PRF (non-secret inputs)
+ * - @ref PSA_ALG_TLS12_PSK_TO_MS (non-secret inputs)
+ */
+#define PSA_KEY_TYPE_RAW_DATA ((psa_key_type_t)0x1001)
+
+/**
+ * @brief RSA key pair: both the private and public key.
+ *
+ * @details The size of an RSA key is the bit size of the modulus.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_RSA_OAEP
+ * - @ref PSA_ALG_RSA_PKCS1V15_CRYPT
+ * - @ref PSA_ALG_RSA_PKCS1V15_SIGN
+ * - @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW
+ * - @ref PSA_ALG_RSA_PSS
+ * - @ref PSA_ALG_RSA_PSS_ANY_SALT
+ */
+#define PSA_KEY_TYPE_RSA_KEY_PAIR ((psa_key_type_t)0x7001)
+
+/**
+ * @brief RSA public key.
+ *
+ * @details The size of an RSA key is the bit size of the modulus.
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_RSA_OAEP (encryption only)
+ * - @ref PSA_ALG_RSA_PKCS1V15_CRYPT (encryption only)
+ * - @ref PSA_ALG_RSA_PKCS1V15_SIGN (signature verification only)
+ * - @ref PSA_ALG_RSA_PKCS1V15_SIGN_RAW (signature verification only)
+ * - @ref PSA_ALG_RSA_PSS (signature verification only)
+ * - @ref PSA_ALG_RSA_PSS_ANY_SALT (signature verification only)
+ */
+#define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x4001)
+
+/**
+ * @brief Key for a cipher, AEAD or MAC algorithm based on the SM4 block cipher.
+ *
+ * @details For algorithms except the XTS block cipher mode, the SM4 key size is 128 bits
+ * (16 bytes).
+ *
+ * For the XTS block cipher mode (@ref PSA_ALG_XTS), the SM4 key size is 256 bits
+ * (two 16-byte keys).
+ *
+ * The SM4 block cipher is defined in GM/T 0002-2012: SM4 block cipher algorithm
+ * [CSTC0002](http://www.gmbz.org.cn/main/viewfile/20180108015408199368.html)
+ * (English version [CSTC0002/E](http://www.gmbz.org.cn/main/postDetail.html?
+ * id=20180404044052)).
+ *
+ * @b Compatible @b algorithms
+ * - @ref PSA_ALG_CBC_MAC
+ * - @ref PSA_ALG_CMAC
+ * - @ref PSA_ALG_CTR
+ * - @ref PSA_ALG_CFB
+ * - @ref PSA_ALG_OFB
+ * - @ref PSA_ALG_XTS
+ * - @ref PSA_ALG_CBC_NO_PADDING
+ * - @ref PSA_ALG_CBC_PKCS7
+ * - @ref PSA_ALG_ECB_NO_PADDING
+ * - @ref PSA_ALG_CCM
+ * - @ref PSA_ALG_GCM
+ */
+#define PSA_KEY_TYPE_SM4 ((psa_key_type_t)0x2405)
+
+/**
+ * @brief Permission for the implementation to cache the key.
+ *
+ * @details This flag allows the implementation to make additional copies of the key material that
+ * are not in storage and not for the purpose of an ongoing operation. Applications can
+ * use it as a hint to keep the key around for repeated access.
+ *
+ * An application can request that cached key material is removed from memory by calling
+ * @ref psa_purge_key().
+ *
+ * The presence of this usage flag when creating a key is a hint:
+ * - An implementation is not required to cache keys that have this usage flag.
+ * - An implementation must not report an error if it does not cache keys.
+ *
+ * If this usage flag is not present, the implementation must ensure key material is
+ * removed from memory as soon as it is not required for an operation or for maintenance
+ * of a volatile key.
+ *
+ * This flag must be preserved when reading back the attributes for all keys, regardless
+ * of key type or implementation behavior.
+ */
+#define PSA_KEY_USAGE_CACHE ((psa_key_usage_t)0x00000004)
+
+/**
+ * @brief Permission to copy the key.
+ *
+ * @details This flag allows the use of @ref psa_copy_key() to make a copy of the key with the same
+ * policy or a more restrictive policy.
+ *
+ * For lifetimes for which the key is located in a secure element which enforce the
+ * non-exportability of keys, copying a key outside the secure element also requires the
+ * usage flag @ref PSA_KEY_USAGE_EXPORT. Copying the key inside the secure element is
+ * permitted with just @ref PSA_KEY_USAGE_COPY if the secure element supports it. For keys
+ * with the lifetime @ref PSA_KEY_LIFETIME_VOLATILE or @ref PSA_KEY_LIFETIME_PERSISTENT,
+ * the usage flag @ref PSA_KEY_USAGE_COPY is sufficient to permit the copy.
+ */
+#define PSA_KEY_USAGE_COPY ((psa_key_usage_t)0x00000002)
+
+/**
+ * @brief Permission to decrypt a message with the key.
+ *
+ * @details This flag allows the key to be used for a symmetric decryption operation, for an AEAD
+ * decryption-and-verification operation, or for an asymmetric decryption operation, if
+ * otherwise permitted by the key’s type and policy. The flag must be present on keys used
+ * with the following APIs:
+ * - @ref psa_cipher_decrypt()
+ * - @ref psa_cipher_decrypt_setup()
+ * - @ref psa_aead_decrypt()
+ * - @ref psa_aead_decrypt_setup()
+ * - @ref psa_asymmetric_decrypt()
+ *
+ * For a key pair, this concerns the private key.
+ */
+#define PSA_KEY_USAGE_DECRYPT ((psa_key_usage_t)0x00000200)
+
+/**
+ * @brief Permission to derive other keys or produce a password hash from this key.
+ *
+ * @details This flag allows the key to be used for a key derivation operation or for a key
+ * agreement operation, if otherwise permitted by the key’s type and policy.
+ *
+ * This flag must be present on keys used with the following APIs:
+ * - @ref psa_key_derivation_key_agreement()
+ * - @ref psa_raw_key_agreement()
+ *
+ * If this flag is present on all keys used in calls to
+ * @ref psa_key_derivation_input_key() for a key derivation operation, then it permits
+ * calling @ref psa_key_derivation_output_bytes() or @ref psa_key_derivation_output_key()
+ * at the end of the operation.
+ */
+#define PSA_KEY_USAGE_DERIVE ((psa_key_usage_t)0x00004000)
+
+/**
+ * @brief Permission to encrypt a message with the key.
+ *
+ * @details This flag allows the key to be used for a symmetric encryption operation, for an AEAD
+ * encryption-and-authentication operation, or for an asymmetric encryption operation, if
+ * otherwise permitted by the key’s type and policy. The flag must be present on keys used
+ * with the following APIs:
+ * - @ref psa_cipher_encrypt()
+ * - @ref psa_cipher_encrypt_setup()
+ * - @ref psa_aead_encrypt()
+ * - @ref psa_aead_encrypt_setup()
+ * - @ref psa_asymmetric_encrypt()
+ *
+ * For a key pair, this concerns the public key.
+ */
+#define PSA_KEY_USAGE_ENCRYPT ((psa_key_usage_t)0x00000100)
+
+/**
+ * @brief Permission to export the key.
+ *
+ * @details This flag allows the use of @ref psa_export_key() to export a key from the
+ * cryptoprocessor. A public key or the public part of a key pair can always be exported
+ * regardless of the value of this permission flag.
+ *
+ * This flag can also be required to copy a key using @ref psa_copy_key() outside of a
+ * secure element. See also @ref PSA_KEY_USAGE_COPY.
+ *
+ * If a key does not have export permission, implementations must not allow the key to be
+ * exported in plain form from the cryptoprocessor, whether through @ref psa_export_key()
+ * or through a proprietary interface. The key might still be exportable in a wrapped
+ * form, i.e. in a form where it is encrypted by another key.
+ */
+#define PSA_KEY_USAGE_EXPORT ((psa_key_usage_t)0x00000001)
+
+/**
+ * @brief Permission to sign a message hash with the key.
+ *
+ * @details This flag allows the key to be used to sign a message hash as part of an asymmetric
+ * signature operation, if otherwise permitted by the key’s type and policy. The flag must
+ * be present on keys used when calling @ref psa_sign_hash().
+ *
+ * This flag automatically sets @ref PSA_KEY_USAGE_SIGN_MESSAGE : if an application sets
+ * the flag @ref PSA_KEY_USAGE_SIGN_HASH when creating a key, then the key always has the
+ * permissions conveyed by @ref PSA_KEY_USAGE_SIGN_MESSAGE, and the flag
+ * @ref PSA_KEY_USAGE_SIGN_MESSAGE will also be present when the application queries the
+ * usage flags of the key.
+ *
+ * For a key pair, this concerns the private key.
+ */
+#define PSA_KEY_USAGE_SIGN_HASH ((psa_key_usage_t)0x00001000)
+
+/**
+ * @brief Permission to sign a message with the key.
+ *
+ * @details This flag allows the key to be used for a MAC calculation operation or for an
+ * asymmetric message signature operation, if otherwise permitted by the key’s type and
+ * policy. The flag must be present on keys used with the following APIs:
+ * - @ref psa_mac_compute()
+ * - @ref psa_mac_sign_setup()
+ * - @ref psa_sign_message()
+ *
+ * For a key pair, this concerns the private key.
+ */
+#define PSA_KEY_USAGE_SIGN_MESSAGE ((psa_key_usage_t)0x00000400)
+
+/**
+ * @brief Permission to verify the result of a key derivation, including password hashing.
+ *
+ * @details This flag allows the key to be used in a key derivation operation, if otherwise
+ * permitted by the key’s type and policy.
+ *
+ * This flag must be present on keys used with @ref psa_key_derivation_verify_key().
+ *
+ * If this flag is present on all keys used in calls to
+ * @ref psa_key_derivation_input_key() for a key derivation operation, then it permits
+ * calling @ref psa_key_derivation_verify_bytes() or @ref psa_key_derivation_verify_key()
+ * at the end of the operation.
+ */
+#define PSA_KEY_USAGE_VERIFY_DERIVATION ((psa_key_usage_t)0x00008000)
+
+/**
+ * @brief Permission to verify a message hash with the key.
+ *
+ * @details This flag allows the key to be used to verify a message hash as part of an asymmetric
+ * signature verification operation, if otherwise permitted by the key’s type and policy.
+ * The flag must be present on keys used when calling @ref psa_verify_hash().
+ *
+ * This flag automatically sets @ref PSA_KEY_USAGE_VERIFY_MESSAGE : if an application sets
+ * the flag @ref PSA_KEY_USAGE_VERIFY_HASH when creating a key, then the key always has
+ * the permissions conveyed by @ref PSA_KEY_USAGE_VERIFY_MESSAGE, and the flag
+ * @ref PSA_KEY_USAGE_VERIFY_MESSAGE will also be present when the application queries the
+ * usage flags of the key.
+ *
+ * For a key pair, this concerns the public key.
+ */
+#define PSA_KEY_USAGE_VERIFY_HASH ((psa_key_usage_t)0x00002000)
+
+/**
+ * @brief Permission to verify a message signature with the key.
+ *
+ * @details This flag allows the key to be used for a MAC verification operation or for an
+ * asymmetric message signature verification operation, if otherwise permitted by the
+ * key’s type and policy. The flag must be present on keys used with the following APIs:
+ * - @ref psa_mac_verify()
+ * - @ref psa_mac_verify_setup()
+ * - @ref psa_verify_message()
+ *
+ * For a key pair, this concerns the public key.
+ */
+#define PSA_KEY_USAGE_VERIFY_MESSAGE ((psa_key_usage_t)0x00000800)
+
+/**
+ * @brief Sufficient output buffer size for @ref psa_raw_key_agreement(), for any of the
+ * supported key types and key agreement algorithms.
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_raw_key_agreement() will not fail due to an insufficient buffer size.
+ *
+ * See also @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE().
+ */
+#define PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE \
+/* implementation-defined value */
+
+/**
+ * @brief Sufficient output buffer size for @ref psa_raw_key_agreement().
+ *
+ * @details If the size of the output buffer is at least this large, it is guaranteed that
+ * @ref psa_raw_key_agreement() will not fail due to an insufficient buffer size.
+ * The actual size of the output might be smaller in any given call.
+ *
+ * See also @ref PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE.
+ *
+ * @param key_type A supported key type.
+ * @param key_bits The size of the key in bits.
+ *
+ * @return A sufficient output buffer size for the specified key type and size.
+ * 0 if key type is not supported.
+ * If the parameters are not valid, the return value is unspecified.
+ */
+#define PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(key_type, key_bits) \
+/* implementation-defined value */
+
+/**
+ * @brief A sufficient signature buffer size for @ref psa_sign_message() and
+ * @ref psa_sign_hash(), for any of the supported key types and asymmetric signature
+ * algorithms.
+ *
+ * @details If the size of the signature buffer is at least this large, it is guaranteed that
+ * @ref psa_sign_message() and @ref psa_sign_hash() will not fail due to an insufficient
+ * buffer size.
+ *
+ * See also @ref PSA_SIGN_OUTPUT_SIZE().
+ */
+#define PSA_SIGNATURE_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief This macro returns the maximum supported length of the PSK for the TLS-1.2 PSK-to-MS
+ * key derivation.
+ *
+ * @details This implementation-defined value specifies the maximum length for the PSK input used
+ * with a @ref PSA_ALG_TLS12_PSK_TO_MS() key agreement algorithm.
+ *
+ * Quoting Pre-Shared Key Ciphersuites for Transport Layer Security (TLS)
+ * [RFC4279](https://tools.ietf.org/html/rfc4279.html) §5.3:
+ * TLS implementations supporting these cipher suites MUST support arbitrary PSK
+ * identities up to 128 octets in length, and arbitrary PSKs up to 64 octets in length.
+ * Supporting longer identities and keys is RECOMMENDED.
+ *
+ * Therefore, it is recommended that implementations define
+ * @ref PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE with a value greater than or equal to 64.
+ */
+#define PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE /* implementation-defined value */
+
+/**
+ * @brief The action was completed successfully.
+ */
+#define PSA_SUCCESS ((psa_status_t)0)
+
+/**
+ * @brief An error occurred that does not correspond to any defined failure cause.
+ */
+#define PSA_ERROR_GENERIC_ERROR ((psa_status_t)-132)
+
+/**
+ * @brief The requested operation or a parameter is not supported by this implementation.
+ */
+#define PSA_ERROR_NOT_SUPPORTED ((psa_status_t)-134)
+
+/**
+ * @brief The requested action is denied by a policy.
+ */
+#define PSA_ERROR_NOT_PERMITTED ((psa_status_t)-133)
+
+/**
+ * @brief An output buffer is too small.
+ */
+#define PSA_ERROR_BUFFER_TOO_SMALL ((psa_status_t)-138)
+
+/**
+ * @brief Asking for an item that already exists.
+ */
+#define PSA_ERROR_ALREADY_EXISTS ((psa_status_t)-139)
+
+/**
+ * @brief Asking for an item that doesn’t exist.
+ */
+#define PSA_ERROR_DOES_NOT_EXIST ((psa_status_t)-140)
+
+/**
+ * @brief The requested action cannot be performed in the current state.
+ */
+#define PSA_ERROR_BAD_STATE ((psa_status_t)-137)
+
+/**
+ * @brief The parameters passed to the function are invalid.
+ */
+#define PSA_ERROR_INVALID_ARGUMENT ((psa_status_t)-135)
+
+/**
+ * @brief There is not enough runtime memory.
+ */
+#define PSA_ERROR_INSUFFICIENT_MEMORY ((psa_status_t)-141)
+
+/**
+ * @brief There is not enough persistent storage.
+ */
+#define PSA_ERROR_INSUFFICIENT_STORAGE ((psa_status_t)-142)
+
+/**
+ * @brief There was a communication failure inside the implementation.
+ */
+#define PSA_ERROR_COMMUNICATION_FAILURE ((psa_status_t)-145)
+
+/**
+ * @brief There was a storage failure that might have led to data loss.
+ */
+#define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146)
+
+/**
+ * @brief Stored data has been corrupted.
+ */
+#define PSA_ERROR_DATA_CORRUPT ((psa_status_t)-152)
+
+/**
+ * @brief Data read from storage is not valid for the implementation.
+ */
+#define PSA_ERROR_DATA_INVALID ((psa_status_t)-153)
+
+/**
+ * @brief A hardware failure was detected.
+ */
+#define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147)
+
+/**
+ * @brief A tampering attempt was detected.
+ */
+#define PSA_ERROR_CORRUPTION_DETECTED ((psa_status_t)-151)
+
+/**
+ * @brief There is not enough entropy to generate random data needed
+ * for the requested action.
+ */
+#define PSA_ERROR_INSUFFICIENT_ENTROPY ((psa_status_t)-148)
+
+/**
+ * @brief The signature, MAC or hash is incorrect.
+ */
+#define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149)
+
+/**
+ * @brief The decrypted padding is incorrect.
+ */
+#define PSA_ERROR_INVALID_PADDING ((psa_status_t)-150)
+
+/**
+ * @brief Return this error when there’s insufficient data when
+ * attempting to read from a resource.
+ */
+#define PSA_ERROR_INSUFFICIENT_DATA ((psa_status_t)-143)
+
+/**
+ * @brief The key identifier is not valid.
+ */
+#define PSA_ERROR_INVALID_HANDLE ((psa_status_t)-136)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_PSA_CRYPTO_VALUES_H */
+/** @} */
diff --git a/sys/psa_crypto/Kconfig b/sys/psa_crypto/Kconfig
new file mode 100644
index 0000000000..4bdda0b10e
--- /dev/null
+++ b/sys/psa_crypto/Kconfig
@@ -0,0 +1,24 @@
+# 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.
+#
+
+menuconfig MODULE_PSA_CRYPTO
+ bool "PSA Crypto"
+ depends on TEST_KCONFIG
+ select MODULE_RANDOM
+
+if MODULE_PSA_CRYPTO
+
+rsource "Kconfig.asymmetric"
+rsource "Kconfig.ciphers"
+rsource "Kconfig.hashes"
+rsource "Kconfig.mac"
+rsource "Kconfig.keys"
+
+rsource "psa_se_mgmt/Kconfig"
+rsource "psa_key_slot_mgmt/Kconfig"
+
+endif # MODULE_PSA_CRYPTO
diff --git a/sys/psa_crypto/Kconfig.asymmetric b/sys/psa_crypto/Kconfig.asymmetric
new file mode 100644
index 0000000000..6361041e23
--- /dev/null
+++ b/sys/psa_crypto/Kconfig.asymmetric
@@ -0,0 +1,61 @@
+# 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.
+#
+
+menuconfig MODULE_PSA_ASYMMETRIC
+ bool "PSA Asymmetric Crypto"
+ select PSA_KEY_CONFIG
+ select MODULE_PSA_KEY_SLOT_MGMT
+
+if MODULE_PSA_ASYMMETRIC
+
+menuconfig MODULE_PSA_ASYMMETRIC_ECC_P192R1
+ bool "ECC NIST-P192R1"
+ select PSA_KEY_SIZE_192
+
+if MODULE_PSA_ASYMMETRIC_ECC_P192R1
+
+choice PSA_ASYMMETRIC_ECC_P192R1_BACKEND
+ bool "ECC NIST-P192R1 Implementation"
+
+config MODULE_PSA_ASYMMETRIC_ECC_P192R1_BACKEND_PERIPH
+ bool "Hardware accelerated with peripheral"
+ depends on HAS_PERIPH_ECC_P192R1
+ select MODULE_PERIPH_ECC_P192R1
+
+config MODULE_PSA_ASYMMETRIC_ECC_P192R1_BACKEND_MICROECC
+ bool "Micro-ECC Package"
+ select PACKAGE_MICRO-ECC
+ select MODULE_PSA_UECC_P192
+
+endchoice
+
+endif # MODULE_PSA_ASYMMETRIC_ECC_P192R1
+
+menuconfig MODULE_PSA_ASYMMETRIC_ECC_P256R1
+ bool "ECC NIST-P256R1"
+ select PSA_KEY_SIZE_256
+
+if MODULE_PSA_ASYMMETRIC_ECC_P256R1
+
+choice PSA_ASYMMETRIC_ECC_P256R1_BACKEND
+ bool "ECC NIST-P256R1 Implementation"
+
+config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_PERIPH
+ bool "Hardware Accelerated"
+ depends on HAS_PERIPH_ECC_P256R1
+ select MODULE_PERIPH_ECC_P256R1
+
+config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC
+ bool "Micro-ECC Package"
+ select PACKAGE_MICRO-ECC
+ select MODULE_PSA_UECC_P256
+
+endchoice
+
+endif # MODULE_PSA_ASYMMETRIC_ECC_P256R1
+
+endif # MODULE_PSA_ASYMMETRIC
diff --git a/sys/psa_crypto/Kconfig.ciphers b/sys/psa_crypto/Kconfig.ciphers
new file mode 100644
index 0000000000..e7d5303a9b
--- /dev/null
+++ b/sys/psa_crypto/Kconfig.ciphers
@@ -0,0 +1,92 @@
+# 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.
+#
+
+menuconfig MODULE_PSA_CIPHER
+ bool "PSA Ciphers"
+ select PSA_KEY_CONFIG
+ select MODULE_PSA_KEY_SLOT_MGMT
+
+if MODULE_PSA_CIPHER
+
+menuconfig MODULE_PSA_CIPHER_AES_128_ECB
+ bool "AES-128 ECB"
+ select PSA_KEY_SIZE_128
+
+if MODULE_PSA_CIPHER_AES_128_ECB
+
+choice PSA_CIPHER_AES_128_ECB_BACKEND
+ bool "AES-128 Implementation"
+
+config MODULE_PSA_CIPHER_AES_128_ECB_BACKEND_RIOT
+ bool "RIOT cipher"
+ select MODULE_CRYPTO
+ select MODULE_PSA_RIOT_CIPHER_AES_ECB
+
+endchoice
+
+endif # MODULE_PSA_CIPHER_AES_128_ECB
+
+menuconfig MODULE_PSA_CIPHER_AES_128_CBC
+ bool "AES-128 CBC"
+ select PSA_KEY_SIZE_128
+
+if MODULE_PSA_CIPHER_AES_128_CBC
+
+choice PSA_CIPHER_AES_128_CBC_BACKEND
+ bool "AES-128 CBC Implementation"
+
+config MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_PERIPH
+ bool "Hardware Accelerated"
+ depends on HAS_PERIPH_CIPHER_AES_128_CBC
+ select MODULE_PERIPH_CIPHER_AES_128_CBC
+
+config MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT
+ bool "RIOT cipher"
+ select MODULE_CRYPTO
+ select MODULE_PSA_RIOT_CIPHER_AES_128_CBC
+
+endchoice
+
+endif # MODULE_PSA_CIPHER_AES_128_CBC
+
+menuconfig MODULE_PSA_CIPHER_AES_192_CBC
+ bool "AES-192 CBC"
+ select PSA_KEY_SIZE_192
+
+if MODULE_PSA_CIPHER_AES_192_CBC
+
+choice PSA_CIPHER_AES_192_CBC_BACKEND
+ bool "AES-192 Implementation"
+
+config MODULE_PSA_CIPHER_AES_192_CBC_BACKEND_RIOT
+ bool "RIOT cipher"
+ select MODULE_CRYPTO
+ select MODULE_PSA_RIOT_CIPHER_AES_CBC
+
+endchoice
+
+endif # MODULE_PSA_CIPHER_AES_192_CBC
+
+menuconfig MODULE_PSA_CIPHER_AES_256_CBC
+ bool "AES-256 CBC"
+ select PSA_KEY_SIZE_256
+
+if MODULE_PSA_CIPHER_AES_256_CBC
+
+choice CIPHER_AES_256_CBC_BACKEND
+ bool "AES-256 Implementation"
+
+config MODULE_PSA_CIPHER_AES_256_CBC_BACKEND_RIOT
+ bool "RIOT Cipher Module"
+ select MODULE_CRYPTO
+ select MODULE_PSA_RIOT_CIPHER_AES_CBC
+
+endchoice
+
+endif # MODULE_PSA_CIPHER_AES_256_CBC
+
+endif # MODULE_PSA_CIPHER
diff --git a/sys/psa_crypto/Kconfig.hashes b/sys/psa_crypto/Kconfig.hashes
new file mode 100644
index 0000000000..6abf34ad9f
--- /dev/null
+++ b/sys/psa_crypto/Kconfig.hashes
@@ -0,0 +1,111 @@
+# 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.
+#
+
+menuconfig MODULE_PSA_HASH
+ bool "PSA Hashes"
+ select PSA_KEY_CONFIG
+
+if MODULE_PSA_HASH
+
+menuconfig MODULE_PSA_HASH_MD5
+ bool "MD5"
+
+if MODULE_PSA_HASH_MD5
+
+choice PSA_HASH_MD5_BACKEND
+ bool "MD5 implementation"
+
+config MODULE_PSA_HASH_MD5_BACKEND_RIOT
+ bool "RIOT hash"
+ select MODULE_PSA_RIOT_HASHES_MD5
+
+endchoice
+
+endif # MODULE_PSA_HASH_MD5
+
+menuconfig MODULE_PSA_HASH_SHA_1
+ bool "SHA-1"
+
+if MODULE_PSA_HASH_SHA_1
+
+choice PSA_HASH_SHA_1_BACKEND
+ bool "SHA-1 implementation"
+
+config MODULE_PSA_HASH_SHA_1_BACKEND_PERIPH
+ bool "Hardware accelerated"
+ depends on HAS_PERIPH_HASH_SHA_1
+ select MODULE_PERIPH_HASH_SHA_1
+
+config MODULE_PSA_HASH_SHA_1_BACKEND_RIOT
+ bool "RIOT hash"
+ select MODULE_PSA_RIOT_HASHES_SHA_1
+
+endchoice
+
+endif # MODULE_PSA_HASH_SHA_1
+
+menuconfig MODULE_PSA_HASH_SHA_224
+ bool "SHA-224"
+
+if MODULE_PSA_HASH_SHA_224
+
+choice PSA_HASH_SHA_224_BACKEND
+ bool "SHA-224 implementation"
+
+config MODULE_PSA_HASH_SHA_224_BACKEND_PERIPH
+ bool "Hardware accelerated"
+ depends on HAS_PERIPH_HASH_SHA_224
+ select MODULE_PERIPH_HASH_SHA_224
+
+config MODULE_PSA_HASH_SHA_224_BACKEND_RIOT
+ bool "RIOT Hash Module"
+ select MODULE_PSA_RIOT_HASHES_SHA_224
+
+endchoice
+
+endif # MODULE_PSA_HASH_SHA_224
+
+menuconfig MODULE_PSA_HASH_SHA_256
+ bool "SHA-256"
+
+if MODULE_PSA_HASH_SHA_256
+
+choice PSA_HASH_SHA_256_BACKEND
+ bool "SHA-256 implementation"
+
+config MODULE_PSA_HASH_SHA_256_BACKEND_PERIPH
+ bool "Hardware accelerated"
+ depends on HAS_PERIPH_HASH_SHA_256
+ select MODULE_PERIPH_HASH_SHA_256
+
+config MODULE_PSA_HASH_SHA_256_BACKEND_RIOT
+ bool "RIOT hash"
+ select MODULE_PSA_RIOT_HASHES_SHA_256
+
+endchoice
+
+endif # MODULE_PSA_HASH_SHA_256
+
+menuconfig MODULE_PSA_HASH_SHA_512
+ bool "SHA-512"
+ depends on HAS_PERIPH_HASH_SHA_512 # no software implementation so far...
+
+if MODULE_PSA_HASH_SHA_512
+
+choice PSA_HASH_SHA_512_BACKEND
+ bool "SHA-512 implementation"
+
+config MODULE_PSA_HASH_SHA_512_BACKEND_PERIPH
+ bool "Hardware accelerated"
+ depends on HAS_PERIPH_HASH_SHA_512
+ select MODULE_PERIPH_HASH_SHA_512
+
+endchoice
+
+endif # MODULE_PSA_HASH_SHA_512
+
+endif # MODULE_PSA_HASH
diff --git a/sys/psa_crypto/Kconfig.keys b/sys/psa_crypto/Kconfig.keys
new file mode 100644
index 0000000000..21cff30403
--- /dev/null
+++ b/sys/psa_crypto/Kconfig.keys
@@ -0,0 +1,55 @@
+# 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.
+#
+
+menu "PSA Key Management Configuration"
+
+config PSA_KEY_SIZE_128
+ bool "Application uses key of size 128 Bits"
+ help
+ Indicates that the maximum PSA key size should be at least 128 bits.
+
+config PSA_KEY_SIZE_192
+ bool
+ help
+ Indicates that the maximum PSA key size should be at least 192 bits.
+
+config PSA_KEY_SIZE_256
+ bool
+ help
+ Indicates that the maximum PSA key size should be at least 256 bits.
+
+config PSA_KEY_SIZE_512
+ bool
+ help
+ Indicates that the maximum PSA key size should be at least 512 bits.
+
+config PSA_MAX_KEY_SIZE
+ int
+ default 64 if PSA_KEY_SIZE_512
+ default 32 if PSA_KEY_SIZE_256
+ default 24 if PSA_KEY_SIZE_192
+ default 16 if PSA_KEY_SIZE_128
+ default 0
+ help
+ Indicates the maximum PSA key size in bytes.
+
+config PSA_PROTECTED_KEY_COUNT
+ int "Specifies number of allocated protected key slots"
+ default 5 if MODULE_PSA_SECURE_ELEMENT
+ default 0
+
+config PSA_ASYMMETRIC_KEYPAIR_COUNT
+ int "Specifies number of allocated key pair slots"
+ default 5 if MODULE_PSA_ASYMMETRIC
+ default 0
+
+config PSA_SINGLE_KEY_COUNT
+ int "Specifies number of allocated single key slots"
+ default 5 if PSA_MAX_KEY_SIZE != 0
+ default 0
+
+endmenu # PSA Key Management Configuration
diff --git a/sys/psa_crypto/Kconfig.mac b/sys/psa_crypto/Kconfig.mac
new file mode 100644
index 0000000000..fcca459f10
--- /dev/null
+++ b/sys/psa_crypto/Kconfig.mac
@@ -0,0 +1,37 @@
+# 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.
+#
+
+menuconfig MODULE_PSA_MAC
+ bool "PSA Message Authenticated Ciphers"
+ select PSA_KEY_CONFIG
+ select MODULE_PSA_KEY_SLOT_MGMT
+
+if MODULE_PSA_MAC
+
+menuconfig MODULE_PSA_MAC_HMAC_SHA_256
+ bool "HMAC SHA-256"
+ select PSA_KEY_SIZE_256
+
+if MODULE_PSA_MAC_HMAC_SHA_256
+
+choice PSA_MAC_HMAC_SHA_256_BACKEND
+ bool "HMAC SHA256 Implementation"
+
+config MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_PERIPH
+ bool "Hardware Accelerated"
+ depends on HAS_PERIPH_HMAC_SHA_256
+ select MODULE_PERIPH_HMAC_SHA_256
+
+config MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT
+ bool "RIOT HMAC SHA-256"
+ select MODULE_PSA_RIOT_HASHES_HMAC_SHA256
+
+endchoice # PSA_MAC_HMAC_SHA_256_BACKEND
+
+endif # MODULE_PSA_MAC_HMAC_SHA_256
+
+endif # MODULE_PSA_MAC
diff --git a/sys/psa_crypto/Makefile b/sys/psa_crypto/Makefile
new file mode 100644
index 0000000000..6d61a2db19
--- /dev/null
+++ b/sys/psa_crypto/Makefile
@@ -0,0 +1,15 @@
+# PSA Crypto casts like hell, so this needs to shut the f up
+CFLAGS += -Wno-cast-align
+
+# include the PSA headers
+INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
+
+ifneq (,$(filter psa_key_slot_mgmt,$(USEMODULE)))
+ DIRS += psa_key_slot_mgmt
+endif
+
+ifneq (,$(filter psa_se_mgmt,$(USEMODULE)))
+ DIRS += psa_se_mgmt
+endif
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/psa_crypto/Makefile.dep b/sys/psa_crypto/Makefile.dep
new file mode 100644
index 0000000000..14e3f34ad4
--- /dev/null
+++ b/sys/psa_crypto/Makefile.dep
@@ -0,0 +1,241 @@
+ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ USEMODULE += random
+ USEMODULE += prng_musl_lcg
+endif
+
+# Asymmetric
+ifneq (,$(filter psa_asymmetric,$(USEMODULE)))
+ USEMODULE += psa_key_slot_mgmt
+endif
+
+## ECC_P192R1 backend
+ifneq (,$(filter psa_asymmetric_ecc_p192r1,$(USEMODULE)))
+ ifeq (,$(filter psa_asymmetric_ecc_p192r1_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_ecc_p192r1
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_ecc_p192r1,$(FEATURES_USED)))
+ USEMODULE += psa_asymmetric_ecc_p192r1_backend_periph
+ else
+ USEMODULE += psa_asymmetric_ecc_p192r1_backend_microecc
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_asymmetric_ecc_p192r1_backend_microecc, $(USEMODULE)))
+ USEPKG += micro-ecc
+ USEMODULE += psa_uecc
+ USEMODULE += psa_uecc_p192
+endif
+
+ifneq (,$(filter psa_asymmetric_ecc_p192r1_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_ecc_p192r1
+endif
+
+## ECC_P256R1 backend
+ifneq (,$(filter psa_asymmetric_ecc_p256r1,$(USEMODULE)))
+ ifeq (,$(filter psa_asymmetric_ecc_p256r1_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_ecc_p256r1
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_ecc_p256r1,$(FEATURES_USED)))
+ USEMODULE += psa_asymmetric_ecc_p256r1_backend_periph
+ else
+ USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_microecc,$(USEMODULE)))
+ USEPKG += micro-ecc
+ USEMODULE += psa_uecc
+ USEMODULE += psa_uecc_p256
+endif
+
+ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_ecc_p256r1
+endif
+
+# Cipher
+ifneq (,$(filter psa_cipher,$(USEMODULE)))
+ USEMODULE += psa_key_slot_mgmt
+endif
+
+## AES-128-ECB backend
+ifneq (,$(filter psa_cipher_aes_128_ecb,$(USEMODULE)))
+ USEMODULE += psa_cipher_aes_128_ecb_backend_riot
+endif
+
+ifneq (,$(filter psa_cipher_aes_128_ecb_backend_riot,$(USEMODULE)))
+ USEMODULE += crypto
+ USEMODULE += cipher_modes
+ USEMODULE += psa_riot_cipher
+ USEMODULE += psa_riot_cipher_aes_ecb
+endif
+
+## AES-128-CBC
+ifneq (,$(filter psa_cipher_aes_128_cbc,$(USEMODULE)))
+ ifeq (,$(filter psa_cipher_aes_128_cbc_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_cipher_aes_128_cbc
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_cipher_aes_128_cbc,$(FEATURES_USED)))
+ USEMODULE += psa_cipher_aes_128_cbc_backend_periph
+ else
+ USEMODULE += psa_cipher_aes_128_cbc_backend_riot
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_cipher_aes_128_cbc_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_cipher_aes_128_cbc
+endif
+
+ifneq (,$(filter psa_cipher_aes_128_cbc_backend_riot,$(USEMODULE)))
+ USEMODULE += crypto
+ USEMODULE += cipher_modes
+ USEMODULE += psa_riot_cipher
+ USEMODULE += psa_riot_cipher_aes_128_cbc
+endif
+
+## AES-192-CBC
+ifneq (,$(filter psa_cipher_aes_192_cbc,$(USEMODULE)))
+ USEMODULE += psa_cipher_aes_192_cbc_backend_riot
+endif
+
+ifneq (,$(filter psa_cipher_aes_192_cbc_backend_riot,$(USEMODULE)))
+ USEMODULE += crypto
+ USEMODULE += cipher_modes
+ USEMODULE += psa_riot_cipher
+ USEMODULE += psa_riot_cipher_aes_192_cbc
+endif
+
+# Hash
+
+## MD5
+ifneq (,$(filter psa_hash_md5,$(USEMODULE)))
+ USEMODULE += psa_hash_md5_backend_riot
+endif
+
+ifneq (,$(filter psa_hash_md5_backend_riot,$(USEMODULE)))
+ USEMODULE += hashes
+ USEMODULE += psa_riot_hashes
+ USEMODULE += psa_riot_hashes_md5
+endif
+
+## SHA-1
+ifneq (,$(filter psa_hash_sha_1,$(USEMODULE)))
+ ifeq (,$(filter psa_hash_sha_1_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_hash_sha_1
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_hash_sha_1,$(FEATURES_USED)))
+ USEMODULE += psa_hash_sha_1_backend_periph
+ else
+ USEMODULE += psa_hash_sha_1_backend_riot
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_hash_sha_1_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_hash_sha_1
+endif
+
+ifneq (,$(filter psa_hash_sha_1_backend_riot,$(USEMODULE)))
+ USEMODULE += hashes
+ USEMODULE += psa_riot_hashes
+ USEMODULE += psa_riot_hashes_sha_1
+endif
+
+## SHA-224
+ifneq (,$(filter psa_hash_sha_224,$(USEMODULE)))
+ ifeq (,$(filter psa_hash_sha_224_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_hash_sha_224
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_hash_sha_224,$(FEATURES_USED)))
+ USEMODULE += psa_hash_sha_224_backend_periph
+ else
+ USEMODULE += psa_hash_sha_224_backend_riot
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_hash_sha_224_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_hash_sha_224
+endif
+
+ifneq (,$(filter psa_hash_sha_224_backend_riot,$(USEMODULE)))
+ USEMODULE += hashes
+ USEMODULE += psa_riot_hashes
+ USEMODULE += psa_riot_hashes_sha_224
+endif
+
+## SHA-256
+ifneq (,$(filter psa_hash_sha_256,$(USEMODULE)))
+ ifeq (,$(filter psa_hash_sha_256_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_hash_sha_256
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_hash_sha_256,$(FEATURES_USED)))
+ USEMODULE += psa_hash_sha_256_backend_periph
+ else
+ USEMODULE += psa_hash_sha_256_backend_riot
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_hash_sha_256_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_hash_sha_256
+endif
+
+ifneq (,$(filter psa_hash_sha_256_backend_riot,$(USEMODULE)))
+ USEMODULE += hashes
+ USEMODULE += psa_riot_hashes
+ USEMODULE += psa_riot_hashes_sha_256
+endif
+
+## SHA-512
+ifneq (,$(filter psa_hash_sha_512,$(USEMODULE)))
+ USEMODULE += psa_hash_sha_512_backend_periph
+endif
+
+ifneq (,$(filter psa_hash_sha_512_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_hash_sha_512
+endif
+
+# MAC
+## HMAC SHA-256
+ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE)))
+ ifeq (,$(filter psa_mac_hmac_sha_256_custom_backend,$(USEMODULE)))
+ FEATURES_OPTIONAL += periph_hmac_sha_256
+ include $(RIOTMAKE)/features_check.inc.mk
+ # HACK: Due to kconfig migration, may cause problems
+ ifneq (,$(filter periph_hmac_sha_256,$(FEATURES_USED)))
+ USEMODULE += psa_mac_hmac_sha_256_backend_periph
+ else
+ USEMODULE += psa_mac_hmac_sha_256_backend_riot
+ endif
+ endif
+endif
+
+ifneq (,$(filter psa_mac_hmac_sha_256_backend_periph,$(USEMODULE)))
+ FEATURES_REQUIRED += periph_hmac_sha_256
+endif
+
+ifneq (,$(filter psa_mac_hmac_sha_256_backend_riot,$(USEMODULE)))
+ USEMODULE += hashes
+ USEMODULE += psa_riot_hashes
+ USEMODULE += psa_riot_hashes_hmac_sha256
+endif
+
+# Secure Elements
+ifneq (,$(filter psa_secure_element,$(USEMODULE)))
+ USEMODULE += psa_se_mgmt
+ USEMODULE += psa_key_slot_mgmt
+endif
+
+ifneq (,$(filter psa_secure_element_ateccx08a, $(USEMODULE)))
+ USEPKG += cryptoauthlib
+ USEMODULE += psa_secure_element_config
+endif
diff --git a/sys/psa_crypto/Makefile.include b/sys/psa_crypto/Makefile.include
new file mode 100644
index 0000000000..2d23d8665c
--- /dev/null
+++ b/sys/psa_crypto/Makefile.include
@@ -0,0 +1,154 @@
+# include the PSA headers
+INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
+
+# Workaround for mbedtls namespacing issue
+# sys/include will include the conflicting header files in psa but requires a psa/*.h structure.
+INCLUDES += -I$(RIOTBASE)/sys/include/psa_crypto
+
+backends = $(words $(filter $1_backend_%,$(USEMODULE)))
+
+# Pseudomodules
+## Asymmetric
+PSEUDOMODULES += psa_asymmetric
+PSEUDOMODULES += psa_asymmetric_ecc_p192r1
+PSEUDOMODULES += psa_asymmetric_ecc_p192r1_backend_microecc
+PSEUDOMODULES += psa_asymmetric_ecc_p192r1_backend_periph
+PSEUDOMODULES += psa_asymmetric_ecc_p192r1_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_asymmetric_ecc_p192r1,$(USEMODULE)))
+ ifneq (1,$(call backends, psa_asymmetric_ecc_p192r1))
+ $(error "One (and only one) backend should be selected for psa_asymmetric_ecc_p192r1")
+ endif
+endif
+
+PSEUDOMODULES += psa_asymmetric_ecc_p256r1
+PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_microecc
+PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_periph
+PSEUDOMODULES += psa_asymmetric_ecc_p256r1_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_asymmetric_ecc_p256r1,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_asymmetric_ecc_p256r1))
+ $(error "One (and only one) backend should be selected for psa_asymmetric_ecc_p256r1")
+ endif
+endif
+
+## Cipher
+PSEUDOMODULES += psa_cipher
+PSEUDOMODULES += psa_cipher_aes_128_ecb
+PSEUDOMODULES += psa_cipher_aes_128_ecb_backend_riot
+
+PSEUDOMODULES += psa_cipher_aes_128_cbc
+PSEUDOMODULES += psa_cipher_aes_128_cbc_backend_periph
+PSEUDOMODULES += psa_cipher_aes_128_cbc_backend_riot
+PSEUDOMODULES += psa_cipher_aes_128_cbc_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_cipher_aes_128_cbc,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_cipher_aes_128_cbc))
+ $(error "One (and only one) backend should be selected for psa_cipher_aes_128_cbc")
+ endif
+endif
+
+PSEUDOMODULES += psa_cipher_aes_192_cbc
+PSEUDOMODULES += psa_cipher_aes_192_cbc_backend_riot
+PSEUDOMODULES += psa_cipher_aes_192_cbc_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_cipher_aes_192_cbc,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_cipher_aes_192_cbc))
+ $(error "One (and only one) backend should be selected for psa_cipher_aes_192_cbc")
+ endif
+endif
+
+PSEUDOMODULES += psa_cipher_aes_256_cbc
+PSEUDOMODULES += psa_cipher_aes_256_cbc_backend_riot
+PSEUDOMODULES += psa_cipher_aes_256_cbc_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_cipher_aes_256_cbc,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_cipher_aes_256_cbc))
+ $(error "One (and only one) backend should be selected for psa_cipher_aes_256_cbc")
+ endif
+endif
+
+## Hash
+PSEUDOMODULES += psa_hash
+PSEUDOMODULES += psa_hash_md5
+PSEUDOMODULES += psa_hash_md5_backend_riot
+PSEUDOMODULES += psa_hash_md5_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_hash_md5,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_hash_md5))
+ $(error "One (and only one) backend should be selected for psa_hash_md5")
+ endif
+endif
+
+PSEUDOMODULES += psa_hash_sha_1
+PSEUDOMODULES += psa_hash_sha_1_backend_periph
+PSEUDOMODULES += psa_hash_sha_1_backend_riot
+PSEUDOMODULES += psa_hash_sha_1_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_hash_sha_1,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_hash_sha_1))
+ $(error "One (and only one) backend should be selected for psa_hash_sha_1")
+ endif
+endif
+
+PSEUDOMODULES += psa_hash_sha_224
+PSEUDOMODULES += psa_hash_sha_224_backend_periph
+PSEUDOMODULES += psa_hash_sha_224_backend_riot
+PSEUDOMODULES += psa_hash_sha_224_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_hash_sha_224,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_hash_sha_224))
+ $(error "One (and only one) backend should be selected for psa_hash_sha_224")
+ endif
+endif
+
+PSEUDOMODULES += psa_hash_sha_256
+PSEUDOMODULES += psa_hash_sha_256_backend_periph
+PSEUDOMODULES += psa_hash_sha_256_backend_riot
+PSEUDOMODULES += psa_hash_sha_256_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_hash_sha_256,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_hash_sha_256))
+ $(error "One (and only one) backend should be selected for psa_hash_sha_256")
+ endif
+endif
+
+PSEUDOMODULES += psa_hash_sha_512
+PSEUDOMODULES += psa_hash_sha_512_backend_periph
+PSEUDOMODULES += psa_hash_sha_512_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_hash_sha_512,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_hash_sha_512))
+ $(error "One (and only one) backend should be selected for psa_hash_sha_512")
+ endif
+endif
+
+## MAC
+PSEUDOMODULES += psa_mac
+PSEUDOMODULES += psa_mac_hmac_sha_256
+PSEUDOMODULES += psa_mac_hmac_sha_256_backend_periph
+PSEUDOMODULES += psa_mac_hmac_sha_256_backend_riot
+PSEUDOMODULES += psa_mac_hmac_sha_256_custom_backend
+
+# check that one and only one backend has been selected
+ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE)))
+ ifneq (1,$(call backends,psa_mac_hmac_sha_256))
+ $(error "One (and only one) backend should be selected for psa_mac_hmac_sha_256")
+ endif
+endif
+
+## Secure Elements
+PSEUDOMODULES += psa_secure_element
+PSEUDOMODULES += psa_secure_element_asymmetric
+PSEUDOMODULES += psa_secure_element_config
+PSEUDOMODULES += psa_secure_element_multiple
diff --git a/sys/psa_crypto/doc.txt b/sys/psa_crypto/doc.txt
new file mode 100644
index 0000000000..64ce3b4ab4
--- /dev/null
+++ b/sys/psa_crypto/doc.txt
@@ -0,0 +1,996 @@
+/**
+ * @defgroup sys_psa_crypto PSA Cryptographic API
+ * @ingroup sys
+ * @brief Implements the PSA Crypto API specification.
+ * @see https://armmbed.github.io/mbed-crypto/html/
+ *
+ * @warning This implementation is not complete and not yet thoroughly tested.
+ * Please do not use this module in production, as it may introduce security issues.
+ *
+ * @note This implementation is not complete and will be successively expanded.
+ *
+ * About {#About}
+ * =====
+ * This module implements the PSA Cryptography API Version 1.1 as specified
+ * [here](https://armmbed.github.io/mbed-crypto/html/).
+ * It provides an OS level access to cryptographic operations and supports software and hardware
+ * backends as well as the use of secure elements.
+ * The API automatically builds a hardware backend for an operation, if there's one available,
+ * otherwise it falls back to software. Specific backends can be configured, if needed.
+ * For configuration options see [Configuration](#configuration).
+ *
+ * PSA Crypto has an integrated key management module, which stores keys internally
+ * without exposing them to applications. To learn how to use keys with PSA,
+ * read [Using Keys](#using-keys).
+ *
+ * A basic usage and configuration example can be found in `examples/psa_crypto`.
+ * For more usage instructions, please read the documentation.
+ *
+ * If you want to add your own crypto backend, see [Porting Guide](#porting-guide).
+ *
+ * Basic Usage
+ * ===
+ * To use PSA Crypto, add `psa/crypto.h` to your includes. This will make all
+ * operations and macros available.
+ *
+ * Call `psa_crypto_init()` before calling any other operation.
+ *
+ * ## Structure Initialization
+ * Whenever you declare a PSA Crypto structure (e.g. operation contexts or key attributes),
+ * it needs to be initialized with zeroes. A structure that is not initialized will be interpreted
+ * by PSA as *active* and can not be used for a new operation.
+ * The example function and macro shown below result in the same thing: A new, inactive structure.
+ *
+ * @code {.c}
+ * // Choose one of these options
+ * psa_hash_operation_t hash_op = psa_hash_operation_init();
+ * psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT;
+ * @endcode
+ *
+ * An already active operation can be set to zero by reinitializing it. It then becomes *inactive*
+ * again and can be used for a new operation.
+ *
+ * When errors occur during execution, PSA resets the operation contexts and makes them
+ * *inactive*, to prevent unauthorized access to an operation's state.
+ * Users can also call `psa__abort()` anytime in between function calls to do the same.
+ *
+ * Using Keys {#using-keys}
+ * ===
+ * PSA can only operate on keys, that are registered with and stored within the internal
+ * key storage module. This means you need to either generate keys with PSA or
+ * import an existing key.
+ * For this purpose there are a number of
+ * [key management functions](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html)
+ * (external link).
+ *
+ * ## Key Attributes
+ * When creating a key for PSA, the implementation needs to know what kind of key it is
+ * dealing with, what it can be used for, where it's supposed to be stored, etc.
+ * That information needs to be specified in a set of
+ * [Key Attributes](https://armmbed.github.io/mbed-crypto/html/api/keys/attributes.html)
+ * (external link).
+ *
+ * The example below defines attributes for an AES-128 key, which can be used for CBC encryption
+ * and decryption and will be stored in local volatile memory.
+ * @code
+ * // Initializes empty attributes structure
+ * psa_key_attributes_t attributes = psa_key_attributes_init();
+ *
+ * // Set all necessary attributes
+ * psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+ * psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
+ * psa_set_key_bits(&attributes, 128);
+ * psa_set_key_algorithm(&attributes, PSA_ALG_CBC_NO_PADDING);
+ * psa_set_key_usage_flags(&attributes, (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT));
+ * @endcode
+ *
+ * After setting the attributes, an exiting key can be imported:
+ * @code
+ * uint8_t aes_key[] = { ... };
+ * psa_key_id_t key_id = 0; // Will be set by PSA Crypto
+ * psa_status_t status = psa_import_key(&attributes, aes_key, sizeof(aes_key), &key_id);
+ * @endcode
+ * The PSA Crypto implementation will assign an identifier to the key and return it
+ * via the `key_id` parameter. This identifier can then be used for operations with this
+ * specific key.
+ * @code
+ * uint8_t PLAINTEXT[] = { ... };
+ * // Buffer sizes can be calculated with macros
+ * size_t output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING,sizeof(PLAINTEXT));
+ * uint8_t output_buffer[output_buf_size];
+ *
+ * status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, sizeof(PLAINTEXT),output_buffer, sizeof(output_buffer), &output_length));
+ * @endcode
+ *
+ * All the supported key types, algorithms and usage flags can be found in the documentation.
+ *
+ * ### Key Lifetime {#key-lifetime}
+ * #### Volatile vs. Persistent
+ * The PSA API specifies two ways of storing keys: volatile and persistent. Volatile
+ * keys will be stored only in RAM, which means they will be destroyed after application
+ * termination or a device reset.
+ * Persistent keys will also be written into flash memory for later access. To destroy
+ * them they must be explicitly deleted with the `psa_destroy_key()` function.
+ *
+ * @note So far this implementation only supports volatile storage. Persistent storage
+ * will be added in the future.
+ *
+ * #### Lifetime Encoding
+ * When creating a key, the user needs to specify a lifetime value, which actually consists
+ * of two values: persistence and location. The location defines the actual memory location
+ * of the key (e.g. whether the key will be stored in RAM, in a hardware protected memory slot
+ * or on an external device like a secure element).
+ *
+ * The persistence value defines whether the key will be stored in RAM (volatile)
+ * in flash (persistent).
+ * Some default values that exist are:
+ * - @ref PSA_KEY_LIFETIME_VOLATILE (stored in local, volatile memory)
+ * - @ref PSA_KEY_LIFETIME_PERSISTENT (stored in local, persistent memory)
+ *
+ * Other lifetime values can be constructed with the macro
+ * `PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location)`.
+ * All supported `PSA_KEY_PERSISTENCE_*` and `PSA_KEY_LOCATION_*` values can be combined.
+ *
+ * In addition to the location values defined by the specification, this implementation also
+ * supports values for [Secure Elements](#secure-elements).
+ *
+ * Configuration {#configuration}
+ * ===
+ * Currently there are two ways to configure PSA Crypto: Kconfig and Makefiles. An example for both
+ * can be found in `RIOT/examples/psa_crypto`.
+ *
+ * ## Kconfig
+ * We recommend using Kconfig and choosing your features in `menuconfig`.
+ * You can access the GUI by calling
+ *
+ * @code
+ * TEST_KCONFIG=1 BOARD= make menuconfig
+ * @endcode
+ *
+ * from your application directory.
+ * There you can find the available PSA features and options under `System->PSA Crypto`.
+ * If you only select the operations you want to use (e.g. `PSA Ciphers->AES-128 CBC`), Kconfig
+ * will automatically select the best backend for you depending on the board (e.g. a hardware
+ * accelerator if it is available). Optionally you can force a custom backend.
+ *
+ * Further you can specify the exact number of keys you need to store (section `PSA Key Management
+ * Configuration` in `menuconfig`), or choose your [Secure Element](#secure-elements)
+ * configurations.
+ *
+ * Alternatively you can create an `app.config.test` file in your application folder
+ * and choose your symbols there (see `examples/psa_crypto`).
+ *
+ * In the `app.config.test` file, modules can be chosen with the following syntax:
+ * `CONFIG_MODULE_=y`, as shown below.
+ * @code
+ * CONFIG_MODULE_PSA_CRYPTO=y
+ * CONFIG_MODULE_PSA_CIPHER=y
+ * CONFIG_MODULE_PSA_CIPHER_AES_128_CBC=y
+ * @endcode
+ *
+ * ## Makefiles
+ * If you don't want to use Kconfig, you can use the traditional way in RIOT of selecting
+ * modules in your application Makefile.
+ *
+ * Here you need to set the base module and individual modules for each operation you need.
+ * The example below also chooses a default backend depending on your board.
+ * @code
+ * // Base module: this is required!
+ * USEMODULE += psa_crypto
+ *
+ * USEMODULE += psa_cipher
+ * USEMODULE += psa_cipher_aes_128_cbc
+ * @endcode
+ *
+ * If desired, you can choose a specific backend at compile time. For this you need to specify
+ * that you want to set a custom backend and then explicitly choose the one you want (see below).
+ * @code
+ * USEMODULE += psa_cipher_aes_128_cbc_custom_backend
+ * USEMODULE += psa_cipher_aes_128_cbc_backend_riot
+ * @endcode
+ *
+ * The currently available modules, are listed [below](#available-modules).
+ *
+ * ## Key Slot Types {#configuration-keys}
+ * The key management of PSA keeps track of keys by storing them in virtual key slot
+ * representations, along with their attributes. Since keys can come in various sizes,
+ * it would be inefficient to allocate the same amount of memory for all keys.
+ * To reduce the amount of memory used for key storage, PSA internally differentiates between
+ * three types of key slots (see below). Depending on the operations your application uses, PSA will
+ * automatically detect the key sizes needed and will allocate the required memory.
+ * The number of key slots allocated of each type is set to five per default, but can be changed by
+ * the user depending on their requirements.
+ *
+ * | Single Key Slot | Asymmetric Key Slot | Protected Key Slot |
+ * |----------------|---------------------|--------------------|
+ * | Single keys or unstructured data, e.g. AES keys or asymmetric public keys in local memory | Asymmetric key pairs (private and public parts) in local memory | Any keys stored on a secure element or on-chip in hardware protected memory |
+ *
+ * If you want to change the default number of allocated key slots you can do so by
+ * updating the number in `menuconfig`, or adding them to the `app.config.test` file like so:
+ * @code
+ * CONFIG_PSA_SINGLE_KEY_COUNT=3
+ * CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
+ * CONFIG_PSA_PROTECTED_KEY_COUNT=2
+ * @endcode
+ *
+ * When using Makefiles, you can pass CFLAGS as shown below.
+ * @code
+ * CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3
+ * CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
+ * CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=2
+ * @endcode
+ *
+ * ## Available Modules {#available-modules}
+ * Below are the currently available modules.
+ * No matter which operation you need, you always have to choose the base module.
+ * If you want to specify a backend other than the default, you need to select
+ * `psa__custom_backend` in addition to the actual backend module.
+ *
+ * The names listed are are the version used in makefiles with the
+ * `USEMODULE += ` syntax.
+ * In Kconfig you don't need to know the exact names, you can simply choose the features in
+ * `menuconfig`.
+ * When using `app.config.test` files in your application directory, you need to write the
+ * names in uppercase and add the prefix `CONFIG_MODULE_` to all of them.
+ *
+ * ### Asymmetric Crypto
+ * - Base: psa_asymmetric
+ *
+ * #### NIST ECC P192
+ * - psa_asymmetric_ecc_p192r1
+ * - psa_asymmetric_ecc_p192r1_backend_periph
+ * - psa_asymmetric_ecc_p192r1_custom_backend
+ * - psa_asymmetric_ecc_p192r1_backend_microecc
+ *
+ * #### NIST ECC P192
+ * - psa_asymmetric_ecc_p256r1
+ * - psa_asymmetric_ecc_p256r1_backend_periph
+ * - psa_asymmetric_ecc_p256r1_custom_backend
+ * - psa_asymmetric_ecc_p256r1_backend_microecc
+ *
+ * ### Ciphers
+ * - Base: psa_cipher
+ *
+ * #### AES ECB
+ * - psa_cipher_aes_128_ecb
+ * - psa_cipher_aes_128_ecb_backend_riot
+ *
+ * #### AES CBC
+ * - psa_cipher_aes_128_cbc
+ * - psa_cipher_aes_128_cbc_backend_periph
+ * - psa_cipher_aes_128_cbc_custom_backend
+ * - psa_cipher_aes_128_cbc_backend_riot
+ * - psa_cipher_aes_192_cbc
+ * - psa_cipher_aes_192_cbc_custom_backend
+ * - psa_cipher_aes_192_cbc_backend_riot
+ * - psa_cipher_aes_256_cbc
+ * - psa_cipher_aes_256_cbc_custom_backend
+ * - psa_cipher_aes_256_cbc_backend_riot
+ *
+ * ### Hashes
+ * - Base: psa_hash
+ *
+ * #### MD5
+ * - psa_hash_md5
+ * - psa_hash_md5_custom_backend
+ * - psa_hash_md5_backend_riot
+ *
+ * #### SHA 1
+ * - psa_hash_sha_1
+ * - psa_hash_sha_1_backend_periph
+ * - psa_hash_sha_1_custom_backend
+ * - psa_hash_sha_1_backend_riot
+ *
+ * #### SHA 224
+ * - psa_hash_sha_224
+ * - psa_hash_sha_224_backend_periph
+ * - psa_hash_sha_224_custom_backend
+ * - psa_hash_sha_224_backend_riot
+ *
+ * #### SHA 256
+ * - psa_hash_sha_256
+ * - psa_hash_sha_256_backend_periph
+ * - psa_hash_sha_256_custom_backend
+ * - psa_hash_sha_256_backend_riot
+ *
+ * #### SHA 512
+ * - psa_hash_sha_512
+ * - psa_hash_sha_512_backend_periph
+ * - psa_hash_sha_512_custom_backend
+ *
+ * ### MAC
+ * - Base: psa_mac
+ *
+ * #### HMAC SHA 256
+ * - psa_mac_hmac_sha_256
+ * - psa_mac_hmac_sha_256_backend_periph
+ * - psa_mac_hmac_sha_256_custom_backend
+ * - psa_mac_hmac_sha_256_backend_riot
+ *
+ * ### Secure Elements
+ * Base:
+ *
+ * - psa_secure_element
+ * - psa_secure_element_multiple
+ *
+ * #### SE Types
+ * - psa_secure_element_ateccx08a
+ * - psa_secure_element_ateccx08a_ecc_p256
+ *
+ * Random Number Generation {#rng}
+ * ===
+ * Currently uses the [RIOT Random Module](#sys_random) as a backend.
+ * See the documentation for configuration options.
+ *
+ * Secure Elements {#secure-elements}
+ * ===
+ *
+ * An example showing the use of SEs can be found in `examples/psa_crypto`.
+ *
+ * To use secure elements, you first need to assign a static location value to each device,
+ * so PSA can find it. If you only use one device, you can use
+ * `PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT`. For additional devices this value must be within
+ * the range of `PSA_KEY_LOCATION_SE_MIN` and `PSA_KEY_LOCATION_SE_MAX`.
+ * When booting the system, the `auto_init` module in RIOT will automatically register the device
+ * with the location with PSA Crypto.
+ *
+ * You can now import or create keys on the secure element by constructing a key lifetime containing
+ * a device's location value.
+ *
+ * @code {.c}
+ * psa_key_lifetime_t lifetime =
+ * PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION (PSA_KEY_LIFETIME_VOLATILE,
+ PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT);
+ * @endcode
+ *
+ * Some secure elements come with their own key management and device configurations. In this case
+ * the configuration parameters must be passed to PSA Crypto during the registration. For this, you
+ * need to define a `psa_se_config_t` structure containing the configuration.
+ * PSA Crypto will use this structure to keep track of what types of keys are allowed on the device
+ * and how much storage is available.
+ * Where this structure should be placed, how it looks and what parameters are required depends
+ * on the type of your device.
+ *
+ * A good place to define that structure and the location values is a drivers `_params.h`
+ * file, but this may vary depending on how your device is integrated in RIOT.
+ *
+ * For detailed, device specific information, please check the device driver documentation or
+ * the example.
+ *
+ * ## Available Devices and Drivers
+ * - ATECCX08A: [Microchip Cryptoauthlib as a PSA backend](#psa-cryptoauthlib)
+ *
+ * ## Main SE Configuration
+ * To use SEs, the appropriate modules must be chosen in Kconfig:
+ * @code
+ * CONFIG_PSA_SECURE_ELEMENT=y
+ * CONFIG_PSA_SECURE_ELEMENT_ATECCX08A=y // device example
+ * CONFIG_PSA_SECURE_ELEMENT_ATECCX08A_ECC=y
+ * @endcode
+ *
+ * or added to the the Makefile:
+ * @code
+ * USEMODULE += psa_secure_element
+ * USEMODULE += psa_secure_element_ateccx08a // device example
+ * USEMODULE += psa_secure_element_ateccx08a_ecc_p256
+ * @endcode
+ *
+ * This implementation supports the use of one or more secure elements (SE) as backends. In this
+ * case the number of used secure elements must be specified (must be at least 2 and at most 255).
+ * When using more than one SE, add
+ * @code
+ * CONFIG_PSA_SECURE_ELEMENT_MULTIPLE=y
+ * CONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255
+ * @endcode
+ *
+ * or, respectively,
+ *
+ * @code
+ * USEMODULE += psa_secure_element_multiple
+ * CFLAGS += -DCONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255
+ * @endcode
+ *
+ * Porting Guide {#porting-guide}
+ * ===
+ * This porting guide focuses on how to add your software library or hardware driver
+ * as a backend to PSA Crypto without actually touching the PSA implementation.
+ * We will provide some [general information](#porting-general) and then some case
+ * examples for different kinds of backends:
+ * - [Software Libraries](#porting-software)
+ * - [Hardware Drivers](#porting-hardware)
+ * - [Secure Elements](#porting-secure-elements)
+ *
+ * Some examples to look at are:
+ * - [RIOT hash module](#sys_hashes)
+ * - [RIOT cipher module](#sys_crypto)
+ * - [Micro-ECC](#pkg_micro_ecc)
+ * - [CryptoCell 310 driver](#pkg_driver_cryptocell_310).
+ *
+ * An example integrating a secure element can be found in the
+ * [Cryptoauthlib Package](#pkg_cryptoauthlib).
+ *
+ * ## General Information {#porting-general}
+ * ### Error Values
+ * You should always check the status of your function calls and translate your library's or
+ * driver's errors to PSA error values (please be as thorough as possible).
+ * The PSA Crypto specification describes exactly what kind of error values should be returned
+ * by which function. Please read the API documentation and comply with the instructions.
+ * We recommend writing a`_to_psa_error()` function right in the beginning (see for
+ * example `CRYS_to_psa_error()` in
+ * `pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c`).
+ *
+ * ### The Build System
+ * As mentioned before, there are two ways of selecting build time configurations in RIOT: Kconfig
+ * and Makefiles.
+ * Kconfig dependency resolution is currently an experimental feature and will at some point
+ * replace Makefiles. Until then, our implementation needs to support both, which means we need
+ * to define features and symbols in multiple places.
+ * Luckily, the modules have the exact same names in both systems, which makes the transfer easier.
+ * The examples below show both ways.
+ *
+ * ### Modules {#module-names}
+ * In RIOT, module names are generated from path names, so if you create a directory for
+ * your sourcefiles, the module name will be the same as the directory name. It is possible
+ * to change that by declaring a new module name in the Makefile by adding the line
+ * your_module_name`.
+ *
+ * If you leave it like this, all sourcefiles in the path corresponding to the module name will be
+ * built (e.g. if you choose to module `hashes`, all files in `sys/hashes` will be included).
+ * For better configurability it is possible to add submodules (see
+ * `sys/hashes/psa_riot_hashes` for example).
+ * In that case the base module name will be the directory name and each file inside the directory
+ * becomes its own submodule that must be explicitly chosen. The module name will then be the
+ * directory name with the file name as a postfix.
+ * For example:
+ * @code
+ * USEMODULE += hashes
+ * USEMODULE += psa_riot_hashes
+ * USEMODULE += psa_riot_hashes_sha_256
+ *
+ * will build the file at `sys/hashes/psa_riot_hashes/sha_256.c`, but none of the other files in
+ * the directory).
+ *
+ * To enable submodules for your implementation add the following to the directory makefile:
+ * @code
+ * BASE_MODULE := psa_
+ * SUBMODULES := 1
+ * @endcode
+ *
+ * We also need to create so-called pseudomodules for each available submodule.
+ * Those must follow the scheme `psa__`.
+ * Where they are declared depends on where your module is located. Pseudomodules in `RIOT/sys` must
+ * be added in `pseudomodules.inc.mk`.
+ * When integrating packages or drivers, the pseudomodules can be added in the `Makefile.include`
+ * file of the individual module's directory (see `pkg/micro-ecc/Makefile.include`).
+ *
+ * When adding backends to PSA Crypto, please name your modules in ways that fit within the
+ * current naming scheme: `psa__`. Also, when adding software libraries and
+ * hardware drivers, use the submodule approach. That makes PSA Crypto more configurable.
+ *
+ * The drawback of the submodule approach is, that if one of our sourcefiles depends on
+ * another sourcefile in the same folder, we need to select it explicitly. For example, in
+ * `pkg/driver_cryptocell_310/psa_cryptocell_310` you can see that there are some common source
+ * files that all the others use (e.g. for hashes there is a `hashes_common.c` file).
+ *
+ * If that is the case for your driver, you need to make sure the modules are selected in
+ * the Kconfig file as well as the `Makefile.dep` file (see `psa_cryptocell_310/Makefile.dep` or
+ * `psa_cryptocell_310/Kconfig`).
+ *
+ * ### Adding Glue Code {#glue-code}
+ * We define a number of wrapper APIs, which are called by PSA to invoke crypto backends.
+ * Software libraries and hardware drivers use the same methods, secure elements are handled
+ * in a different way (see [Case Example – Secure Elements](#porting-secure-elements) for details).
+ *
+ * The names, parameters and return values for wrapper methods are defined in header files in
+ * `sys/psa_crypto/include/psa_.h`.
+ * The functions declared in those files are the ones that are currently supported by this
+ * PSA implementation. They will be extended in the future.
+ *
+ * You need to implement those functions with glue code calling your library or driver code
+ * and converting types and error values between PSA and your backend.
+ * Below is an example of how this might look (it's very reduced, your library may need
+ * much more glue code).
+ * @code {.c}
+ * psa_status_t psa_ecc_p256r1_sign_hash(const psa_key_attributes_t *attributes,
+ * psa_algorithm_t alg, const uint8_t *key_buffer,
+ * size_t key_buffer_size, const uint8_t *hash,
+ * size_t hash_length, uint8_t *signature,
+ * size_t signature_size, size_t *signature_length)
+ * {
+ * int status = _(key_buffer, hash, hash_length,
+ * signature, signature_length, curve);
+ *
+ * if (status != SUCCESS) {
+ * return _status_to_psa_error(status);
+ * }
+ *
+ * (void)alg;
+ * (void)attributes;
+ * (void)key_buffer_size;
+ * return PSA_SUCCESS;
+ * }
+ * @endcode
+ *
+ * ### Operation Contexts
+ * Some cryptographic operations use driver specific context to store the operation state in
+ * between function calls. These must be defined somewhere. Examples can be found in
+ * `pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h` and
+ * `sys/include/hashes/psa/riot_hashes.h`.
+ *
+ * When defining the contexts for a hardware driver, all you need to do is add a file called
+ * `psa_periph__ctx.h` to your driver's include folder and define the available types
+ * (see supported [types](#supported-types) below).
+ * Those files are automatically included in `crypto_includes.h` and it is important that they
+ * always have the same name for each algorithm.
+ *
+ * When defining the contexts for a software library, the headerfile should be called
+ * `_.h` (e.g. `riot_hashes.h`) and must be added to `crypto_includes.h` as
+ * shown below:
+ * @code
+ * #if IS_USED(MODULE_PSA__)
+ * #include "/_.h"
+ * #endif
+ * @endcode
+ *
+ * When defining the context types, those must always depend on the specific algorithm module,
+ * for example
+ * @code
+ * #if IS_USED(MODULE_PSA__HASHES_SHA_256)
+ * #include "path/to/headerfile_containing_the_driver_context_definition"
+ *
+ * typedef psa_hashes_sha256_ctx_t;
+ * #endif
+ * @endcode
+ *
+ * #### Hashes {#supported-types}
+ * - `psa_hashes_md5_ctx_t`
+ * - `psa_hashes_sha1_ctx_t`
+ * - `psa_hashes_sha224_ctx_t`
+ * - `psa_hashes_sha256_ctx_t`
+ * - `psa_hashes_sha512_ctx_t`
+ *
+ * #### Ciphers
+ * - `psa_cipher_aes_128_ctx_t`
+ * - `psa_cipher_aes_192_ctx_t`
+ * - `psa_cipher_aes_256_ctx_t`
+ *
+ * Secure Elements need their own contexts. For this,
+ * see [Case Example – Secure Elements](#porting-secure-elements).
+ *
+ * ## Adding a Backend
+ * The integration of hardware drivers, software libraries and secure element drivers
+ * differs a bit. Below we describe the necessary steps for each of them.
+ *
+ * ### Case Example – A Software Library {#porting-software}
+ * Software libraries are the easiest backends, because they are not platform or hardware
+ * specific. They can generally run on all platforms in RIOT and we can
+ * combine different software backends for different operations (we could, for example,
+ * use the Micro-ECC package for ECC NIST curves and the C25519 package for operations with
+ * the Curve25519).
+ *
+ * Let's say we have an imaginary software library called `FancyCrypt` and want to use
+ * it as a backend of PSA. We've already added it to RIOT as a third party package in
+ * `pkg/fancycrypt`.
+ * Our library provides hashes and elliptic curve operations and to make it accessible to
+ * PSA Crypto we need to write wrappers for our API calls.
+ *
+ * First we create a folder called `psa_fancycrypt` in the package directory. Inside we create
+ * a file with the name of each operation you want to integrate, e.g. `p256.c` and
+ * `hashes_sha_224.c` (when adding operations, remember that the path of the files will also
+ * be the [module name](#module-names), so please comply with the current naming scheme).
+ *
+ * In these files we need to implement the methods that are called by PSA as described
+ * [above](#glue-code).
+ *
+ * #### Adding Makefiles
+ * We add a Makefile to the `psa_fancycrypt` folder with the following content:
+ * @code {.c}
+ * BASE_MODULE := psa_fancycrypt
+ * SUBMODULES := 1
+ *
+ * include $(RIOTBASE)/Makefile.base
+ * @endcode
+ *
+ * This tells RIOT that the `psa_fancycrypt` module has submodules, which can be selected
+ * individually.
+ *
+ * In `pkg/fancycrypt` we now need to declare explicit pseudomodules in `Makefile.include` and add
+ * the `psa_fancycrypt` folder to the source files and the `sys/psa_crypto/include` folder to the
+ * includes.
+ * These should be dependent on the PSA Crypto module as shown below.
+ *
+ * @code
+ * ifneq (,$(filter psa_fancycrypt_%, $(USEMODULE)))
+ * PSEUDOMODULES += psa_fancycrypt_hashes_sha_256
+ * PSEUDOMODULES += psa_fancycrypt_p256
+ * DIRS += $(RIOTPKG)/fancycrypt/psa_fancycrypt
+ * INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
+ * endif
+ * @endcode
+ *
+ * If the implementation has any dependencies, they need to be added in `Makefile.dep`, for example:
+ * @code
+ * USEMODULE += psa_fancycrypt
+ * USEMODULE += psa_fancycrypt_error_conversion
+ *
+ * ifneq (,$(filter psa_fancycrypt_hashes_sha1,$(USEMODULE)))
+ * USEMODULE += psa_fancycrypt_hashes_common
+ * endif
+ * @endcode
+ *
+ * #### Adding a Kconfig file
+ * We add a file called `Kconfig` to the `psa_fancycrypt` folder. Here we declare
+ * the modules for Kconfig like so:
+ * @code
+ * config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256
+ * bool
+ * depends on MODULE_PSA_CRYPTO
+ * select MODULE_PSA_FANCYCRYPT
+ *
+ * config MODULE_PSA_FANCYCRYPT_P256
+ * bool
+ * depends on MODULE_PSA_CRYPTO
+ * select MODULE_PSA_FANCYCRYPT
+ *
+ * config MODULE_PSA_FANCYCRYPT
+ * bool
+ * @endcode
+ *
+ * If the implementation has any dependencies, we can select them in this Kconfig file:
+ * @code
+ * config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256
+ * bool
+ * depends on MODULE_PSA_CRYPTO
+ * select MODULE_PSA_FANCYCRYPT
+ * select MODULE_PSA_FANCYCRYPT_HASHES_COMMON
+ * select MODULE_PSA_FANCYCRYPT_ERROR_CONVERSION
+ * @endcode
+ *
+ * In `pkg/fancycrypt/Kconfig` we need to add the line
+ * @code
+ * rsource "psa_fancycrypt/Kconfig"
+ * @endcode
+ * at the bottom.
+ *
+ * #### Telling PSA Crypto about it
+ * To be able to choose `fancycrypt` as a PSA backend, we need to add the option to the Kconfig
+ * and Makefiles of the PSA Crypto Module.
+ *
+ * In `sys/psa_crypto/` we need to modify `Kconfig.asymmetric`, `sys/psa_crypto/Kconfig.hashes`,
+ * `Makefile.dep` and `Makefile.include`.
+ *
+ * To `Kconfig.asymmetric` we need to add
+ * @code
+ * config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_FANCYCRYPT
+ * bool "FancyCrypt Package"
+ * select PACKAGE_FANCYCRYPT
+ * select MODULE_PSA_FANCYCRYPT_P256
+ * @endcode
+ * This will expose FancyCrypt as a backend option in PSA and then enable all the necessary
+ * features, when users select it.
+ * You need to do the same thing for the hash operation in `Kconfig.hashes`.
+ *
+ * To achieve the same thing with Makefiles we need to do this in two places:
+ * In `Makefile.include` there are some existing pseudomodules for asymmetric crypto and hashes.
+ * There we need to create the backend modules for FancyCrypt by adding
+ *
+ * @code
+ * PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_fancycrypt
+ * @endcode
+ *
+ * and
+ *
+ * @code
+ * PSEUDOMODULES += psa_hash_sha_256_backend_fancycrypt
+ * @endcode
+ *
+ * The automatic module selection happens in `Makefile.dep`. To the place where exiting P256 curves
+ * and hashes are selected we add cases for our backend modules:
+ *
+ * @code
+ * ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_fancycrypt,$(USEMODULE)))
+ * USEPKG += fancycrypt
+ * USEMODULE += psa_fancycrypt
+ * USEMODULE += psa_fancycrypt_p256
+ * endif
+ * @endcode
+ *
+ * Now you should be able to select your package as a backend for PSA Crypto and use it to perform
+ * operations.
+ *
+ * ### Case Example – A Hardware Driver {#porting-hardware}
+ * The first steps of porting a hardware driver are the same as for the software library.
+ * Only we skip the last part where we add the modules to the PSA Crypto Kconfig and Makefiles
+ * and do something else instead.
+ *
+ * Hardware drivers are treated a little differently, mostly because they are tied to a specific
+ * platform and users can not just choose a different driver for their accelerator.
+ * Therefore we just want PSA Crypto to automatically use this driver whenever it runs on the
+ * corresponding platform, which means that we have to add some additional options and features,
+ * not only to the driver but also to the CPU it belongs to.
+ * A good example for this is the [CryptoCell 310 driver](#pkg_driver_cryptocell_310) for the
+ * accelerator on the [nRF52840 CPU](#cpu_nrf52).
+ *
+ * Now, let's say we have a CPU called `myCPU` with an on-chip accelerator called
+ * `speedycrypt`. Let's say that `speedycrypt` provides hashes and ECC curves.
+ * The vendor provides a driver, which we already have included in RIOT as a package.
+ * Also we've followed the steps in the [glue code section](#glue-code) and provide a folder called
+ * `pkg/driver_speedycrypt/psa_speedycrypt` with the required wrapper files.
+ * We have also added the module names in a Kconfig file and in the Makefiles.
+ *
+ * #### Telling PSA Crypto about it
+ * This is where we diverge from the software library example. If you take a look at the available
+ * backends in PSA, you'll notice one with the postfix `*_BACKEND_PERIPH` for each available
+ * algorithm. **Periph** here is short for *peripheral hardware accelerator*.
+ * The `*_BACKEND_PERIPH` modules depend on the presence of such an accelerator. They are a generic
+ * module for all crypto hardware accelerators and will automatically resolve to the driver that is
+ * associated with the available accelerator.
+ *
+ * Before we're able to use it we need to tell RIOT that those hardware features exist for
+ * our `myCPU` (see `cpu/nrf52/Kconfig` and `cpu/nrf52/Makefile.features` as an example).
+ * In `cpu/myCPU` we add all the provided features as shown below.
+ *
+ * Files we need to touch:
+ * - `cpu/myCPU/Makefile.features`
+ * - `cpu/myCPU/Kconfig`
+ * - `cpu/myCPU/periph/Makefile.dep`
+ * - `cpu/myCPU/periph/Kconfig`
+ * - When defining new features: `RIOT/kconfigs/Kconfig.features`
+ *
+ * **cpu/myCPU/Makefile.features:**
+ * @code
+ * FEATURES_PROVIDED += periph_speedycrypt // General feature for the acclerator
+ * FEATURES_PROVIDED += periph_hash_sha_256
+ * FEATURES_PROVIDED += periph_ecc_p256r1
+ * @endcode
+ *
+ * **cpu/myCPU/Kconfig:**
+ * @code
+ * config CPU_FAM_MYCPU
+ * bool
+ * select CPU_SOME_FEATURES
+ * ...
+ * select HAS_PERIPH_HASH_SHA_256
+ * select HAS_PERIPH_ECC_P256R1
+ * select HAS_PERIPH_SPEEDYCRYPT
+ * @endcode
+ * The `HAS_PERIPH_*` symbols are defined in ``. If your device
+ * provides capabilities that are not yet defined, you can add them to that file.
+ *
+ * Next we need to define selectable modules for this in the `cpu/myCPU/periph` folder, which
+ * then automatically enable the driver. An example for this is `cpu/nrf52/periph`.
+ * We add the following to the `cpu/myCPU/periph/Kconfig` file and `cpu/myCPU/periph/Makefile.dep`:
+ *
+ * **cpu/myCPU/periph/Makefile.dep:**
+ * @code
+ * ifneq (,$(filter periph_hash_sha_256,$(USEMODULE)))
+ * USEPKG += driver_speedycrypt
+ * USEMODULE += psa_speedycrypt_hashes_sha256
+ * endif
+ * @endcode
+ *
+ * **cpu/myCPU/periph/Kconfig:**
+ * @code
+ * config MODULE_PERIPH_FANCYCRYPT
+ * bool
+ * depends on HAS_PERIPH_FANCYCRYPT
+ * select PACKAGE_DRIVER_FANCYCRYPT
+ *
+ * config MODULE_PERIPH_HASH_SHA_256
+ * bool
+ * depends on HAS_PERIPH_HASH_SHA_256
+ * select MODULE_PERIPH_SPEEDYCRYPT
+ * select MODULE_PSA_SPEEDYCRYPT_HASHES_SHA256
+ * @endcode
+ *
+ * Here we basically say "If the user chooses the `periph_hash_sha_256 module`, also select the
+ * `periph_speedycrypt` feature, which will then enable the speedycrypt driver". Of course you need
+ * to do this for all your available features.
+ *
+ * Now, if you build PSA Crypto with default configurations, it should automatically detect that
+ * your board has a hardware accelerator for hashes and ECC operations and build the hardware
+ * driver as a backend.
+ *
+ * ### Case Example – A Secure Element Driver {#porting-secure-elements}
+ * Secure elements (SEs) are handled almost completely separate from the other backends. When we use
+ * software libraries or hardware drivers, we only build one implementation per algorithm.
+ * When it comes to secure elements we want to be able to build them in addition to the other
+ * backends and we may want to connect and use more than one of them at the same time.
+ * Another difference is that when using software libraries and hardware drivers, PSA handles the
+ * storage of key material. When using SEs, keys are stored on the SE, which means, we need
+ * additional functionality for the key management.
+ *
+ * An existing example in RIOT is the Microchip ATECCX08A device family, whose driver can be found
+ * in `pkg/cryptoauthlib`.
+ *
+ * PSA Crypto has an integrated SE driver registry, which stores all registered drivers in a list.
+ * When an application calls a cryptographic operation that's supposed to be performed by a secure
+ * element, the registry will find the correct driver in the list and PSA will invoke the operation.
+ * Each driver is stored with a context that contains persistent as well as transient driver data.
+ * Transient driver data can be anything the driver needs to function. Persistent data is supposed
+ * to be used to keep track of how many keys are stored on the device and if there is still some
+ * free space available.
+ *
+ * @note Currently PSA does not support persistent storage, so the persistent driver data
+ * is not really persistent, yet. Once persistent storage is implemented, this data
+ * will be stored, so the implementation can find already existing keys again after
+ * a reboot.
+ *
+ * For this example we integrate an imaginary SE called `superSE`, which comes with a driver called
+ * `superSE_lib`. Again, we assume that we have already added the driver as a package in RIOT and it
+ * can be found at `pkg/superse_lib`.
+ *
+ * #### Adding the Glue Code
+ * Secure element drivers need to implement a different API than the other backends. It is defined
+ * [here](#sys_psa_crypto_se_driver).
+ * In our package folder we now create a new folder called `psa_superse_driver` and add a source
+ * file called `psa_superse_lib_driver.c`. Here we now implement glue code for all the cryptographic
+ * operations our SE supports.
+ *
+ * You will notice that the SE interface also provides some key management functions. This is
+ * because keys are stored on the device and PSA can not access the memory and key data itself,
+ * but needs to tell the driver to do it.
+ *
+ * ### Operation Contexts
+ * Some operations need driver specific contexts. For secure elements these are wrapped in types
+ * defined in `crypto_contexts.h` (currently only `psa_se_cipher_context_t` is supported).
+ * In this header file add operation contexts that belong to your driver to the available SE
+ * context unions as shown in the example below:
+ *
+ * @code
+ * typedef struct {
+ * union driver_context {
+ * unsigned dummy;
+ * #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
+ * atca_aes_cbc_ctx_t atca_aes_cbc;
+ * #endif
+ * #if IS_USED(MODULE_PSA_SECURE_ELEMENT_SUPERSE) || defined(DOXYGEN)
+ * superse_cipher_ctx_t superse_aes_cbc;
+ * #endif
+ * } drv_ctx;
+ * } psa_se_cipher_context_t;
+ * @endcode
+ *
+ * #### Allocation
+ * The first thing PSA will do, when an application creates a key on an SE, is ask the driver to
+ * find a free key slot on the device. This is what the `allocate` function is for. How exactly
+ * the slot is allocated, depends on the driver.
+ * It may be possible to query that information directly from the device. If that is not possible,
+ * we can use the persistent data stored in the driver context. An example for this can be
+ * found in `pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c`.
+ * This example requires the user to provide information about the configurations for each key slot,
+ * which is then stored in the persistent driver data and used for key management (for a better
+ * description read [Using Cryptoauthlib as a backend for PSA Crypto](#psa-cryptoauthlib)).
+ * At this point you can decide what the best approach for your device is.
+ *
+ * The `allocate` function should then return some reference to the slot it has allocated
+ * for the key (possibly a pointer or a slot number). Next PSA Crypto will invoke the `import`
+ * or `generate` function to store a key.
+ *
+ * #### Using Persistent Data
+ * When you want to use persistent data to keep track of keys, you should utilize the
+ * `psa_se_config_t` structure, which is declared in `crypto_se_config.h`.
+ * You can define a structure that can hold your device configuration and make sure it is available
+ * then your SE is used.
+ *
+ * #### Making the Methods Available
+ * At the bottom of the wrapper code, define structures with pointers to the available methods.
+ * For example if you have implemented a `superse_allocate` and `superse_generate_key` function,
+ * you need to add a `psa_drv_se_key_management_t` structure as shown below. Fill the unimplemented
+ * methods with `NULL` pointers.
+ * The last structure should be a `psa_drv_se_t` struct containing pointers to the other structures.
+ * That one will be stored during driver registration to get access to all the implemented
+ * functions.
+ *
+ * @code {.c}
+ * static psa_drv_se_key_management_t superse_key_management = {
+ * .p_allocate = superse_allocate,
+ * .p_validate_slot_number = NULL,
+ * .p_import = NULL,
+ * .p_generate = superse_generate_key,
+ * .p_destroy = NULL,
+ * .p_export = NULL,
+ * .p_export_public = NULL
+ * };
+ *
+ * psa_drv_se_t superse_methods = {
+ * .hal_version = PSA_DRV_SE_HAL_VERSION,
+ * .persistent_data_size = 0,
+ * .p_init = NULL,
+ * .key_management = &superse_key_management,
+ * .mac = NULL,
+ * .cipher = NULL,
+ * .aead = NULL,
+ * .asymmetric = NULL,
+ * .derivation = NULL
+ * };
+ * @endcode
+ *
+ * You should do this for all available functions. The structures for the functions are
+ * declared in `sys/psa_crypto/include/psa_crypto_se_driver.h`.
+ *
+ * #### Driver Registration
+ * At start-up all secure element drivers need to be registered with the PSA SE management module.
+ * This happens by calling `psa_register_secure_element()` during the automatic driver
+ * initialization in RIOT.
+ * When you added support for our device to RIOT, you should have implemented an
+ * `auto_init_` function, which initializes the connected devices.
+ * In this function, after initializing a device, you should call `psa_register_secure_element()`
+ * and pass the device's location value, and pointers to the `psa_drv_se_t` structure,
+ * the persistent data and some device specific context.
+ * An example implementation of this can be seen in `sys/auto_init/security/auto_init_atca.c`.
+ *
+ * #### Telling PSA Crypto about it
+ * To be able to choose our `superSE` during configuration, we need to define the corresponding
+ * modules in the Kconfig files and Makefiles.
+ *
+ * To `pkg/super_se_lib/Kconfig` we add something like
+ * @code
+ * config MODULE_PSA_SUPERSE_DRIVER
+ * bool
+ * depends on PACKAGE_SUPERSE_LIB
+ * default y if MODULE_PSA_CRYPTO
+ * select PSA_KEY_MANAGEMENT
+ * @endcode
+ * This tells the build system that whenever this driver and PSA Crypto are used at the same time,
+ * the wrapper and the PSA key management module are needed, too.
+ *
+ * To `sys/psa_crypto/psa_se_mgmt/Kconfig` we add a menu for the SE like so:
+ * @code
+ * menuconfig MODULE_PSA_SECURE_ELEMENT_SUPERSE
+ * bool "Our Vendor's SuperSE"
+ * select PACKAGE_SUPERSE_LIB
+ * depends on
+ * help
+ *
+ * @endcode
+ * This makes our driver selectable whenever an application configuration selects the PSA secure
+ * element module.
+ *
+ * As described in the [Configuration Section](#configuration-keys), references to keys on secure
+ * elements are stored by PSA in a different type of key slot than other keys.
+ * The slot for protected keys usually only contains a slot number or address and not the actual
+ * key, which requires a lot less memory space.
+ *
+ * **BUT:** If your secure element supports asymmetric cryptography and exports a public key part
+ * during key generation, that key part must be stored somewhere. This is why there needs to be
+ * an option to tell PSA Crypto that an application is going to perform asymmetric operations.
+ * Only if that option is selected, the protected key slots will have the space to store a public
+ * key.
+ *
+ * For this we need to add the following to the `superSE` menu:
+ * @code
+ * config MODULE_PSA_SECURE_ELEMENT_SUPERSE_ECC_P256
+ * bool "Our Vendor's Elliptic Curve P256"
+ * select PSA_KEY_SIZE_256
+ * select MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC
+ * depends on MODULE_PSA_SECURE_ELEMENT_SUPERSE
+ * @endcode
+ * This tells us, what size a key slot should have to store the public key. If your SE supports
+ * other curves, you need to modify this accordingly or add more of them.
+ *
+ * Now we need to add the same to the Makefiles. In `Makefile.include` we add the source file path
+ * and the PSA include folders and define the new available pseudomodules:
+ * @code
+ * ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ * DIRS += $(RIOTPKG)/superse_lib/psa_superse_driver
+ * INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
+ * PSEUDOMODULES += psa_secure_element_superse
+ * PSEUDOMODULES += psa_secure_element_superse_ecc_p256
+ * endif
+ * @endcode
+ *
+ * In `Makefile.dep` we automatically add required modules when PSA Crypto and the ECC curve
+ * module are chosen:
+ * @code
+ * ifneq (,$(filter psa_crypto,$(USEMODULE)))
+ * USEMODULE += psa_superse_driver
+ * endif
+ *
+ * ifneq (,$(filter psa_secure_element_superse_ecc_p256, $(USEMODULE)))
+ * USEMODULE += psa_secure_element_asymmetric
+ * endif
+ *
+ * Now the secure element should be available for use with PSA Crypto.
+ * @endcode
+ */
diff --git a/sys/psa_crypto/include/psa_ciphers.h b/sys/psa_crypto/include/psa_ciphers.h
new file mode 100644
index 0000000000..65c5601b92
--- /dev/null
+++ b/sys/psa_crypto/include/psa_ciphers.h
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_cipher PSA Wrapper Functions: Cipher
+ * @{
+ *
+ * @file psa_ciphers.h
+ * @brief Function declarations for low level wrapper functions for cipher operations.
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CIPHERS_H
+#define PSA_CIPHERS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "psa/crypto.h"
+#include "psa/crypto_contexts.h"
+
+/**
+ * @brief Low level wrapper function to call a driver for an AES 128 CBC encryption.
+ * See @ref psa_cipher_encrypt()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param alg
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_cipher_cbc_aes_128_encrypt(const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ psa_algorithm_t alg,
+ 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 an AES 128 CBC decryption.
+ * See @ref psa_cipher_decrypt()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param alg
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_cipher_cbc_aes_128_decrypt(const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ psa_algorithm_t alg,
+ 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 an AES 192 CBC encryption.
+ * See @ref psa_cipher_encrypt()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param alg
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_cipher_cbc_aes_192_encrypt(const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ psa_algorithm_t alg,
+ 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 an AES 256 CBC encryption.
+ * See @ref psa_cipher_encrypt()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param alg
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return psa_status_t
+ */
+psa_status_t psa_cipher_cbc_aes_256_encrypt(const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CIPHERS_H */
+/** @} */
diff --git a/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h b/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h
new file mode 100644
index 0000000000..3e70dd5335
--- /dev/null
+++ b/sys/psa_crypto/include/psa_crypto_algorithm_dispatch.h
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_alg_disp PSA Crypto Algorithm Dispatcher
+ * @{
+ *
+ * @file psa_crypto_algorithm_dispatch.h
+ * @brief Function declarations for PSA Crypto algorithm dispatcher
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_ALGORITHM_DISPATCH_H
+#define PSA_CRYPTO_ALGORITHM_DISPATCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include "kernel_defines.h"
+#include "psa/crypto.h"
+#include "psa_crypto_slot_management.h"
+
+/**
+ * @brief Dispatch a hash setup function to a specific backend.
+ * See @ref psa_hash_setup()
+ *
+ * @param operation
+ * @param alg
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_hash_setup(psa_hash_operation_t *operation,
+ psa_algorithm_t alg);
+
+/**
+ * @brief Dispatch a hash update function to a specific backend.
+ * See @ref psa_hash_update()
+ *
+ * @param operation
+ * @param input
+ * @param input_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_hash_update(psa_hash_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Dispatch a hash finish function to a specific backend.
+ * See @ref psa_hash_finish()
+ *
+ * @param operation
+ * @param hash
+ * @param hash_size
+ * @param hash_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_hash_finish(psa_hash_operation_t *operation,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+
+/**
+ * @brief Dispatch a hash signature function to a specific backend.
+ * See @ref psa_sign_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_size
+ * @param signature_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_sign_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * @brief Dispatch a hash verification function to a specific backend.
+ * See @ref psa_verify_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_verify_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length);
+
+/**
+ * @brief Dispatch the key generation function to a specific backend.
+ * See @ref psa_generate_key()
+ *
+ * @param attributes
+ * @param slot
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes,
+ psa_key_slot_t *slot);
+
+/**
+ * @brief Dispatch a cipher encrypt function to a specific backend.
+ * See @ref psa_cipher_encrypt()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Dispatch a cipher decrypt function to a specific backend.
+ * See @ref psa_cipher_decrypt()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Dispatch a mac computation function to a specific backend.
+ * See @ref psa_mac_compute()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param mac
+ * @param mac_size
+ * @param mac_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_algorithm_dispatch_mac_compute(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_ALGORITHM_DISPATCH_H */
+/** @} */
diff --git a/sys/psa_crypto/include/psa_crypto_location_dispatch.h b/sys/psa_crypto/include/psa_crypto_location_dispatch.h
new file mode 100644
index 0000000000..a6ff3c7099
--- /dev/null
+++ b/sys/psa_crypto/include/psa_crypto_location_dispatch.h
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_loc_disp PSA Crypto Location Dispatcher
+ * @{
+ *
+ * @file psa_crypto_location_dispatch.h
+ * @brief Function declarations for the PSA Crypto location dispatcher.
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_LOCATION_DISPATCH_H
+#define PSA_CRYPTO_LOCATION_DISPATCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include "kernel_defines.h"
+#include "psa/crypto.h"
+
+/**
+ * @brief Dispatch call of a hash signature function to a location specific backend.
+ * See psa_sign_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_size
+ * @param signature_length
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * @brief Dispatch call of a hash verification function to a location specific backend.
+ * See psa_verify_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_length
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_verify_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length);
+
+/**
+ * @brief Dispatch call of a mac computation function to a location specific backend.
+ * See psa_mac_compute()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param mac
+ * @param mac_size
+ * @param mac_length
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+
+/**
+ * @brief Dispatch call of the key generation function to a location specific backend.
+ * See psa_generate_key()
+ *
+ * @param attributes
+ * @param slot
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes,
+ psa_key_slot_t *slot);
+
+/**
+ * @brief Dispatch call of the key import function to a location specific backend.
+ * See psa_import_key()
+ *
+ * @param attributes
+ * @param data
+ * @param data_length
+ * @param slot
+ * @param bits
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes,
+ const uint8_t *data, size_t data_length,
+ psa_key_slot_t *slot, size_t *bits);
+
+/**
+ * @brief Dispatch call of a cipher encrypt setup function to a location specific backend.
+ * See psa_cipher_setup()
+ *
+ * @param operation
+ * @param attributes
+ * @param slot
+ * @param alg
+ * @return psa_status_t
+ */
+psa_status_t psa_location_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()
+ *
+ * @param operation
+ * @param attributes
+ * @param slot
+ * @param alg
+ * @return psa_status_t
+ */
+psa_status_t psa_location_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 function to set a cipher IV to a location specific backend.
+ * See psa_cipher_set_iv()
+ *
+ * @param operation
+ * @param iv
+ * @param iv_length
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_cipher_set_iv( psa_cipher_operation_t *operation,
+ const uint8_t *iv,
+ size_t iv_length);
+
+/**
+ * @brief Dispatch call of a cipher encrypt function to a location specific backend.
+ * See psa_cipher_encrypt()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Dispatch call of a cipher decrypt function to a location specific backend.
+ * See psa_cipher_decrypt()
+ *
+ * @param attributes
+ * @param alg
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length);
+
+/**
+ * @brief Dispatch call of a random number generator to a specific backend.
+ * See psa_generate_random()
+ *
+ * @param output
+ * @param output_size
+ * @return psa_status_t
+ */
+psa_status_t psa_location_dispatch_generate_random(uint8_t *output,
+ size_t output_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_LOCATION_DISPATCH_H */
+/** @} */
diff --git a/sys/psa_crypto/include/psa_crypto_operation_encoder.h b/sys/psa_crypto/include/psa_crypto_operation_encoder.h
new file mode 100644
index 0000000000..bcac6c80fa
--- /dev/null
+++ b/sys/psa_crypto/include/psa_crypto_operation_encoder.h
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file psa_crypto_operation_encoder.h
+ * @brief Macros used to map PSA akgorithms, key types and key sizes to specific key types
+ * and operations to call the corresponding driver functions.
+ *
+ * @note Currently this only supports a small number of operations. It should be expanded as
+ * needed as this implementation increases support for more operations.
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_OPERATION_ENCODER_H
+#define PSA_CRYPTO_OPERATION_ENCODER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "psa/crypto.h"
+#include "psa_crypto_slot_management.h"
+
+/**
+ * @brief Unknown or invalid operation
+ */
+#define PSA_INVALID_OPERATION (0xFF)
+
+/**
+ * @brief Enum encoding available cipher operations.
+ *
+ * @details To be expanded with the development of this implementation.
+ */
+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_cipher_op_t;
+
+/**
+ * @brief Enum encoding available asymmetric key types and sizes.
+ *
+ * @details To be expanded with the development of this implementation.
+ */
+typedef enum {
+ PSA_ECC_P160_K1,
+ PSA_ECC_P160_R1,
+ PSA_ECC_P160_R2,
+ PSA_ECC_P192_K1,
+ PSA_ECC_P192_R1,
+ PSA_ECC_P224_K1,
+ PSA_ECC_P224_R1,
+ PSA_ECC_P256_K1,
+ PSA_ECC_P256_R1,
+ PSA_ECC_P384_R1,
+ PSA_ECC_P521_R1,
+ PSA_ECC_FRP,
+ PSA_ECMONT_255,
+ PSA_ECMONT_448
+} psa_asym_key_t;
+
+/**
+ * @brief Combine an ECC 192 key type with a given curve.
+ *
+ * @param curve Must be a curve of type @ref psa_ecc_family_t
+ *
+ * @return @ref psa_asym_key_t
+ * @return @ref PSA_INVALID_OPERATION @c curve is not compatible with key size
+ */
+#define GET_ECC_KEY_TYPE_192(curve) \
+ ((curve == PSA_ECC_FAMILY_SECP_R1) ? PSA_ECC_P192_R1 : \
+ PSA_INVALID_OPERATION)
+
+/**
+ * @brief Combine an ECC 265 key type with a given curve.
+ *
+ * @param curve Must be a curve of type @ref psa_ecc_family_t
+ *
+ * @return @ref psa_asym_key_t
+ * @return @ref PSA_INVALID_OPERATION @c curve is not compatible with key size
+ */
+#define GET_ECC_KEY_TYPE_256(curve) \
+ ((curve == PSA_ECC_FAMILY_SECP_R1) ? PSA_ECC_P256_R1 : \
+ PSA_INVALID_OPERATION)
+
+/**
+ * @brief Map an ECC 192 key to a given curve according to its type and size.
+ *
+ * @param bits Key size of type @ref psa_key_bits_t
+ * @param curve Must be a curve of type @ref psa_ecc_family_t
+ *
+ * @return @ref psa_asym_key_t
+ * @return @ref PSA_INVALID_OPERATION @c curve and @c bits are incompatible
+ */
+#define PSA_ENCODE_ECC_KEY_TYPE(bits, curve) \
+ ((bits == 256) || (bits == 520) ? GET_ECC_KEY_TYPE_256(curve) : \
+ (bits == 192) || (bits == 392) ? GET_ECC_KEY_TYPE_192(curve) : \
+ PSA_INVALID_OPERATION)
+
+/**
+ * @brief Combine algorithm, and key type with a key size of 128 bits.
+ *
+ * @param alg Algorithm of type @ref psa_algorithm_t.
+ * @param type Key type of type @ref psa_key_type_t
+ *
+ * @return @ref psa_cipher_op_t
+ * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size
+ */
+#define GET_CIPHER_OPERATION_128(alg, type) \
+ (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_128 : \
+ PSA_INVALID_OPERATION)
+
+/**
+ * @brief Combine algorithm, and key type with a key size of 192 bits.
+ *
+ * @param alg Algorithm of type @ref psa_algorithm_t.
+ * @param type Key type of type @ref psa_key_type_t
+ *
+ * @return @ref psa_cipher_op_t
+ * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size
+ */
+#define GET_CIPHER_OPERATION_192(alg, type) \
+ (((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_192 : \
+ PSA_INVALID_OPERATION)
+
+/**
+ * @brief Combine algorithm, and key type with a key size of 256 bits.
+ *
+ * @param alg Algorithm of type @ref psa_algorithm_t.
+ * @param type Key type of type @ref psa_key_type_t
+ *
+ * @return @ref psa_cipher_op_t
+ * @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size
+ */
+#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 : \
+ 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
+ *
+ * @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) : \
+ PSA_INVALID_OPERATION)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_OPERATION_ENCODER_H */
+/** @} */
diff --git a/sys/psa_crypto/include/psa_crypto_se_driver.h b/sys/psa_crypto/include/psa_crypto_se_driver.h
new file mode 100644
index 0000000000..cb856e4d8d
--- /dev/null
+++ b/sys/psa_crypto/include/psa_crypto_se_driver.h
@@ -0,0 +1,1314 @@
+/*
+ * Copyright The Mbed TLS Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_se_driver PSA Crypto Secure Element Wrapper
+ * @{
+ *
+ * @file psa_crypto_se_driver.h
+ * @brief PSA external cryptoprocessor driver module
+ *
+ * @details This header declares types and function signatures for cryptography
+ * drivers that access key material via opaque references.
+ * This is meant for cryptoprocessors that have a separate key storage from the
+ * space in which the PSA Crypto implementation runs, typically secure
+ * elements (SEs).
+ *
+ * This file is part of the PSA Crypto Driver HAL (hardware abstraction layer),
+ * containing functions for driver developers to implement to enable hardware
+ * to be called in a standardized way by a PSA Cryptography API
+ * implementation. The functions comprising the driver HAL, which driver
+ * authors implement, are not intended to be called by application developers.
+ */
+
+#ifndef PSA_CRYPTO_SE_DRIVER_H
+#define PSA_CRYPTO_SE_DRIVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+#include "psa/crypto_values.h"
+#include "psa/crypto_types.h"
+
+/**
+ * @brief Maximum size of persistent driver data in bytes
+ */
+#define PSA_MAX_PERSISTENT_DATA_SIZE (16)
+
+/**
+ * @defgroup se_init Secure Element Driver Initialization
+ */
+/**@{*/
+
+/**
+ * @brief Driver context structure
+ *
+ * @details Driver functions receive a pointer to this structure.
+ * Each registered driver has one instance of this structure.
+ *
+ * Implementations must include the fields specified here and
+ * may include other fields.
+ */
+typedef struct {
+ /**
+ * A read-only pointer to the driver's persistent data.
+ *
+ * Drivers typically use this persistent data to keep track of
+ * which slot numbers are available. This is only a guideline:
+ * drivers may use the persistent data for any purpose, keeping
+ * in mind the restrictions on when the persistent data is saved
+ * to storage: the persistent data is only saved after calling
+ * certain functions that receive a writable pointer to the
+ * persistent data.
+ *
+ * The core allocates a memory buffer for the persistent data.
+ * The pointer is guaranteed to be suitably aligned for any data type,
+ * like a pointer returned by @c malloc (but the core can use any
+ * method to allocate the buffer, not necessarily @c malloc).
+ *
+ * The size of this buffer is in the @c persistent_data_size field of
+ * this structure.
+ *
+ * Before the driver is initialized for the first time, the content of
+ * the persistent data is all-bits-zero. After a driver upgrade, if the
+ * size of the persistent data has increased, the original data is padded
+ * on the right with zeros; if the size has decreased, the original data
+ * is truncated to the new size.
+ *
+ * This pointer is to read-only data. Only a few driver functions are
+ * allowed to modify the persistent data. These functions receive a
+ * writable pointer. These functions are:
+ * - @ref psa_drv_se_t::p_init
+ * - @ref psa_drv_se_key_management_t::p_allocate
+ * - @ref psa_drv_se_key_management_t::p_destroy
+ *
+ * The PSA Cryptography core saves the persistent data from one
+ * session to the next. It does this before returning from API functions
+ * that call a driver method that is allowed to modify the persistent
+ * data, specifically:
+ * - @ref psa_crypto_init() causes a call to @ref psa_drv_se_t::p_init, and may call
+ * @ref psa_drv_se_key_management_t::p_destroy to complete an action that was
+ * interrupted by a power failure.
+ * - Key creation functions cause a call to @ref psa_drv_se_key_management_t::p_allocate,
+ * and may cause a call to @ref psa_drv_se_key_management_t::p_destroy in case an error
+ * occurs.
+ * - @ref psa_destroy_key() causes a call to @ref psa_drv_se_key_management_t::p_destroy.
+ */
+ const void * persistent_data;
+
+ /**
+ * The size of @c persistent_data in bytes.
+ *
+ * This is always equal to the value of the @c persistent_data_size field
+ * of the @ref psa_drv_se_t structure when the driver is registered.
+ */
+ const size_t persistent_data_size;
+
+ /**
+ * Driver transient data.
+ *
+ * The core initializes this value to 0 and does not read or modify it
+ * afterwards. The driver may store whatever it wants in this field.
+ */
+ uintptr_t transient_data;
+} psa_drv_se_context_t;
+
+/**
+ * @brief A driver initialization function.
+ *
+ * @param drv_context The driver context structure.
+ * @param persistent_data A pointer to the persistent data
+ * that allows writing.
+ * @param location The location value for which this driver
+ * is registered. The driver will be invoked
+ * for all keys whose lifetime is in this
+ * location.
+ *
+ * @return @ref PSA_SUCCESS The driver is operational.
+ * The core will update the persistent data in storage.
+ * Any other return value prevents the driver from being used in
+ * this session.
+ * The core will NOT update the persistent data in storage.
+ */
+typedef psa_status_t (*psa_drv_se_init_t)(psa_drv_se_context_t *drv_context,
+ void *persistent_data,
+ psa_key_location_t location);
+
+/**
+ * @brief Encoding of a key slot number on a secure element.
+ */
+typedef uint64_t psa_key_slot_number_t;
+/**@}*/
+
+/**
+ * @defgroup se_mac Secure Element Message Authentication Codes
+ *
+ * @details Generation and authentication of Message Authentication Codes (MACs)
+ * using a secure element can be done either as a single function call
+ * (via the `psa_drv_se_mac_generate_t` or `psa_drv_se_mac_verify_t` functions),
+ * or in parts using the following sequence:
+ * - `psa_drv_se_mac_setup_t`
+ * - `psa_drv_se_mac_update_t`
+ * - `psa_drv_se_mac_update_t`
+ * - ...
+ * - `psa_drv_se_mac_finish_t` or `psa_drv_se_mac_finish_verify_t`
+ *
+ * If a previously started secure element MAC operation needs to be terminated,
+ * it should be done so by the `psa_drv_se_mac_abort_t`. Failure to do so may
+ * result in allocated resources not being freed or in other undefined
+ * behavior.
+ * @{
+ */
+
+/**
+ * @brief A function that starts a secure element MAC operation for a PSA
+ * Crypto Driver implementation
+ *
+ * @param drv_context The driver context structure.
+ * @param op_context A structure that will contain the
+ * hardware-specific MAC context
+ * @param key_slot The slot of the key to be used for the
+ * operation
+ * @param algorithm The algorithm to be used to underly the MAC
+ * operation
+ *
+ * @return @ref PSA_SUCCESS Success.
+ *
+ */
+typedef psa_status_t (*psa_drv_se_mac_setup_t)(psa_drv_se_context_t *drv_context,
+ void *op_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t algorithm);
+
+/**
+ * @brief A function that continues a previously started secure element MAC
+ * operation
+ *
+ * @param op_context A hardware-specific structure for the
+ * previously-established MAC operation to be
+ * updated
+ * @param p_input A buffer containing the message to be appended
+ * to the MAC operation
+ * @param input_length The size in bytes of the input message buffer
+ */
+typedef psa_status_t (*psa_drv_se_mac_update_t)(void *op_context,
+ const uint8_t *p_input,
+ size_t input_length);
+
+/**
+ * @brief A function that completes a previously started secure element MAC
+ * operation by returning the resulting MAC.
+ *
+ * @param op_context A hardware-specific structure for the
+ * previously started MAC operation to be
+ * finished
+ * @param p_mac A buffer where the generated MAC will be
+ * placed
+ * @param mac_size The size in bytes of the buffer that has been
+ * allocated for the @c output buffer
+ * @param p_mac_length After completion, will contain the number of
+ * bytes placed in the @c p_mac buffer
+ *
+ * @return @ref PSA_SUCCESS Success.
+ */
+typedef psa_status_t (*psa_drv_se_mac_finish_t)(void *op_context,
+ uint8_t *p_mac,
+ size_t mac_size,
+ size_t *p_mac_length);
+
+/**
+ * @brief A function that completes a previously started secure element MAC
+ * operation by comparing the resulting MAC against a provided value
+ *
+ * @param op_context A hardware-specific structure for the previously
+ * started MAC operation to be fiinished
+ * @param p_mac The MAC value against which the resulting MAC
+ * will be compared against
+ * @param mac_length The size in bytes of the value stored in @c p_mac
+ *
+ * @return @ref PSA_SUCCESS The operation completed successfully and the MACs
+ * matched each other
+ * @ref PSA_ERROR_INVALID_SIGNATURE The operation completed successfully, but the
+ * calculated MAC did not match the provided MAC
+ */
+typedef psa_status_t (*psa_drv_se_mac_finish_verify_t)(void *op_context,
+ const uint8_t *p_mac,
+ size_t mac_length);
+
+/** @brief A function that aborts a previous started secure element MAC
+ * operation
+ *
+ * @param op_context A hardware-specific structure for the previously
+ * started MAC operation to be aborted
+ */
+typedef psa_status_t (*psa_drv_se_mac_abort_t)(void *op_context);
+
+/**
+ * @brief A function that performs a secure element MAC operation in one
+ * command and returns the calculated MAC
+ *
+ * @param drv_context The driver context structure.
+ * @param p_input A buffer containing the message to be MACed
+ * @param input_length The size in bytes of @c p_input
+ * @param key_slot The slot of the key to be used
+ * @param alg The algorithm to be used to underlie the MAC
+ * operation
+ * @param p_mac A buffer where the generated MAC will be
+ * placed
+ * @param mac_size The size in bytes of the @c p_mac buffer
+ * @param p_mac_length After completion, will contain the number of
+ * bytes placed in the @c output buffer
+ *
+ * @return @ref PSA_SUCCESS Success.
+ */
+typedef psa_status_t (*psa_drv_se_mac_generate_t)(psa_drv_se_context_t *drv_context,
+ const uint8_t *p_input,
+ size_t input_length,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t alg,
+ uint8_t *p_mac,
+ size_t mac_size,
+ size_t *p_mac_length);
+
+/**
+ * @brief A function that performs a secure element MAC operation in one
+ * command and compares the resulting MAC against a provided value
+ *
+ * @param drv_context The driver context structure.
+ * @param p_input A buffer containing the message to be MACed
+ * @param input_length The size in bytes of @c input
+ * @param key_slot The slot of the key to be used
+ * @param alg The algorithm to be used to underlie the MAC
+ * operation
+ * @param p_mac The MAC value against which the resulting MAC will
+ * be compared against
+ * @param mac_length The size in bytes of @c p_mac
+ *
+ * @return @ref PSA_SUCCESS The operation completed successfully and the MACs
+ * matched each other
+ * @ref PSA_ERROR_INVALID_SIGNATURE The operation completed successfully, but the
+ * calculated MAC did not match the provided MAC
+ */
+typedef psa_status_t (*psa_drv_se_mac_verify_t)(psa_drv_se_context_t *drv_context,
+ const uint8_t *p_input,
+ size_t input_length,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t alg,
+ const uint8_t *p_mac,
+ size_t mac_length);
+
+/**
+ * @brief A struct containing all of the function pointers needed to
+ * perform secure element MAC operations
+ *
+ * @details PSA Crypto API implementations should populate the table as appropriate
+ * upon startup.
+ *
+ * If one of the functions is not implemented (such as
+ * @ref psa_drv_se_mac_generate_t), it should be set to NULL.
+ *
+ * Driver implementers should ensure that they implement all of the functions
+ * that make sense for their hardware, and that they provide a full solution
+ * (for example, if they support @c p_setup, they should also support
+ * @c p_update and at least one of @c p_finish or @c p_finish_verify ).
+ *
+ */
+typedef struct {
+ /** The size in bytes of the hardware-specific secure element MAC context structure */
+ size_t context_size;
+ /** Function that performs a MAC setup operation */
+ psa_drv_se_mac_setup_t p_setup;
+ /** Function that performs a MAC update operation */
+ psa_drv_se_mac_update_t p_update;
+ /** Function that completes a MAC operation */
+ psa_drv_se_mac_finish_t p_finish;
+ /** Function that completes a MAC operation with a verify check */
+ psa_drv_se_mac_finish_verify_t p_finish_verify;
+ /** Function that aborts a previoustly started MAC operation */
+ psa_drv_se_mac_abort_t p_abort;
+ /** Function that performs a MAC operation in one call */
+ psa_drv_se_mac_generate_t p_mac;
+ /** Function that performs a MAC and verify operation in one call */
+ psa_drv_se_mac_verify_t p_mac_verify;
+} psa_drv_se_mac_t;
+/**@}*/
+
+/**
+ * @defgroup se_cipher Secure Element Symmetric Ciphers
+ *
+ * @details Encryption and Decryption using secure element keys in block modes other
+ * than ECB must be done in multiple parts, using the following flow:
+ * - @ref psa_drv_se_cipher_setup_t
+ * - @ref psa_drv_se_cipher_set_iv_t (optional depending upon block mode)
+ * - @ref psa_drv_se_cipher_update_t
+ * - @ref psa_drv_se_cipher_update_t
+ * - ...
+ * - @ref psa_drv_se_cipher_finish_t
+ *
+ * If a previously started secure element Cipher operation needs to be
+ * terminated, it should be done so by the @ref psa_drv_se_cipher_abort_t. Failure
+ * to do so may result in allocated resources not being freed or in other
+ * undefined behavior.
+ *
+ * In situations where a PSA Cryptographic API implementation is using a block
+ * mode not-supported by the underlying hardware or driver, it can construct
+ * the block mode itself, while calling the @ref psa_drv_se_cipher_ecb_t function
+ * for the cipher operations.
+ * @{
+ */
+
+/**
+ * @brief A function that provides the cipher setup function for a
+ * secure element driver
+ *
+ * @param drv_context The driver context structure.
+ * @param op_context A structure that will contain the
+ * hardware-specific cipher context.
+ * @param key_slot The slot of the key to be used for the
+ * operation
+ * @param algorithm The algorithm to be used in the cipher
+ * operation
+ * @param direction Indicates whether the operation is an encrypt
+ * or decrypt
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ */
+typedef psa_status_t (*psa_drv_se_cipher_setup_t)(psa_drv_se_context_t *drv_context,
+ void *op_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t algorithm,
+ psa_encrypt_or_decrypt_t direction);
+
+/**
+ * @brief A function that sets the initialization vector (if necessary) for an secure element
+ * cipher operation
+ *
+ * @details Rationale: The @c psa_se_cipher_* operation in the PSA Cryptographic API has
+ * two IV functions: one to set the IV, and one to generate it internally. The
+ * generate function is not necessary for the drivers to implement as the PSA
+ * Crypto implementation can do the generation using its RNG features.
+ *
+ * @param op_context A structure that contains the previously set up
+ * hardware-specific cipher context
+ * @param p_iv A buffer containing the initialization vector
+ * @param iv_length The size (in bytes) of the @c p_iv buffer
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_cipher_set_iv_t)(void *op_context,
+ const uint8_t *p_iv,
+ size_t iv_length);
+
+/**
+ * @brief A function that continues a previously started secure element cipher
+ * operation
+ *
+ * @param op_context A hardware-specific structure for the
+ * previously started cipher operation
+ * @param p_input A buffer containing the data to be
+ * encrypted/decrypted
+ * @param input_size The size in bytes of the buffer pointed to
+ * by @c p_input
+ * @param p_output The caller-allocated buffer where the
+ * output will be placed
+ * @param output_size The allocated size in bytes of the
+ * @c p_output buffer
+ * @param p_output_length After completion, will contain the number
+ * of bytes placed in the @c p_output buffer
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_cipher_update_t)(void *op_context,
+ const uint8_t *p_input,
+ size_t input_size,
+ uint8_t *p_output,
+ size_t output_size,
+ size_t *p_output_length);
+
+/**
+ * @brief A function that completes a previously started secure element cipher
+ * operation
+ *
+ * @param op_context A hardware-specific structure for the
+ * previously started cipher operation
+ * @param p_output The caller-allocated buffer where the output
+ * will be placed
+ * @param output_size The allocated size in bytes of the @c p_output
+ * buffer
+ * @param p_output_length After completion, will contain the number of
+ * bytes placed in the @c p_output buffer
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_cipher_finish_t)(void *op_context,
+ uint8_t *p_output,
+ size_t output_size,
+ size_t *p_output_length);
+
+/**
+ * @brief A function that aborts a previously started secure element cipher
+ * operation
+ *
+ * @param op_context A hardware-specific structure for the
+ * previously started cipher operation
+ */
+typedef psa_status_t (*psa_drv_se_cipher_abort_t)(void *op_context);
+
+/**
+ * @brief A function that performs the ECB block mode for secure element
+ * cipher operations
+ *
+ * @note This function should only be used with implementations that do not
+ * provide a needed higher-level operation.
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot The slot of the key to be used for the operation
+ * @param algorithm The algorithm to be used in the cipher operation
+ * @param direction Indicates whether the operation is an encrypt or
+ * decrypt
+ * @param p_input A buffer containing the data to be
+ * encrypted/decrypted
+ * @param input_size The size in bytes of the buffer pointed to by
+ * @c input
+ * @param p_output The caller-allocated buffer where the output
+ * will be placed
+ * @param output_size The allocated size in bytes of the @c output
+ * buffer
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ */
+typedef psa_status_t (*psa_drv_se_cipher_ecb_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t algorithm,
+ psa_encrypt_or_decrypt_t direction,
+ const uint8_t *p_input,
+ size_t input_size,
+ uint8_t *p_output,
+ size_t output_size);
+
+/**
+ * @brief A struct containing all of the function pointers needed to implement
+ * cipher operations using secure elements.
+ *
+ * @details PSA Crypto API implementations should populate instances of the table as
+ * appropriate upon startup or at build time.
+ *
+ * If one of the functions is not implemented (such as
+ * @c psa_drv_se_cipher_ecb_t ), it should be set to NULL.
+ */
+typedef struct {
+ /** The size in bytes of the hardware-specific secure element cipher context structure */
+ size_t context_size;
+ /** Function that performs a cipher setup operation */
+ psa_drv_se_cipher_setup_t p_setup;
+ /** Function that sets a cipher IV (if necessary) */
+ psa_drv_se_cipher_set_iv_t p_set_iv;
+ /** Function that performs a cipher update operation */
+ psa_drv_se_cipher_update_t p_update;
+ /** Function that completes a cipher operation */
+ psa_drv_se_cipher_finish_t p_finish;
+ /** Function that aborts a cipher operation */
+ psa_drv_se_cipher_abort_t p_abort;
+ /**
+ * Function that performs ECB mode for a cipher operation
+ * @warning ECB mode should not be used directly by clients of the PSA
+ * Crypto Client API)
+ */
+ psa_drv_se_cipher_ecb_t p_ecb;
+} psa_drv_se_cipher_t;
+
+/**@}*/
+
+/**
+ * @defgroup se_asymmetric Secure Element Asymmetric Cryptography
+ *
+ * @details Since the amount of data that can (or should) be encrypted or signed using
+ * asymmetric keys is limited by the key size, asymmetric key operations using
+ * keys in a secure element must be done in single function calls.
+ * @{
+ */
+
+/**
+ * @brief A function that signs a hash or short message with a private key in
+ * a secure element
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Key slot of an asymmetric key pair
+ * @param alg A signature algorithm that is compatible
+ * with the type of @c key
+ * @param p_hash The hash to sign
+ * @param hash_length Size of the @c p_hash buffer in bytes
+ * @param p_signature Buffer where the signature is to be written
+ * @param signature_size Size of the @c p_signature buffer in bytes
+ * @param p_signature_length On success, the number of bytes
+ * that make up the returned signature value
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_asymmetric_sign_t)( psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t alg,
+ const uint8_t *p_hash,
+ size_t hash_length,
+ uint8_t *p_signature,
+ size_t signature_size,
+ size_t *p_signature_length);
+
+/**
+ * @brief A function that verifies the signature a hash or short message using
+ * an asymmetric public key in a secure element
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Key slot of a public key or an asymmetric key
+ * pair
+ * @param alg A signature algorithm that is compatible with
+ * the type of @c key
+ * @param p_hash The hash whose signature is to be verified
+ * @param hash_length Size of the @c p_hash buffer in bytes
+ * @param p_signature Buffer containing the signature to verify
+ * @param signature_length Size of the @c p_signature buffer in bytes
+ *
+ * @return @ref PSA_SUCCESS The signature is valid.
+ */
+typedef psa_status_t (*psa_drv_se_asymmetric_verify_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t alg,
+ const uint8_t *p_hash,
+ size_t hash_length,
+ const uint8_t *p_signature,
+ size_t signature_length);
+
+/**
+ * @brief A function that encrypts a short message with an asymmetric public
+ * key in a secure element
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Key slot of a public key or an asymmetric key pair
+ * @param alg An asymmetric encryption algorithm that is compatible
+ * with the type of @c key
+ * @param p_input The message to encrypt
+ * @param input_length Size of the @c p_input buffer in bytes
+ * @param p_salt A salt or label, if supported by the
+ * encryption algorithm
+ * If the algorithm does not support a
+ * salt, pass @c NULL.
+ * If the algorithm supports an optional
+ * salt and you do not want to pass a salt,
+ * pass @c NULL.
+ * For @ref PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is
+ * supported.
+ * @param salt_length Size of the @c p_salt buffer in bytes
+ * If @c p_salt is @c NULL, pass 0.
+ * @param p_output Buffer where the encrypted message is to
+ * be written
+ * @param output_size Size of the @c p_output buffer in bytes
+ * @param p_output_length On success, the number of bytes that make up
+ * the returned output
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_asymmetric_encrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t alg,
+ const uint8_t *p_input,
+ size_t input_length,
+ const uint8_t *p_salt,
+ size_t salt_length,
+ uint8_t *p_output,
+ size_t output_size,
+ size_t *p_output_length);
+
+/**
+ * @brief A function that decrypts a short message with an asymmetric private
+ * key in a secure element.
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Key slot of an asymmetric key pair
+ * @param alg An asymmetric encryption algorithm that is
+ * compatible with the type of @c key
+ * @param p_input The message to decrypt
+ * @param input_length Size of the @c p_input buffer in bytes
+ * @param p_salt A salt or label, if supported by the
+ * encryption algorithm
+ * If the algorithm does not support a
+ * salt, pass @c NULL.
+ * If the algorithm supports an optional
+ * salt and you do not want to pass a salt,
+ * pass @c NULL.
+ * For #PSA_ALG_RSA_PKCS1V15_CRYPT, no salt is
+ * supported.
+ * @param salt_length Size of the @c p_salt buffer in bytes
+ * If @c p_salt is @c NULL, pass 0.
+ * @param p_output Buffer where the decrypted message is to
+ * be written
+ * @param output_size Size of the @c p_output buffer in bytes
+ * @param p_output_length On success, the number of bytes
+ * that make up the returned output
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_asymmetric_decrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t alg,
+ const uint8_t *p_input,
+ size_t input_length,
+ const uint8_t *p_salt,
+ size_t salt_length,
+ uint8_t *p_output,
+ size_t output_size,
+ size_t *p_output_length);
+
+/**
+ * @brief A struct containing all of the function pointers needed to implement
+ * asymmetric cryptographic operations using secure elements.
+ *
+ * @details PSA Crypto API implementations should populate instances of the table as
+ * appropriate upon startup or at build time.
+ *
+ * If one of the functions is not implemented, it should be set to @c NULL.
+ */
+typedef struct {
+ /** Function that performs an asymmetric sign operation */
+ psa_drv_se_asymmetric_sign_t p_sign;
+ /** Function that performs an asymmetric verify operation */
+ psa_drv_se_asymmetric_verify_t p_verify;
+ /** Function that performs an asymmetric encrypt operation */
+ psa_drv_se_asymmetric_encrypt_t p_encrypt;
+ /** Function that performs an asymmetric decrypt operation */
+ psa_drv_se_asymmetric_decrypt_t p_decrypt;
+} psa_drv_se_asymmetric_t;
+
+/**@}*/
+
+/**
+ * @defgroup se_aead Secure Element Authenticated Encryption with Additional Data
+ *
+ * @details Authenticated Encryption with Additional Data (AEAD) operations with secure
+ * elements must be done in one function call. While this creates a burden for
+ * implementers as there must be sufficient space in memory for the entire
+ * message, it prevents decrypted data from being made available before the
+ * authentication operation is complete and the data is known to be authentic.
+ * @{
+ */
+
+/**
+ * @brief A function that performs a secure element authenticated encryption operation
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Slot containing the key to use.
+ * @param algorithm The AEAD algorithm to compute
+ * (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true)
+ * @param p_nonce Nonce or IV to use
+ * @param nonce_length Size of the @c p_nonce buffer in bytes
+ * @param p_additional_data Additional data that will be
+ * authenticated but not encrypted
+ * @param additional_data_length Size of @c p_additional_data in bytes
+ * @param p_plaintext Data that will be authenticated and
+ * encrypted
+ * @param plaintext_length Size of @c p_plaintext in bytes
+ * @param p_ciphertext Output buffer for the authenticated and
+ * encrypted data. The additional data is
+ * not part of this output. For algorithms
+ * where the encrypted data and the
+ * authentication tag are defined as
+ * separate outputs, the authentication
+ * tag is appended to the encrypted data.
+ * @param ciphertext_size Size of the @c p_ciphertext buffer in
+ * bytes
+ * @param p_ciphertext_length On success, the size of the output in
+ * the @c p_ciphertext buffer
+ *
+ * @return @ref PSA_SUCCESS Success.
+ */
+typedef psa_status_t (*psa_drv_se_aead_encrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t algorithm,
+ const uint8_t *p_nonce,
+ size_t nonce_length,
+ const uint8_t *p_additional_data,
+ size_t additional_data_length,
+ const uint8_t *p_plaintext,
+ size_t plaintext_length,
+ uint8_t *p_ciphertext,
+ size_t ciphertext_size,
+ size_t *p_ciphertext_length);
+
+/**
+ * @brief A function that peforms a secure element authenticated decryption operation
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Slot containing the key to use
+ * @param algorithm The AEAD algorithm to compute
+ * (@c PSA_ALG_XXX value such that
+ * @ref PSA_ALG_IS_AEAD(@p alg) is true)
+ * @param p_nonce Nonce or IV to use
+ * @param nonce_length Size of the @c p_nonce buffer in bytes
+ * @param p_additional_data Additional data that has been
+ * authenticated but not encrypted
+ * @param additional_data_length Size of @c p_additional_data in bytes
+ * @param p_ciphertext Data that has been authenticated and
+ * encrypted.
+ * For algorithms where the encrypted data
+ * and the authentication tag are defined
+ * as separate inputs, the buffer must
+ * contain the encrypted data followed by
+ * the authentication tag.
+ * @param ciphertext_length Size of @c p_ciphertext in bytes
+ * @param p_plaintext Output buffer for the decrypted data
+ * @param plaintext_size Size of the @c p_plaintext buffer in
+ * bytes
+ * @param p_plaintext_length On success, the size of the output in
+ * the @c p_plaintext buffer
+ *
+ * @return @ref PSA_SUCCESS Success.
+ */
+typedef psa_status_t (*psa_drv_se_aead_decrypt_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ psa_algorithm_t algorithm,
+ const uint8_t *p_nonce,
+ size_t nonce_length,
+ const uint8_t *p_additional_data,
+ size_t additional_data_length,
+ const uint8_t *p_ciphertext,
+ size_t ciphertext_length,
+ uint8_t *p_plaintext,
+ size_t plaintext_size,
+ size_t *p_plaintext_length);
+
+/**
+ * @brief A struct containing all of the function pointers needed to implement
+ * secure element Authenticated Encryption with Additional Data operations
+ *
+ * @details PSA Crypto API implementations should populate instances of the table as
+ * appropriate upon startup.
+ *
+ * If one of the functions is not implemented, it should be set to NULL.
+ */
+typedef struct {
+ /** Function that performs the AEAD encrypt operation */
+ psa_drv_se_aead_encrypt_t p_encrypt;
+ /** Function that performs the AEAD decrypt operation */
+ psa_drv_se_aead_decrypt_t p_decrypt;
+} psa_drv_se_aead_t;
+/**@}*/
+
+/**
+ * @defgroup se_key_management Secure Element Key Management
+ *
+ * @details Currently, key management is limited to importing keys in the clear,
+ * destroying keys, and exporting keys in the clear.
+ * Whether a key may be exported is determined by the key policies in place
+ * on the key slot.
+ *
+ * @{
+ */
+
+/**
+ * An enumeration indicating how a key is created.
+ */
+typedef enum {
+ PSA_KEY_CREATION_IMPORT, /**< During @ref psa_import_key() */
+ PSA_KEY_CREATION_GENERATE, /**< During @ref psa_generate_key() */
+ PSA_KEY_CREATION_DERIVE, /**< During @ref psa_key_derivation_output_key() */
+ PSA_KEY_CREATION_COPY, /**< During @ref psa_copy_key() */
+} psa_key_creation_method_t;
+
+/**
+ * @brief A function that allocates a slot for a key.
+ *
+ * @details To create a key in a specific slot in a secure element, the core first calls this
+ * function to determine a valid slot number, then calls a function to create the key
+ * material in that slot. In nominal conditions (that is, if no error occurs), the effect
+ * of a call to a key creation function in the PSA Cryptography API with a lifetime that
+ * places the key in a secure element is the following:
+ * -# The core calls @ref psa_drv_se_key_management_t::p_allocate
+ * (or in some implementations @ref
+ * psa_drv_se_key_management_t::p_validate_slot_number). The driver selects (or
+ * validates) a suitable slot number given the key attributes and the state of the
+ * secure element.
+ * -# The core calls a key creation function in the driver.
+ *
+ * The key creation functions in the PSA Cryptography API are:
+ * - @ref psa_import_key(), which causes a call to @c p_allocate with
+ * @c method = @ref PSA_KEY_CREATION_IMPORT then a call to
+ * @ref psa_drv_se_key_management_t::p_import.
+ * - @ref psa_generate_key(), which causes a call to @c p_allocate with
+ * @c method = @ref PSA_KEY_CREATION_GENERATE then a call to
+ * @ref psa_drv_se_key_management_t::p_import.
+ * - @ref psa_key_derivation_output_key(), which causes a call to @c p_allocate with
+ * @p method = @ref PSA_KEY_CREATION_DERIVE then a call to
+ * @ref psa_drv_se_key_derivation_t::p_derive.
+ * - @ref psa_copy_key(), which causes a call to @c p_allocate with
+ * @p method = @ref PSA_KEY_CREATION_COPY then a call to
+ * @ref psa_drv_se_key_management_t::p_export.
+ *
+ * In case of errors, other behaviors are possible.
+ * - If the PSA Cryptography subsystem dies after the first step, for example because the
+ * device has lost power abruptly, the second step may never happen, or may happen after
+ * a reset and re-initialization. Alternatively, after a reset and re-initialization,
+ * the core may call @ref psa_drv_se_key_management_t::p_destroy on the slot number that
+ * was allocated (or validated) instead of calling a key creation function.
+ * - If an error occurs, the core may call @ref psa_drv_se_key_management_t::p_destroy on
+ * the slot number that was allocated (or validated) instead of calling a key creation
+ * function.
+ *
+ * Errors and system resets also have an impact on the driver's persistent
+ * data. If a reset happens before the overall key creation process is
+ * completed (before or after the second step above), it is unspecified
+ * whether the persistent data after the reset is identical to what it
+ * was before or after the call to @c p_allocate (or @c p_validate_slot_number).
+ *
+ * @param drv_context The driver context structure.
+ * @param persistent_data A pointer to the persistent data
+ * that allows writing.
+ * @param attributes Attributes of the key.
+ * @param method The way in which the key is being created.
+ * @param key_slot Slot where the key will be stored.
+ * This must be a valid slot for a key of the
+ * chosen type. It must be unoccupied.
+ *
+ * @return @ref PSA_SUCCESS Success. The core will record @c *key_slot as the key slot where
+ * the key is stored and will update the persistent data in storage.
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ * @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ */
+typedef psa_status_t (*psa_drv_se_allocate_key_t)( psa_drv_se_context_t *drv_context,
+ void *persistent_data,
+ const psa_key_attributes_t *attributes,
+ psa_key_creation_method_t method,
+ psa_key_slot_number_t *key_slot);
+
+/**
+ * @brief A function that determines whether a slot number is valid for a key.
+ *
+ * @details To create a key in a specific slot in a secure element, the core
+ * first calls this function to validate the choice of slot number,
+ * then calls a function to create the key material in that slot.
+ * See the documentation of @ref psa_drv_se_allocate_key_t for more details.
+ *
+ * As of the PSA Cryptography API specification version 1.0, there is no way
+ * for applications to trigger a call to this function. However some
+ * implementations offer the capability to create or declare a key in
+ * a specific slot via implementation-specific means, generally for the
+ * sake of initial device provisioning or onboarding. Such a mechanism may
+ * be added to a future version of the PSA Cryptography API specification.
+ *
+ * This function may update the driver's persistent data through
+ * @c persistent_data. The core will save the updated persistent data at the
+ * end of the key creation process. See the description of
+ * @ref psa_drv_se_allocate_key_t for more information.
+ *
+ * @param drv_context The driver context structure.
+ * @param persistent_data A pointer to the persistent data
+ * that allows writing.
+ * @param attributes Attributes of the key.
+ * @param method The way in which the key is being created.
+ * @param key_slot Slot where the key is to be stored.
+ *
+ * @return @ref PSA_SUCCESS The given slot number is valid for a key with the given
+ * attributes.
+ * @ref PSA_ERROR_INVALID_ARGUMENT The given slot number is not valid for a key with the
+ * given attributes. This includes the case where the slot
+ * number is not valid at all.
+ * @ref PSA_ERROR_ALREADY_EXISTS There is already a key with the specified slot number.
+ * Drivers may choose to return this error from the key
+ * creation function instead.
+ */
+typedef psa_status_t (*psa_drv_se_validate_slot_number_t)( psa_drv_se_context_t *drv_context,
+ void *persistent_data,
+ const psa_key_attributes_t *attributes,
+ psa_key_creation_method_t method,
+ psa_key_slot_number_t key_slot);
+
+/**
+ * @brief A function that imports a key into a secure element in binary format
+ *
+ * @details This function can support any output from @ref psa_export_key(). Refer to the
+ * documentation of @ref psa_export_key() for the format for each key type.
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Slot where the key will be stored.
+ * This must be a valid slot for a key of the
+ * chosen type. It must be unoccupied.
+ * @param attributes The key attributes, including the lifetime,
+ * the key type and the usage policy.
+ * Drivers should not access the key size stored
+ * in the attributes: it may not match the
+ * data passed in @c data.
+ * Drivers can call @ref psa_get_key_lifetime(),
+ * @ref psa_get_key_type(), @ref psa_get_key_usage_flags()
+ * and @ref psa_get_key_algorithm() to access this
+ * information.
+ * @param data Buffer containing the key data.
+ * @param data_length Size of the @c data buffer in bytes.
+ * @param bits On success, the key size in bits. The driver
+ * must determine this value after parsing the
+ * key according to the key type.
+ * This value is not used if the function fails.
+ *
+ * @return @ref PSA_SUCCESS Success.
+ */
+typedef psa_status_t (*psa_drv_se_import_key_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ const psa_key_attributes_t *attributes,
+ const uint8_t *data,
+ size_t data_length,
+ size_t *bits);
+
+/**
+ * @brief A function that destroys a secure element key and restore the slot to
+ * its default state
+ *
+ * @details This function destroys the content of the key from a secure element.
+ * Implementations shall make a best effort to ensure that any previous content
+ * of the slot is unrecoverable.
+ *
+ * This function returns the specified slot to its default state.
+ *
+ * @param drv_context The driver context structure.
+ * @param persistent_data A pointer to the persistent data
+ * that allows writing.
+ * @param key_slot The key slot to erase.
+ *
+ * @return @ref PSA_SUCCESS The slot's content, if any, has been erased.
+ */
+typedef psa_status_t (*psa_drv_se_destroy_key_t)( psa_drv_se_context_t *drv_context,
+ void *persistent_data,
+ psa_key_slot_number_t key_slot);
+
+/**
+ * @brief A function that exports a secure element key in binary format
+ *
+ * @details The output of this function can be passed to @ref psa_import_key() to
+ * create an equivalent object.
+ *
+ * If a key is created with @ref psa_import_key() and then exported with
+ * this function, it is not guaranteed that the resulting data is
+ * identical: the implementation may choose a different representation
+ * of the same key if the format permits it.
+ *
+ * This function should generate output in the same format that @ref psa_export_key()
+ * does. Refer to the documentation of @ref psa_export_key() for the format for each key
+ * type.
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Slot whose content is to be exported. This must be an occupied key slot.
+ * @param p_data Buffer where the key data is to be written.
+ * @param data_size Size of the @c p_data buffer in bytes.
+ * @param p_data_length On success, the number of bytes that make up the key data.
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_DOES_NOT_EXIST
+ * @ref PSA_ERROR_NOT_PERMITTED
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ * @ref PSA_ERROR_COMMUNICATION_FAILURE
+ * @ref PSA_ERROR_HARDWARE_FAILURE
+ * @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+typedef psa_status_t (*psa_drv_se_export_key_t)(psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ uint8_t *p_data,
+ size_t data_size,
+ size_t *p_data_length);
+
+/**
+ * @brief A function that generates a symmetric or asymmetric key on a secure element
+ *
+ * @details If the key type @c type recorded in @c attributes is asymmetric (@ref
+ * PSA_KEY_TYPE_IS_ASYMMETRIC(@c type) = 1), the driver may export the public key at the
+ * time of generation, in the format documented for @ref psa_export_public_key() by
+ * writing it to the @c pubkey buffer.
+ * This is optional, intended for secure elements that output the public key at generation
+ * time and that cannot export the public key later. Drivers that do not need this feature
+ * should leave @c *pubkey_length set to 0 and should implement the
+ * @c p_export_public function. Some implementations do not
+ * support this feature, in which case @c pubkey is @c NULL and @c pubkey_size is 0.
+ *
+ * @param drv_context The driver context structure.
+ * @param key_slot Slot where the key will be stored. This must be a valid slot for a key
+ * of the chosen type. It must be unoccupied.
+ * @param attributes The key attributes, including the lifetime, the key type and size, and
+ * the usage policy. Drivers can call @ref psa_get_key_lifetime(),
+ * @ref psa_get_key_type(), @ref psa_get_key_bits(),
+ * @ref psa_get_key_usage_flags() and @ref psa_get_key_algorithm() to
+ * access this information.
+ * @param pubkey A buffer where the driver can write the public key, when generating an
+ * asymmetric key pair. This is @c NULL when generating a symmetric key or
+ * if the core does not support exporting the public key at generation
+ * time.
+ * @param pubkey_size The size of the @c pubkey buffer in bytes. This is 0 when generating a
+ * symmetric key or if the core does not support exporting the public key
+ * at generation time.
+ * @param pubkey_length On entry, this is always 0. On success, the number of bytes written to
+ * @c pubkey. If this is 0 or unchanged on return, the core will not read
+ * the @c pubkey buffer, and will instead call the driver's
+ * @c p_export_public function to export the
+ * public key when needed.
+ */
+typedef psa_status_t (*psa_drv_se_generate_key_t)( psa_drv_se_context_t *drv_context,
+ psa_key_slot_number_t key_slot,
+ const psa_key_attributes_t *attributes,
+ uint8_t *pubkey, size_t pubkey_size,
+ size_t *pubkey_length);
+
+/**
+ * @brief A struct containing all of the function pointers needed to for secure element key
+ * management
+ *
+ * @details PSA Crypto API implementations should populate instances of the table as
+ * appropriate upon startup or at build time.
+ *
+ * If one of the functions is not implemented, it should be set to @c NULL.
+ */
+typedef struct {
+ /** Function that allocates a slot for a key. */
+ psa_drv_se_allocate_key_t p_allocate;
+ /** Function that checks the validity of a slot for a key. */
+ psa_drv_se_validate_slot_number_t p_validate_slot_number;
+ /** Function that performs a key import operation */
+ psa_drv_se_import_key_t p_import;
+ /** Function that performs a generation */
+ psa_drv_se_generate_key_t p_generate;
+ /** Function that performs a key destroy operation */
+ psa_drv_se_destroy_key_t p_destroy;
+ /** Function that performs a key export operation */
+ psa_drv_se_export_key_t p_export;
+ /** Function that performs a public key export operation */
+ psa_drv_se_export_key_t p_export_public;
+} psa_drv_se_key_management_t;
+
+/**@}*/
+
+/**
+ * @defgroup driver_derivation Secure Element Key Derivation and Agreement
+ *
+ * @details Key derivation is the process of generating new key material using an
+ * existing key and additional parameters, iterating through a basic
+ * cryptographic function, such as a hash.
+ * Key agreement is a part of cryptographic protocols that allows two parties
+ * to agree on the same key value, but starting from different original key
+ * material.
+ * The flows are similar, and the PSA Crypto Driver Model uses the same functions
+ * for both of the flows.
+ *
+ * There are two different final functions for the flows,
+ * @c psa_drv_se_key_derivation_derive and @c psa_drv_se_key_derivation_export.
+ * @c psa_drv_se_key_derivation_derive is used when the key material should be
+ * placed in a slot on the hardware and not exposed to the caller.
+ * @c psa_drv_se_key_derivation_export is used when the key material should be
+ * returned to the PSA Cryptographic API implementation.
+ *
+ * Different key derivation algorithms require a different number of inputs.
+ * Instead of having an API that takes as input variable length arrays, which
+ * can be problemmatic to manage on embedded platforms, the inputs are passed
+ * to the driver via a function, @c psa_drv_se_key_derivation_collateral, that
+ * is called multiple times with different @c collateral_ids. Thus, for a key
+ * derivation algorithm that required 3 parameter inputs, the flow would look
+ * something like:
+ *
+ * @code
+ * psa_drv_se_key_derivation_setup(kdf_algorithm, source_key,
+ * dest_key_size_bytes);
+ * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_0,
+* p_collateral_0,
+* collateral_0_size);
+ * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_1,
+ * p_collateral_1,
+ * collateral_1_size);
+ * psa_drv_se_key_derivation_collateral(kdf_algorithm_collateral_id_2,
+ * p_collateral_2,
+ * collateral_2_size);
+ * psa_drv_se_key_derivation_derive();
+ * @endcode
+ *
+ * key agreement example:
+ * @code
+ * psa_drv_se_key_derivation_setup(alg, source_key. dest_key_size_bytes);
+ * psa_drv_se_key_derivation_collateral(DHE_PUBKEY, p_pubkey, pubkey_size);
+ * psa_drv_se_key_derivation_export(p_session_key,
+ * session_key_size,
+ * &session_key_length);
+ * @endcode
+ * @{
+ */
+
+/**
+ * @brief A function that Sets up a secure element key derivation operation by specifying the
+ * algorithm and the source key sot
+ *
+ * @param drv_context The driver context structure.
+ * @param op_context A hardware-specific structure containing any
+ * context information for the implementation
+ * @param kdf_alg The algorithm to be used for the key derivation
+ * @param source_key The key to be used as the source material for
+ * the key derivation
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_key_derivation_setup_t)(psa_drv_se_context_t *drv_context,
+ void *op_context,
+ psa_algorithm_t kdf_alg,
+ psa_key_slot_number_t source_key);
+
+/**
+ * @brief A function that provides collateral (parameters) needed for a secure
+ * element key derivation or key agreement operation
+ *
+ * @details Since many key derivation algorithms require multiple parameters, it is
+ * expected that this function may be called multiple times for the same
+ * operation, each with a different algorithm-specific `collateral_id`
+ *
+ * @param op_context A hardware-specific structure containing any
+ * context information for the implementation
+ * @param collateral_id An ID for the collateral being provided
+ * @param p_collateral A buffer containing the collateral data
+ * @param collateral_size The size in bytes of the collateral
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_key_derivation_collateral_t)(void *op_context,
+ uint32_t collateral_id,
+ const uint8_t *p_collateral,
+ size_t collateral_size);
+
+/**
+ * @brief A function that performs the final secure element key derivation
+ * step and place the generated key material in a slot
+ *
+ * @param op_context A hardware-specific structure containing any
+ * context information for the implementation
+ * @param dest_key The slot where the generated key material should be placed
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_key_derivation_derive_t)(void *op_context,
+ psa_key_slot_number_t dest_key);
+
+/**
+ * @brief A function that performs the final step of a secure element key
+ * agreement and place the generated key material in a buffer
+ *
+ * @param op_context A hardware-specific structure containing any
+ * context information for the implementation
+ * @param p_output Buffer in which to place the generated key material
+ * @param output_size The size in bytes of @c p_output
+ * @param p_output_length Upon success, contains the number of bytes of key
+ * material placed in @c p_output
+ *
+ * @return @ref PSA_SUCCESS
+ */
+typedef psa_status_t (*psa_drv_se_key_derivation_export_t)(void *op_context,
+ uint8_t *p_output,
+ size_t output_size,
+ size_t *p_output_length);
+
+/**
+ * @brief A struct containing all of the function pointers needed to for secure
+ * element key derivation and agreement
+ *
+ * @details PSA Crypto API implementations should populate instances of the table as
+ * appropriate upon startup.
+ *
+ * If one of the functions is not implemented, it should be set to @c NULL.
+ */
+typedef struct {
+ /** The driver-specific size of the key derivation context */
+ size_t context_size;
+ /** Function that performs a key derivation setup */
+ psa_drv_se_key_derivation_setup_t p_setup;
+ /** Function that sets key derivation collateral */
+ psa_drv_se_key_derivation_collateral_t p_collateral;
+ /** Function that performs a final key derivation step */
+ psa_drv_se_key_derivation_derive_t p_derive;
+ /** Function that perforsm a final key derivation or agreement and exports the key */
+ psa_drv_se_key_derivation_export_t p_export;
+} psa_drv_se_key_derivation_t;
+
+/**@}*/
+
+/**
+ * @defgroup se_registration Secure Element Driver Registration
+ * @{
+ */
+
+/**
+ * @brief A structure containing pointers to all the entry points of a secure element driver.
+ *
+ * @details Future versions of this specification may add extra substructures at the end of this
+ * structure.
+ */
+typedef struct {
+ /**
+ * The version of the driver HAL that this driver implements.
+ * This is a protection against loading driver binaries built against
+ * a different version of this specification.
+ * Use @ref PSA_DRV_SE_HAL_VERSION.
+ */
+ uint32_t hal_version;
+
+ /**
+ * The size of the driver's persistent data in bytes.
+ *
+ * This can be 0 if the driver does not need persistent data.
+ *
+ * See the documentation of @ref psa_drv_se_context_t::persistent_data
+ * for more information about why and how a driver can use
+ * persistent data.
+ */
+ size_t persistent_data_size;
+
+ /**
+ * The driver initialization function.
+ *
+ * This function is called once during the initialization of the
+ * PSA Cryptography subsystem, before any other function of the
+ * driver is called. If this function returns a failure status,
+ * the driver will be unusable, at least until the next system reset.
+ *
+ * If this field is @c NULL, it is equivalent to a function that does
+ * nothing and returns @ref PSA_SUCCESS.
+ */
+ psa_drv_se_init_t p_init;
+
+ const psa_drv_se_key_management_t *key_management; /**< Key management methods */
+ const psa_drv_se_mac_t *mac; /**< MAC operation methods */
+ const psa_drv_se_cipher_t *cipher; /**< Cipher operation methods */
+ const psa_drv_se_aead_t *aead; /**< AEAD operation methods */
+ const psa_drv_se_asymmetric_t *asymmetric; /**< Asymmetric operation methods */
+ const psa_drv_se_key_derivation_t *derivation; /**< Key derivation methods */
+} psa_drv_se_t;
+/**@}*/
+
+/**
+ * The current version of the secure element driver HAL.
+ */
+#define PSA_DRV_SE_HAL_VERSION 0x00000005
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_SE_DRIVER_H */
+/** @} */
diff --git a/sys/psa_crypto/include/psa_crypto_se_management.h b/sys/psa_crypto/include/psa_crypto_se_management.h
new file mode 100644
index 0000000000..dc342a28a7
--- /dev/null
+++ b/sys/psa_crypto/include/psa_crypto_se_management.h
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup psa_crypto_se_mgmt PSA Crypto SE Management
+ * @{
+ *
+ * @file psa_crypto_se_management.h
+ * @brief PSA Secure Element management function declarations
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_SE_MANAGEMENT_H
+#define PSA_CRYPTO_SE_MANAGEMENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "psa/crypto.h"
+#include "psa_crypto_se_driver.h"
+
+/**
+ * @brief Maximum number of available secure elements.
+ */
+#ifndef CONFIG_PSA_MAX_SE_COUNT
+#define CONFIG_PSA_MAX_SE_COUNT (1)
+#endif /* CONFIG_PSA_MAX_SE_COUNT */
+
+/**
+ * @brief Maximum supported number of secure elements
+ */
+#define PSA_MAX_SE_COUNT (CONFIG_PSA_MAX_SE_COUNT)
+
+/**
+ * @brief Internal secure element driver context.
+ *
+ * @details This is the same structure as @ref psa_drv_se_context_t, with the difference that it is
+ * also writeable for the implementation.
+ *
+ * This structure is not to be used by applications, only by the PSA Crypto implementation.
+ */
+typedef struct {
+ void * persistent_data; /**< Driver specific persistent data */
+ size_t persistent_data_size; /**< Size of persistent data in bytes */
+ uintptr_t transient_data; /**< Driver specific transient data */
+} psa_drv_se_internal_context_t;
+
+/**
+ * @brief Structure containing secure element driver data and contexts.
+ */
+struct psa_se_drv_data_s {
+ psa_key_location_t location; /**< Location value assigned to driver */
+ const psa_drv_se_t *methods; /**< Methods implemented by driver */
+ union {
+ psa_drv_se_internal_context_t internal; /**< Internally writable SE driver context */
+ psa_drv_se_context_t context; /**< SE driver context, read only */
+ } ctx; /**< SE driver context */
+};
+
+/**
+ * @brief Encodes the secure element driver data
+ */
+typedef struct psa_se_drv_data_s psa_se_drv_data_t;
+
+/**
+ * @brief Register a secure element driver with the SE management.
+ *
+ * @details This function is called by the @c auto_init module during boot.
+ *
+ * @param location Location the driver should be registered with,
+ * of type @ref psa_key_location_t
+ * @param methods Structure of available driver entry points of the driver
+ * @param psa_se_configuration Pointer to a secure element configuration structure
+ * @param drv_transient_data Transient driver data to be used by the driver
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT The location value is invalid
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ * @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
+ * @return @ref PSA_ERROR_ALREADY_EXISTS *
+ */
+psa_status_t psa_register_secure_element(psa_key_location_t location,
+ const psa_drv_se_t *methods,
+ void *psa_se_configuration,
+ const void *drv_transient_data);
+
+/**
+ * @brief Get the driver data of a specified driver
+ *
+ * @param lifetime Lifetime value of type @ref psa_key_lifetime_t of the key to be used
+ *
+ * @return @ref psa_se_drv_data_t* Pointer to the driver data
+ * @return @c NULL if no driver exists with this location
+ */
+psa_se_drv_data_t *psa_get_se_driver_data(psa_key_lifetime_t lifetime);
+
+/**
+ * @brief Get the driver entry points and context of a specified driver
+ *
+ * @param lifetime Lifetime value of type @ref psa_key_lifetime_t of the key to be used
+ * @param p_methods Pointer that will reference the driver methods
+ * @param p_drv_context Pointer that will reference the driver context
+ *
+ * @return 1 if a driver was found
+ * @return 0 if no driver exists with this location
+ */
+int psa_get_se_driver( psa_key_lifetime_t lifetime,
+ const psa_drv_se_t **p_methods,
+ psa_drv_se_context_t **p_drv_context);
+
+/**
+ * @brief Get the driver entry points of a specified driver
+ *
+ * @param driver Driver data of type @ref psa_se_drv_data_t containing the entry points
+ *
+ * @return const psa_drv_se_t*
+ */
+const psa_drv_se_t *psa_get_se_driver_methods(const psa_se_drv_data_t *driver);
+
+/**
+ * @brief Get the driver context of a specified driver
+ *
+ * @param driver Driver data of type @ref psa_se_drv_data_t containing the context
+ *
+ * @return @ref psa_drv_se_context_t*
+ */
+psa_drv_se_context_t *psa_get_se_drv_context(psa_se_drv_data_t *driver);
+
+/**
+ * @brief Find an empty key slot on a secure element appropriate to the key attributes
+ *
+ * @param attributes @ref psa_key_attributes_t containing the attributes of the key to be created
+ * @param method The method used to create the key (see @ref psa_key_creation_method_t)
+ * @param driver Pointer to the driver for the SE the key should be created on
+ * @param slot_number Pointer that will contain the slot number of the free SE slot
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ */
+psa_status_t psa_find_free_se_slot( const psa_key_attributes_t *attributes,
+ psa_key_creation_method_t method,
+ psa_se_drv_data_t *driver,
+ psa_key_slot_number_t *slot_number);
+
+/**
+ * @brief Destroy the key on a secure element
+ *
+ * @note Some secure elements may not support this operation.
+ *
+ * @param driver Driver of the SE containing the key to be destroyed
+ * @param slot_number Slot number of the key that is to be destroyed
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_NOT_PERMITTED
+ */
+psa_status_t psa_destroy_se_key(psa_se_drv_data_t *driver,
+ psa_key_slot_number_t slot_number);
+
+/**
+ * @brief Load SE data from persistent memory
+ *
+ * @note This operation is not yet supported by this implementation
+ *
+ * @param driver Pointer to the driver data the loaded data should be stored in
+ *
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ */
+psa_status_t psa_load_se_persistent_data(const psa_se_drv_data_t *driver);
+
+/**
+ * @brief Save SE data to persistent memory
+ *
+ * @note This operation is not yet supported by this implementation
+ *
+ * @param driver Pointer to the driver data containing the data to be saved
+ *
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ */
+psa_status_t psa_save_se_persistent_data(const psa_se_drv_data_t *driver);
+
+/**
+ * @brief Destroy SE data in persistent memory
+ *
+ * @note This operation is not yet supported by this implementation
+ *
+ * @param location Location of the data that should be destroyed
+ *
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ */
+psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_SE_MANAGEMENT_H */
+/**@}*/
diff --git a/sys/psa_crypto/include/psa_crypto_slot_management.h b/sys/psa_crypto/include/psa_crypto_slot_management.h
new file mode 100644
index 0000000000..27febefcfb
--- /dev/null
+++ b/sys/psa_crypto/include/psa_crypto_slot_management.h
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_slot_mgmt PSA Crypto Key Slot Management
+ * @{
+ *
+ * @file psa_crypto_slot_management.h
+ * @brief PSA key slot management function declarations
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H
+#define PSA_CRYPTO_SLOT_MANAGEMENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "clist.h"
+#include "psa/crypto.h"
+#include "psa_crypto_se_management.h"
+
+/**
+ * @brief Number of allocated slots for keys in protected memory or secure elements.
+ */
+#define PSA_PROTECTED_KEY_COUNT (CONFIG_PSA_PROTECTED_KEY_COUNT)
+
+/**
+ * @brief Number of allocated slots for asymmetric key pairs.
+ */
+#define PSA_ASYMMETRIC_KEYPAIR_COUNT (CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT)
+
+/**
+ * @brief Number of allocated slots for single keys in local memory.
+ */
+#define PSA_SINGLE_KEY_COUNT (CONFIG_PSA_SINGLE_KEY_COUNT)
+
+/**
+ * @brief Complete number of available key slots
+ */
+#define PSA_KEY_SLOT_COUNT (PSA_PROTECTED_KEY_COUNT + \
+ PSA_ASYMMETRIC_KEYPAIR_COUNT + \
+ PSA_SINGLE_KEY_COUNT)
+
+/**
+ * @brief Minimum key id for volatile keys.
+ *
+ * @details This is used to assign volatile identifiers to created keys.
+ */
+#define PSA_KEY_ID_VOLATILE_MIN (PSA_KEY_ID_VENDOR_MIN)
+
+/**
+ * @brief Maximum key id for volatile keys.
+ *
+ * @details This is the maximum volatile identifiers that can be assigned to created keys.
+ */
+#define PSA_KEY_ID_VOLATILE_MAX (PSA_KEY_ID_VENDOR_MAX)
+
+/**
+ * @brief Structure of a virtual key slot in local memory.
+ *
+ * @details A slot contains key attributes, a lock count and the @c key_data structure.
+ * @c key_data consists of the size of the stored key in bytes and a @c uint8_t data array
+ * large enough to store the largest key used in the current build. This type of key slot
+ * contains symmetric keys, asymmetric public keys or unstructured data.
+ */
+typedef struct {
+ clist_node_t node; /**< List node to link slot in global list */
+ size_t lock_count; /**< Number of entities accessing the slot */
+ psa_key_attributes_t attr; /**< Attributes associated with the stored key */
+ /** Structure containing key data */
+ struct key_data {
+ uint8_t data[PSA_MAX_KEY_DATA_SIZE]; /**< Key data buffer */
+ size_t data_len; /**< Size of actual key data in bytes */
+ } key; /**< Key data structure */
+} psa_key_slot_t;
+
+/**
+ * @brief Initializes the allocated key slots and prepares the internal key slot lists.
+ */
+void psa_init_key_slots(void);
+
+/**
+ * @brief Check whether a key identifier is a volatile key identifier.
+ *
+ * @param key_id Key identifier to test.
+ *
+ * @return 1 The key identifier is a volatile key identifier.
+ * @return 0 The key identifier is not a volatile key identifier.
+ */
+static inline int psa_key_id_is_volatile(psa_key_id_t key_id)
+{
+ return ((key_id >= PSA_KEY_ID_VOLATILE_MIN) &&
+ (key_id <= PSA_KEY_ID_VOLATILE_MAX));
+}
+
+/**
+ * @brief Check whether a key slot is locked
+ *
+ * @param slot Pointer to the slot to be checked
+ *
+ * @return 1 if slot is locked, otherwise 0
+ */
+static inline int psa_is_key_slot_locked(psa_key_slot_t *slot)
+{
+ return (slot->lock_count > 0);
+}
+
+/**
+ * @brief Get slot number in protected memory
+ *
+ * @param slot Pointer to the slot containing the protected slot number
+ * @return @ref psa_key_slot_number_t Key slot number stored in the input slot
+ */
+psa_key_slot_number_t * psa_key_slot_get_slot_number(const psa_key_slot_t *slot);
+
+/**
+ * @brief Check whether a key is stored on an external device
+ *
+ * @param lifetime Lifetime value of the key that's supposed to be checked
+ *
+ * @return int
+ * @return 1 if key is stored on external device, otherwise 0
+ */
+static inline int psa_key_lifetime_is_external(psa_key_lifetime_t lifetime)
+{
+ return (PSA_KEY_LIFETIME_GET_LOCATION(lifetime) != PSA_KEY_LOCATION_LOCAL_STORAGE);
+}
+
+/**
+ * @brief Wipe volatile key slot and its contents. Wiped key slots can be reused.
+ *
+ * @param slot Pointer to the key slot to be wiped
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_DOES_NOT_EXIST
+ */
+psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot);
+
+/**
+ * @brief Wipe all existing volatile key slots.
+ */
+void psa_wipe_all_key_slots(void);
+
+/**
+ * @brief Find a key slot in local memory and lock it.
+ *
+ * @param id ID of the key to be used
+ * @param slot Pointer to the slot the key is stored in
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_DOES_NOT_EXIST
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ */
+psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **slot);
+
+/**
+ * @brief Find a currently empty key slot that is appropriate for the key.
+ *
+ * @param id Key ID of the newly generated or imported key
+ * @param attr Attributes of the key that is supposed to be stored in the slot
+ * @param p_slot Pointer to the empty slot in memory
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ */
+psa_status_t psa_allocate_empty_key_slot( psa_key_id_t *id,
+ const psa_key_attributes_t *attr,
+ psa_key_slot_t **p_slot);
+
+/**
+ * @brief Increase lock count
+ *
+ * @param slot Slot to be locked
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_lock_key_slot(psa_key_slot_t *slot);
+
+/**
+ * @brief Decrease lock count
+ *
+ * @param slot Slot to be unlocked
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+psa_status_t psa_unlock_key_slot(psa_key_slot_t *slot);
+
+/**
+ * @brief Check if key location exists
+ *
+ * @param lifetime Lifetime value of the key to be validated
+ * @param driver Pointer to driver assigned to the existing key location, if it exists
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_INVALID_ARGUMENT
+ */
+psa_status_t psa_validate_key_location( psa_key_lifetime_t lifetime,
+ psa_se_drv_data_t **driver);
+
+/**
+ * @brief Validate key persistence. Currently only volatile keys are supported.
+ *
+ * @param lifetime Lifetime of key to be validated
+ *
+ * @return @ref PSA_SUCCESS
+ * @return @ref PSA_ERROR_NOT_SUPPORTED
+ */
+psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime);
+
+/**
+ * @brief Check if provided key ID is either a valid user ID or vendor ID
+ *
+ * @param id ID of key to be validated
+ * @param vendor If ID is supposed to be user or vendor ID
+ *
+ * @return 1 if valid
+ * @return 0 if invalid
+ */
+int psa_is_valid_key_id(psa_key_id_t id, int vendor);
+
+/**
+ * @brief Get key data and key size from key slot
+ *
+ * @param slot Slot the desired key is stored in
+ * @param key_data Pointer to key data
+ * @param key_bytes Pointer to key data size in bytes
+ *
+ * @return Size of @p key_data in bytes.
+ */
+size_t psa_get_key_data_from_key_slot(const psa_key_slot_t *slot,
+ uint8_t **key_data,
+ size_t **key_bytes);
+
+/**
+ * @brief Get public key data and size from key slot
+ *
+ * @param slot Slot the desired key is stored in
+ * @param pubkey_data Pointer to key data
+ * @param pubkey_data_len Pointer to key data size in bytes
+ */
+void psa_get_public_key_data_from_key_slot( const psa_key_slot_t *slot,
+ uint8_t **pubkey_data,
+ size_t **pubkey_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_CRYPTO_SLOT_MANAGEMENT_H */
+/**@}*/
diff --git a/sys/psa_crypto/include/psa_ecc.h b/sys/psa_crypto/include/psa_ecc.h
new file mode 100644
index 0000000000..d995b821cb
--- /dev/null
+++ b/sys/psa_crypto/include/psa_ecc.h
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_ecc PSA Wrapper Functions: ECC
+ * @{
+ *
+ * @file psa_ecc.h
+ * @brief Function declarations for low level wrapper functions for ECC operations.
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_ECC_H
+#define PSA_ECC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "psa/crypto.h"
+#include "kernel_defines.h"
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC key generation
+ * with a SECP 192 R1 key.
+ * See @ref psa_generate_key()
+ *
+ * @param attributes
+ * @param priv_key_buffer
+ * @param pub_key_buffer
+ * @param priv_key_buffer_length
+ * @param pub_key_buffer_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_generate_ecc_p192r1_key_pair( const psa_key_attributes_t *attributes,
+ uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
+ size_t *priv_key_buffer_length,
+ size_t *pub_key_buffer_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC public key export
+ * of a SECP 192 R1 key.
+ * See @ref psa_export_public_key()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param data
+ * @param data_size
+ * @param data_length
+ * @return psa_status_t
+ */
+psa_status_t psa_ecc_p192r1_export_public_key( const psa_key_attributes_t *attributes,
+ uint8_t *key_buffer,
+ size_t key_buffer_size,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC hash signature
+ * with a SECP 192 R1 key.
+ * See @ref psa_sign_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_size
+ * @param signature_length
+ * @return psa_status_t
+ */
+psa_status_t psa_ecc_p192r1_sign_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const uint8_t *key_buffer, size_t key_buffer_size,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC hash verification
+ * with a SECP 192 R1 key.
+ * See @ref psa_verify_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_length
+ * @return psa_status_t
+ */
+psa_status_t psa_ecc_p192r1_verify_hash(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const uint8_t *key_buffer, size_t key_buffer_size,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC key generation
+ * with a SECP 192 R1 key.
+ * See @ref psa_generate_key()
+ *
+ * @param attributes
+ * @param priv_key_buffer
+ * @param pub_key_buffer
+ * @param priv_key_buffer_length
+ * @param pub_key_buffer_length
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_generate_ecc_p256r1_key_pair( const psa_key_attributes_t *attributes,
+ uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
+ size_t *priv_key_buffer_length,
+ size_t *pub_key_buffer_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC public key export
+ * of a SECP 256 R1 key.
+ * See @ref psa_export_public_key()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param data
+ * @param data_size
+ * @param data_length
+ * @return psa_status_t
+ */
+psa_status_t psa_ecc_p256r1_export_public_key( const psa_key_attributes_t *attributes,
+ uint8_t *key_buffer,
+ size_t key_buffer_size,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC hash signature
+ * with a SECP 256 R1 key.
+ * See @ref psa_sign_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_size
+ * @param signature_length
+ * @return psa_status_t
+ */
+psa_status_t psa_ecc_p256r1_sign_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const uint8_t *key_buffer, size_t key_buffer_size,
+ const uint8_t *hash, size_t hash_length,
+ uint8_t *signature, size_t signature_size,
+ size_t *signature_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an ECC hash verification
+ * with a SECP 256 R1 key.
+ * See @ref psa_verify_hash()
+ *
+ * @param attributes
+ * @param alg
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param hash
+ * @param hash_length
+ * @param signature
+ * @param signature_length
+ * @return psa_status_t
+ */
+psa_status_t psa_ecc_p256r1_verify_hash(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const uint8_t *key_buffer, size_t key_buffer_size,
+ const uint8_t *hash, size_t hash_length,
+ const uint8_t *signature, size_t signature_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_ECC_H */
+/**@}*/
diff --git a/sys/psa_crypto/include/psa_hashes.h b/sys/psa_crypto/include/psa_hashes.h
new file mode 100644
index 0000000000..98a7f23867
--- /dev/null
+++ b/sys/psa_crypto/include/psa_hashes.h
@@ -0,0 +1,232 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_hashes PSA Wrapper Functions: Hashes
+ * @{
+ *
+ * @file psa_hashes.h
+ * @brief Function declarations for low level wrapper functions for hash operations.
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_HASHES_H
+#define PSA_HASHES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_defines.h"
+#include "psa/crypto.h"
+#include "psa/crypto_contexts.h"
+
+#if IS_USED(MODULE_PSA_HASH_MD5) || defined(DOXYGEN)
+/**
+ * @brief Low level wrapper function to call a driver for an MD5 hash setup
+ * See @ref psa_hash_setup()
+ *
+ * @param ctx
+ * @return @ref psa_status_t
+ */
+psa_status_t psa_hashes_md5_setup(psa_hashes_md5_ctx_t *ctx);
+
+/**
+ * @brief Low level wrapper function to call a driver for an MD5 hash update
+ * See @ref psa_hash_update()
+ *
+ * @param ctx
+ * @param input
+ * @param input_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_md5_update(psa_hashes_md5_ctx_t *ctx,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an MD5 hash finish
+ * See @ref psa_hash_finish()
+ *
+ * @param ctx
+ * @param hash
+ * @param hash_size
+ * @param hash_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_md5_finish(psa_hashes_md5_ctx_t *ctx,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+#endif /* CONFIG_HASHES_MD5 */
+
+#if IS_USED(MODULE_PSA_HASH_SHA_1) || defined(DOXYGEN)
+/**
+ * @brief Low level wrapper function to call a driver for an SHA1 hash setup
+ * See @ref psa_hash_setup()
+ *
+ * @param ctx
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA1 hash update
+ * See @ref psa_hash_update()
+ *
+ * @param ctx
+ * @param input
+ * @param input_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA1 hash finish
+ * See @ref psa_hash_finish()
+ *
+ * @param ctx
+ * @param hash
+ * @param hash_size
+ * @param hash_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+#endif /* CONFIG_HASHES_SHA1 */
+
+#if IS_USED(MODULE_PSA_HASH_SHA_224) || defined(DOXYGEN)
+/**
+ * @brief Low level wrapper function to call a driver for an SHA224 hash setup
+ * See @ref psa_hash_setup()
+ *
+ * @param ctx
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA224 hash update
+ * See @ref psa_hash_update()
+ *
+ * @param ctx
+ * @param input
+ * @param input_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA224 hash finish
+ * See @ref psa_hash_finish()
+ *
+ * @param ctx
+ * @param hash
+ * @param hash_size
+ * @param hash_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+#endif /* CONFIG_HASHES_SHA224 */
+
+#if IS_USED(MODULE_PSA_HASH_SHA_256) || defined(DOXYGEN)
+/**
+ * @brief Low level wrapper function to call a driver for an SHA256 hash setup
+ * See @ref psa_hash_setup()
+ *
+ * @param ctx
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA256 hash update
+ * See @ref psa_hash_update()
+ *
+ * @param ctx
+ * @param input
+ * @param input_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA256 hash finish
+ * See @ref psa_hash_finish()
+ *
+ * @param ctx
+ * @param hash
+ * @param hash_size
+ * @param hash_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+#endif /* CONFIG_HASHES_SHA256 */
+
+#if IS_USED(MODULE_PSA_HASH_SHA_512) || defined(DOXYGEN)
+/**
+ * @brief Low level wrapper function to call a driver for an SHA512 hash setup
+ * See @ref psa_hash_setup()
+ *
+ * @param ctx
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha512_setup(psa_hashes_sha512_ctx_t *ctx);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA512 hash update
+ * See @ref psa_hash_update()
+ *
+ * @param ctx
+ * @param input
+ * @param input_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha512_update(psa_hashes_sha512_ctx_t *ctx,
+ const uint8_t *input,
+ size_t input_length);
+
+/**
+ * @brief Low level wrapper function to call a driver for an SHA512 hash finish
+ * See @ref psa_hash_finish()
+ *
+ * @param ctx
+ * @param hash
+ * @param hash_size
+ * @param hash_length
+ * @return psa_status_t
+ */
+psa_status_t psa_hashes_sha512_finish(psa_hashes_sha512_ctx_t *ctx,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length);
+#endif /* CONFIG_HASHES_SHA512 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_HASHES_H */
+/**@}*/
diff --git a/sys/psa_crypto/include/psa_mac.h b/sys/psa_crypto/include/psa_mac.h
new file mode 100644
index 0000000000..1e74dea94c
--- /dev/null
+++ b/sys/psa_crypto/include/psa_mac.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @defgroup sys_psa_crypto_mac PSA Wrapper Functions: MAC
+ * @{
+ *
+ * @file psa_mac.h
+ * @brief Function declarations for low level wrapper functions for MAC operations.
+ *
+ * @author Lena Boeckmann
+ *
+ */
+
+#ifndef PSA_MAC_H
+#define PSA_MAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_defines.h"
+#include "psa/crypto.h"
+#include "psa/crypto_contexts.h"
+
+/**
+ * @brief Low level wrapper function to call a driver for a HMAC SHA256 computation
+ * See psa_mac_compute()
+ *
+ * @param attributes
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param input
+ * @param input_length
+ * @param mac
+ * @param mac_size
+ * @param mac_length
+ * @return psa_status_t
+ */
+psa_status_t psa_mac_compute_hmac_sha256( const psa_key_attributes_t *attributes,
+ const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PSA_MAC_H */
+/**@}*/
diff --git a/sys/psa_crypto/psa_crypto.c b/sys/psa_crypto/psa_crypto.c
new file mode 100644
index 0000000000..ef7158b7b3
--- /dev/null
+++ b/sys/psa_crypto/psa_crypto.c
@@ -0,0 +1,1931 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto
+ * @{
+ *
+ * @file
+ * @brief PSA Crypto API implementation
+ *
+ * @author Lena Boeckmann
+ *
+ * @}
+ */
+
+#include
+#include "psa/crypto.h"
+#include "psa_crypto_se_driver.h"
+#include "psa_crypto_se_management.h"
+#include "psa_crypto_slot_management.h"
+#include "psa_crypto_location_dispatch.h"
+#include "psa_crypto_algorithm_dispatch.h"
+
+#include "random.h"
+#include "kernel_defines.h"
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+/**
+ * @brief Set by psa_crypto_init, which is required to be called once before
+ * PSA Crypto. Must be checked by other operations first.
+ */
+static uint8_t lib_initialized = 0;
+
+/**
+ * @brief Compares the content of two same-sized buffers while maintaining
+ * constant processing time
+ *
+ * @param a Buffer A to compare with B
+ * @param b Buffer B to compare with A
+ * @param n Size of the input buffers
+ *
+ * @return int
+ * 0 if buffer contents are the same
+ * 1 if buffer contents differ
+ */
+static inline int constant_time_memcmp(const uint8_t *a, const uint8_t *b, size_t n)
+{
+ uint8_t diff = 0;
+
+ for (size_t i = 0; i < n; i++) {
+ diff |= a[i] ^ b[i];
+ }
+
+ return diff;
+}
+
+const char *psa_status_to_humanly_readable(psa_status_t status)
+{
+ switch (status) {
+ case PSA_ERROR_GENERIC_ERROR:
+ return "PSA_ERROR_GENERIC_ERROR";
+ case PSA_ERROR_NOT_SUPPORTED:
+ return "PSA_ERROR_NOT_SUPPORTED";
+ case PSA_ERROR_NOT_PERMITTED:
+ return "PSA_ERROR_NOT_PERMITTED";
+ case PSA_ERROR_BUFFER_TOO_SMALL:
+ return "PSA_ERROR_BUFFER_TOO_SMALL";
+ case PSA_ERROR_ALREADY_EXISTS:
+ return "PSA_ERROR_ALREADY_EXISTS";
+ case PSA_ERROR_DOES_NOT_EXIST:
+ return "PSA_ERROR_DOES_NOT_EXIST";
+ case PSA_ERROR_BAD_STATE:
+ return "PSA_ERROR_BAD_STATE";
+ case PSA_ERROR_INVALID_ARGUMENT:
+ return "PSA_ERROR_INVALID_ARGUMENT";
+ case PSA_ERROR_INSUFFICIENT_MEMORY:
+ return "PSA_ERROR_INSUFFICIENT_MEMORY";
+ case PSA_ERROR_INSUFFICIENT_STORAGE:
+ return "PSA_ERROR_INSUFFICIENT_STORAGE";
+ case PSA_ERROR_COMMUNICATION_FAILURE:
+ return "PSA_ERROR_COMMUNICATION_FAILURE";
+ case PSA_ERROR_STORAGE_FAILURE:
+ return "PSA_ERROR_STORAGE_FAILURE";
+ case PSA_ERROR_DATA_CORRUPT:
+ return "PSA_ERROR_DATA_CORRUPT";
+ case PSA_ERROR_DATA_INVALID:
+ return "PSA_ERROR_DATA_INVALID";
+ case PSA_ERROR_HARDWARE_FAILURE:
+ return "PSA_ERROR_HARDWARE_FAILURE";
+ case PSA_ERROR_CORRUPTION_DETECTED:
+ return "PSA_ERROR_CORRUPTION_DETECTED";
+ case PSA_ERROR_INSUFFICIENT_ENTROPY:
+ return "PSA_ERROR_INSUFFICIENT_ENTROPY";
+ case PSA_ERROR_INVALID_SIGNATURE:
+ return "PSA_ERROR_INVALID_SIGNATURE";
+ case PSA_ERROR_INVALID_PADDING:
+ return "PSA_ERROR_INVALID_PADDING";
+ case PSA_ERROR_INSUFFICIENT_DATA:
+ return "PSA_ERROR_INSUFFICIENT_DATA";
+ case PSA_ERROR_INVALID_HANDLE:
+ return "PSA_ERROR_INVALID_HANDLE";
+ default:
+ return "Error value not recognized";
+ }
+}
+
+psa_status_t psa_crypto_init(void)
+{
+ lib_initialized = 1;
+
+#if (IS_USED(MODULE_PSA_KEY_SLOT_MGMT))
+ psa_init_key_slots();
+#endif
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_aead_abort(psa_aead_operation_t *operation)
+{
+ (void)operation;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_decrypt( psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *ciphertext,
+ size_t ciphertext_length,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length)
+{
+ (void)key;
+ (void)alg;
+ (void)nonce;
+ (void)nonce_length;
+ (void)additional_data;
+ (void)additional_data_length;
+ (void)ciphertext;
+ (void)ciphertext_length;
+ (void)plaintext;
+ (void)plaintext_size;
+ (void)plaintext_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ (void)operation;
+ (void)key;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_encrypt( psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *nonce,
+ size_t nonce_length,
+ const uint8_t *additional_data,
+ size_t additional_data_length,
+ const uint8_t *plaintext,
+ size_t plaintext_length,
+ uint8_t *ciphertext,
+ size_t ciphertext_size,
+ size_t *ciphertext_length)
+{
+ (void)key;
+ (void)alg;
+ (void)nonce;
+ (void)nonce_length;
+ (void)additional_data;
+ (void)additional_data_length;
+ (void)plaintext;
+ (void)plaintext_length;
+ (void)ciphertext;
+ (void)ciphertext_size;
+ (void)ciphertext_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ (void)operation;
+ (void)key;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_finish( psa_aead_operation_t *operation,
+ uint8_t *ciphertext,
+ size_t ciphertext_size,
+ size_t *ciphertext_length,
+ uint8_t *tag,
+ size_t tag_size,
+ size_t *tag_length)
+{
+ (void)operation;
+ (void)ciphertext;
+ (void)ciphertext_size;
+ (void)ciphertext_length;
+ (void)tag;
+ (void)tag_size;
+ (void)tag_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_generate_nonce( psa_aead_operation_t *operation,
+ uint8_t *nonce,
+ size_t nonce_size,
+ size_t *nonce_length)
+{
+ (void)operation;
+ (void)nonce;
+ (void)nonce_size;
+ (void)nonce_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_set_lengths( psa_aead_operation_t *operation,
+ size_t ad_length,
+ size_t plaintext_length)
+{
+ (void)operation;
+ (void)ad_length;
+ (void)plaintext_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation,
+ const uint8_t *nonce,
+ size_t nonce_length)
+{
+ (void)operation;
+ (void)nonce;
+ (void)nonce_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_update( psa_aead_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ 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 psa_aead_update_ad(psa_aead_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ (void)operation;
+ (void)input;
+ (void)input_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_aead_verify( psa_aead_operation_t *operation,
+ uint8_t *plaintext,
+ size_t plaintext_size,
+ size_t *plaintext_length,
+ const uint8_t *tag,
+ size_t tag_length)
+{
+ (void)operation;
+ (void)plaintext;
+ (void)plaintext_size;
+ (void)plaintext_length;
+ (void)tag;
+ (void)tag_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_asymmetric_decrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *salt,
+ size_t salt_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ (void)key;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)salt;
+ (void)salt_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_asymmetric_encrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *salt,
+ size_t salt_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ (void)key;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)salt;
+ (void)salt_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+/**
+ * @brief Checks whether a key's policy permits the usage of a given algorithm
+ *
+ * @param policy Policy of the given key
+ * @param type Type of the given key
+ * @param requested_alg Algorithm to be used
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_NOT_PERMITTED
+ * @ref PSA_ERROR_INVALID_ARGUMENT If @c requested_alg is not a valid algorithm
+ */
+static psa_status_t psa_key_policy_permits( const psa_key_policy_t *policy,
+ psa_key_type_t type,
+ psa_algorithm_t requested_alg)
+{
+ if (requested_alg == 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ if (policy->alg == requested_alg) {
+ return PSA_SUCCESS;
+ }
+
+ (void)type;
+ return PSA_ERROR_NOT_PERMITTED;
+}
+
+/**
+ * @brief Check whether the policy of the key associated with the given ID permits the requested
+ * usage and return the key slot.
+ *
+ * @param id ID of the key to be used
+ * @param p_slot Pointer to a @c psa_key_slot_t type to return the desired key slot.
+ * @c NULL if something went wrong.
+ * @param usage The requested usage of the key
+ * @param alg The requested algorithm that uses the key
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_NOT_PERMITTED
+ * @ref PSA_ERROR_DOES_NOT_EXIST
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ * @ref PSA_ERROR_CORRUPTION_DETECTED
+ */
+static psa_status_t psa_get_and_lock_key_slot_with_policy( psa_key_id_t id,
+ psa_key_slot_t **p_slot,
+ psa_key_usage_t usage,
+ psa_algorithm_t alg)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+
+ status = psa_get_and_lock_key_slot(id, p_slot);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ slot = *p_slot;
+
+ if (PSA_KEY_TYPE_IS_PUBLIC_KEY(slot->attr.type)) {
+ /* Export is always permitted for asymmetric public keys */
+ usage &= ~PSA_KEY_USAGE_EXPORT;
+ }
+
+ if ((slot->attr.policy.usage & usage) != usage) {
+ *p_slot = NULL;
+ psa_unlock_key_slot(slot);
+ return PSA_ERROR_NOT_PERMITTED;
+ }
+
+ if (alg != 0) {
+ status = psa_key_policy_permits( &slot->attr.policy, slot->attr.type, alg);
+ if (status != PSA_SUCCESS) {
+ *p_slot = NULL;
+ psa_unlock_key_slot(slot);
+ return status;
+ }
+ }
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ *operation = psa_cipher_operation_init();
+ return PSA_SUCCESS;
+}
+
+/**
+ * @brief Setup a cipher encrypt or decrypt operation.
+ *
+ * See @ref psa_cipher_encrypt_setup(...)
+ * See @ref psa_cipher_decrypt_setup(...)
+ *
+ * @param operation
+ * @param key
+ * @param alg
+ * @param direction Whether encrypt or decrypt, see @ref psa_encrypt_or_decrypt_t
+ * @return @ref psa_status_t
+ */
+static psa_status_t psa_cipher_setup( psa_cipher_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg,
+ psa_encrypt_or_decrypt_t direction)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+ psa_key_usage_t usage = (direction == PSA_CRYPTO_DRIVER_ENCRYPT ?
+ PSA_KEY_USAGE_ENCRYPT :
+ PSA_KEY_USAGE_DECRYPT);
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!operation) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!PSA_ALG_IS_CIPHER(alg)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot, usage, alg);
+ if (status != PSA_SUCCESS) {
+ psa_cipher_abort(operation);
+ unlock_status = psa_unlock_key_slot(slot);
+ return status;
+ }
+
+ operation->iv_set = 0;
+ if (alg == PSA_ALG_ECB_NO_PADDING) {
+ operation->iv_required = 0;
+ }
+ else {
+ operation->iv_required = 1;
+ }
+ operation->default_iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg);
+
+ psa_key_attributes_t attr = slot->attr;
+
+ if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
+ status = psa_location_dispatch_cipher_encrypt_setup(operation, &attr, slot, alg);
+ }
+ else if (direction == PSA_CRYPTO_DRIVER_DECRYPT) {
+ status = psa_location_dispatch_cipher_decrypt_setup(operation, &attr, slot, alg);
+ }
+
+ if (status != PSA_SUCCESS) {
+ psa_cipher_abort(operation);
+ }
+
+ unlock_status = psa_unlock_key_slot(slot);
+ return ((status == PSA_SUCCESS) ? unlock_status : status);
+}
+
+/**
+ * @brief Cipher encrypt and decrypt function
+ *
+ * See @ref psa_cipher_encrypt(...)
+ * See @ref psa_cipher_decrypt(...)
+ *
+ * @param key
+ * @param alg
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @param direction Whether to encrypt or decrypt, see @ref psa_encrypt_or_decrypt_t
+ * @return @ref psa_status_t
+ */
+static psa_status_t psa_cipher_encrypt_decrypt( psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length,
+ psa_encrypt_or_decrypt_t direction)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!input || !output || !output_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!PSA_ALG_IS_CIPHER(alg)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ psa_key_usage_t usage = (direction == PSA_CRYPTO_DRIVER_ENCRYPT ?
+ PSA_KEY_USAGE_ENCRYPT :
+ PSA_KEY_USAGE_DECRYPT);
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot, usage, alg);
+ if (status != PSA_SUCCESS) {
+ unlock_status = psa_unlock_key_slot(slot);
+ if (unlock_status != PSA_SUCCESS) {
+ status = unlock_status;
+ }
+ return status;
+ }
+
+ if (((alg == PSA_ALG_CBC_NO_PADDING) || (alg == PSA_ALG_ECB_NO_PADDING)) &&
+ (input_length % PSA_BLOCK_CIPHER_BLOCK_LENGTH(slot->attr.type))) {
+ unlock_status = psa_unlock_key_slot(slot);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
+ if (output_size < PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(slot->attr.type, alg, input_length)) {
+ unlock_status = psa_unlock_key_slot(slot);
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ status = psa_location_dispatch_cipher_encrypt(&slot->attr, alg, slot, input, input_length,
+ output, output_size, output_length);
+ }
+ else {
+ size_t iv_length = PSA_CIPHER_IV_LENGTH(slot->attr.type, alg);
+ if (output_size < (input_length - iv_length)) {
+ /* Input buffer contains iv + cipher, so output must be at least input_length - IV */
+ unlock_status = psa_unlock_key_slot(slot);
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ status = psa_location_dispatch_cipher_decrypt(&slot->attr, alg, slot, input, input_length,
+ output, output_size, output_length);
+ }
+
+ unlock_status = psa_unlock_key_slot(slot);
+ return ((status == PSA_SUCCESS) ? unlock_status : status);
+}
+
+psa_status_t psa_cipher_decrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ return psa_cipher_encrypt_decrypt(key, alg, input, input_length, output, output_size,
+ output_length, PSA_CRYPTO_DRIVER_DECRYPT);
+}
+
+psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ return psa_cipher_setup(operation, key, alg, PSA_CRYPTO_DRIVER_DECRYPT);
+}
+
+psa_status_t psa_cipher_encrypt(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ return psa_cipher_encrypt_decrypt(key, alg, input, input_length, output, output_size,
+ output_length, PSA_CRYPTO_DRIVER_ENCRYPT);
+}
+
+psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ return psa_cipher_setup(operation, key, alg, PSA_CRYPTO_DRIVER_ENCRYPT);
+}
+
+psa_status_t psa_cipher_finish(psa_cipher_operation_t *operation,
+ uint8_t *output,
+ 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 psa_cipher_generate_iv(psa_cipher_operation_t *operation,
+ uint8_t *iv,
+ size_t iv_size,
+ size_t *iv_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!operation || !iv || !iv_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ *iv_length = 0;
+
+ if (!operation->iv_required || operation->iv_set) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (iv_size < operation->default_iv_length) {
+ psa_cipher_abort(operation);
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ status = psa_generate_random(iv, iv_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ operation->iv_set = 1;
+ *iv_length = iv_size;
+
+ return status;
+}
+
+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 psa_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)
+{
+ (void)operation;
+ (void)input;
+ (void)input_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
+ psa_algorithm_t alg)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!operation) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (operation->alg != 0) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!PSA_ALG_IS_HASH(alg)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ psa_status_t status = psa_algorithm_dispatch_hash_setup(operation, alg);
+ if (status == PSA_SUCCESS) {
+ operation->alg = alg;
+ }
+
+ return status;
+}
+
+psa_status_t psa_hash_update(psa_hash_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!operation || !input) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (operation->alg == 0) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ psa_status_t status = psa_algorithm_dispatch_hash_update(operation, input, input_length);
+
+ if (status != PSA_SUCCESS) {
+ psa_hash_abort(operation);
+ }
+ return status;
+}
+
+psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!operation || !hash || !hash_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (operation->alg == 0) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ uint8_t actual_hash_length = PSA_HASH_LENGTH(operation->alg);
+
+ if (hash_size < actual_hash_length) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ psa_status_t status =
+ psa_algorithm_dispatch_hash_finish(operation, hash, hash_size, hash_length);
+ if (status == PSA_SUCCESS) {
+ *hash_length = actual_hash_length;
+ }
+
+ /* Make sure operation becomes inactive after successful execution */
+ psa_hash_abort(operation);
+ return status;
+}
+
+psa_status_t psa_hash_verify(psa_hash_operation_t *operation,
+ const uint8_t *hash,
+ size_t hash_length)
+{
+ int status = PSA_ERROR_CORRUPTION_DETECTED;
+ uint8_t digest[PSA_HASH_MAX_SIZE];
+ size_t actual_hash_length = 0;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!operation || !hash) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_hash_finish(operation, digest, PSA_HASH_MAX_SIZE, &actual_hash_length);
+
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ if (actual_hash_length != hash_length) {
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ if (constant_time_memcmp(hash, digest, hash_length) != 0) {
+ return PSA_ERROR_INVALID_SIGNATURE;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_hash_suspend(psa_hash_operation_t *operation,
+ uint8_t *hash_state,
+ size_t hash_state_size,
+ size_t *hash_state_length)
+{
+ (void)operation;
+ (void)hash_state;
+ (void)hash_state_size;
+ (void)hash_state_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_hash_resume(psa_hash_operation_t *operation,
+ const uint8_t *hash_state,
+ size_t hash_state_length)
+{
+ (void)operation;
+ (void)hash_state;
+ (void)hash_state_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_hash_abort(psa_hash_operation_t *operation)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ *operation = psa_hash_operation_init();
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
+ psa_hash_operation_t *target_operation)
+{
+ (void)source_operation;
+ (void)target_operation;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_hash_compare(psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *hash,
+ size_t hash_length)
+{
+ psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!input || !hash) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_hash_setup(&operation, alg);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ status = psa_hash_update(&operation, input, input_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ status = psa_hash_verify(&operation, hash, hash_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_hash_compute(psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length)
+{
+ psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!input || !hash || !hash_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (hash_size < PSA_HASH_LENGTH(alg)) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ *hash_length = hash_size;
+ status = psa_hash_setup(&operation, alg);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ status = psa_hash_update(&operation, input, input_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ status = psa_hash_finish(&operation, hash, hash_size, hash_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ return PSA_SUCCESS;
+}
+
+/* Key Management */
+/**
+ * @brief Check whether the key policy is valid
+ *
+ * @param policy Policy of type @ref psa_key_policy_t of the key to be used
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ */
+static psa_status_t psa_validate_key_policy(const psa_key_policy_t *policy)
+{
+ if ((policy->usage & ~(PSA_KEY_USAGE_EXPORT |
+ PSA_KEY_USAGE_COPY |
+ PSA_KEY_USAGE_ENCRYPT |
+ PSA_KEY_USAGE_DECRYPT |
+ PSA_KEY_USAGE_SIGN_MESSAGE |
+ PSA_KEY_USAGE_VERIFY_MESSAGE |
+ PSA_KEY_USAGE_SIGN_HASH |
+ PSA_KEY_USAGE_VERIFY_HASH |
+ PSA_KEY_USAGE_DERIVE)) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return PSA_SUCCESS;
+}
+
+/**
+ * @brief Check whether the size of a symmetric key is supported
+ *
+ * @param type Type of the used key as @ref psa_key_type_t
+ * @param bits Size of the key as @c size_t
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ */
+static psa_status_t psa_validate_unstructured_key_size(psa_key_type_t type, size_t bits)
+{
+ switch (type) {
+ case PSA_KEY_TYPE_AES:
+ if (bits != 128 && bits != 192 && bits != 256) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ break;
+ case PSA_KEY_TYPE_HMAC:
+ if (bits % 8 != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ break;
+ default:
+ (void)bits;
+ return PSA_ERROR_NOT_SUPPORTED;
+ break;
+ }
+ return PSA_SUCCESS;
+}
+
+/**
+ * @brief Check whether the key size is valid for key generation
+ *
+ * @param type Type of the used key as @ref psa_key_type_t
+ * @param bits Size of the key as @c size_t
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ */
+static psa_status_t psa_validate_key_for_key_generation(psa_key_type_t type, size_t bits)
+{
+ if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) {
+ return psa_validate_unstructured_key_size(type, bits);
+ }
+#if IS_USED(MODULE_PSA_ASYMMETRIC) || IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC)
+ else if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type)) {
+ return PSA_ECC_KEY_SIZE_IS_VALID(bits) ? PSA_SUCCESS : PSA_ERROR_INVALID_ARGUMENT;
+ }
+#endif
+ /* TODO: add validation for other key types */
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+/**
+ * @brief Check validity of key attributes and get secure element driver in case the key is
+ * stored on a secure element
+ *
+ * @param attributes Key attributes that are to be checked
+ * @param p_drv Pointer which will contain the SE driver, if one exists
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ */
+static psa_status_t psa_validate_key_attributes(const psa_key_attributes_t *attributes,
+ psa_se_drv_data_t **p_drv)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+ psa_key_lifetime_t lifetime = psa_get_key_lifetime(attributes);
+ psa_key_id_t key = psa_get_key_id(attributes);
+
+ status = psa_validate_key_location(lifetime, p_drv);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ status = psa_validate_key_persistence(lifetime);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
+ if (key != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+ else {
+ if (!psa_is_valid_key_id(key, 0)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ status = psa_validate_key_policy(&attributes->policy);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ return PSA_SUCCESS;
+}
+
+/**
+ * @brief Set up a key creation process.
+ *
+ * Validate key attributes for key creation and find free slots and drivers if they exists.
+ *
+ * @param method Key creation method (see @ref psa_key_creation_method_t)
+ * @param attributes Key attributes of the key that should be created
+ * @param p_slot Pointer which will contain a key slot to store the key in
+ * @param p_drv Pointer to a SE driver if one exists for the given key location
+ *
+ * @return @ref psa_status_t
+ */
+static psa_status_t psa_start_key_creation(psa_key_creation_method_t method,
+ const psa_key_attributes_t *attributes,
+ psa_key_slot_t **p_slot, psa_se_drv_data_t **p_drv)
+{
+ psa_status_t status;
+ psa_key_id_t key_id;
+ psa_key_slot_t *slot;
+
+ *p_drv = NULL;
+
+ status = psa_validate_key_attributes(attributes, p_drv);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ status = psa_allocate_empty_key_slot(&key_id, attributes, p_slot);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ slot = *p_slot;
+ slot->attr = *attributes;
+
+ if (PSA_KEY_LIFETIME_IS_VOLATILE(slot->attr.lifetime)) {
+ slot->attr.id = key_id;
+ }
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ /* Find a free slot on a secure element and store SE slot number in key_data */
+ if (*p_drv != NULL) {
+ psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
+ status = psa_find_free_se_slot(attributes, method, *p_drv, slot_number);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ /* TODO: Start transaction for persistent key storage */
+ }
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+
+ (void)method;
+ return PSA_SUCCESS;
+}
+
+/**
+ * @brief Finish up key creation process
+ *
+ * @param slot Pointer to slot that the key is stored in
+ * @param driver SE driver, in case the key creation took place on a secure element
+ * @param key Pointer which will contain the key ID assigned to the key
+ *
+ * @return @ref psa_status_t
+ */
+static psa_status_t psa_finish_key_creation(psa_key_slot_t *slot, psa_se_drv_data_t *driver,
+ psa_key_id_t *key)
+{
+ psa_status_t status = PSA_SUCCESS;
+
+ *key = PSA_KEY_ID_NULL;
+ /* TODO: Finish persistent key storage */
+ /* TODO: Finish SE key storage with transaction */
+
+ if (status == PSA_SUCCESS) {
+ *key = slot->attr.id;
+ status = psa_unlock_key_slot(slot);
+ }
+ else {
+ (void)slot;
+ }
+
+ (void)driver;
+ return status;
+}
+
+/**
+ * @brief Abort key creation and clean up in case of failure
+ *
+ * @param slot Slot that the key has been written to
+ * @param driver SE driver, in case the key creation took place on a secure element
+ */
+static void psa_fail_key_creation(psa_key_slot_t *slot, psa_se_drv_data_t *driver)
+{
+ (void)driver;
+ if (slot == NULL) {
+ return;
+ }
+ /* TODO: Destroy key in secure element (see mbedtls code) */
+ /* TODO: Secure Element stop transaction */
+ psa_wipe_key_slot(slot);
+}
+
+psa_status_t psa_copy_key(psa_key_id_t source_key,
+ const psa_key_attributes_t *attributes,
+ psa_key_id_t *target_key)
+{
+ (void)source_key;
+ (void)attributes;
+ (void)target_key;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_destroy_key(psa_key_id_t key)
+{
+ psa_status_t status;
+ psa_key_slot_t *slot;
+
+ status = psa_get_and_lock_key_slot(key, &slot);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ if (slot->lock_count > 1) {
+ return PSA_ERROR_CORRUPTION_DETECTED;
+ }
+
+ return psa_wipe_key_slot(slot);
+}
+
+psa_status_t psa_export_key(psa_key_id_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length)
+{
+ (void)key;
+ (void)data;
+ (void)data_size;
+ (void)data_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+/**
+ * @brief Export asymmetric public key that is stored in local memory
+ *
+ * See @ref psa_export_public_key
+ *
+ * @param key_buffer
+ * @param key_buffer_size
+ * @param data
+ * @param data_size
+ * @param data_length
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ */
+static psa_status_t psa_builtin_export_public_key( const uint8_t *key_buffer,
+ size_t key_buffer_size,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length)
+{
+ if (key_buffer_size == 0 || data_size == 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (data_size < key_buffer_size) {
+ DEBUG("PSA Crypto Builtin Export Key: Output buffer too small\n");
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+ /** Some implementations and drivers can generate a public key from existing private key
+ * material. This implementation does not support the recalculation of a public key, yet.
+ * It requires the key to already exist in local memory and just copies it into the data
+ * output. */
+ memcpy(data, key_buffer, key_buffer_size);
+ *data_length = key_buffer_size;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_export_public_key(psa_key_id_t key,
+ uint8_t *data,
+ size_t data_size,
+ size_t *data_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+ uint8_t *pubkey_data = NULL;
+ size_t *pubkey_data_len = NULL;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!data || !data_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ *data_length = 0;
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot, 0, 0);
+ if (status != PSA_SUCCESS) {
+ unlock_status = psa_unlock_key_slot(slot);
+ if (unlock_status != PSA_SUCCESS) {
+ status = unlock_status;
+ }
+ return status;
+ }
+
+ if ((data_size == 0) ||
+ (data_size < PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(slot->attr.type, slot->attr.bits))) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (!PSA_KEY_TYPE_IS_ECC(slot->attr.type)) {
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ unlock_status = psa_unlock_key_slot(slot);
+ return status;
+ }
+ psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
+
+ status =
+ psa_builtin_export_public_key(pubkey_data, *pubkey_data_len, data, data_size, data_length);
+
+ unlock_status = psa_unlock_key_slot(slot);
+ return ((status == PSA_SUCCESS) ? unlock_status : status);
+}
+
+psa_status_t psa_builtin_generate_key(const psa_key_attributes_t *attributes, uint8_t *key_buffer,
+ size_t key_buffer_size, size_t *key_buffer_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ if (!attributes || !key_buffer || !key_buffer_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ psa_key_type_t type = attributes->type;
+
+ if (PSA_KEY_TYPE_IS_UNSTRUCTURED(type)) {
+ status = psa_generate_random(key_buffer, key_buffer_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ *key_buffer_length = key_buffer_size;
+ return PSA_SUCCESS;
+ }
+ (void)key_buffer;
+ (void)key_buffer_size;
+ (void)key_buffer_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
+ psa_key_id_t *key)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot = NULL;
+ psa_se_drv_data_t *driver = NULL;
+
+ *key = PSA_KEY_ID_NULL;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!attributes || !key) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (psa_get_key_bits(attributes) == 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* Find empty slot */
+ status = psa_start_key_creation(PSA_KEY_CREATION_GENERATE, attributes, &slot, &driver);
+ if (status != PSA_SUCCESS) {
+ psa_fail_key_creation(slot, driver);
+ return status;
+ }
+
+ if (PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime) == PSA_KEY_LOCATION_LOCAL_STORAGE) {
+ status = psa_validate_key_for_key_generation(attributes->type, attributes->bits);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ slot->key.data_len = PSA_MAX_KEY_DATA_SIZE;
+ }
+
+ status = psa_location_dispatch_generate_key(attributes, slot);
+
+ if (status != PSA_SUCCESS) {
+ psa_fail_key_creation(slot, driver);
+ return status;
+ }
+
+ status = psa_finish_key_creation(slot, driver, key);
+
+ if (status != PSA_SUCCESS) {
+ psa_fail_key_creation(slot, driver);
+ }
+
+ return status;
+}
+
+psa_status_t psa_builtin_generate_random( uint8_t *output,
+ size_t output_size)
+{
+ if (!output) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* TODO: Should point to a CSPRNG API in the future */
+ random_bytes(output, output_size);
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_generate_random(uint8_t *output,
+ size_t output_size)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!output) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return psa_location_dispatch_generate_random(output, output_size);
+}
+
+psa_status_t psa_get_key_attributes(psa_key_id_t key,
+ psa_key_attributes_t *attributes)
+{
+ psa_status_t status;
+ psa_key_slot_t *slot = NULL;
+
+ if (!attributes) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ psa_reset_key_attributes(attributes);
+
+ status = psa_get_and_lock_key_slot(key, &slot);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ *attributes = slot->attr;
+
+ status = psa_unlock_key_slot(slot);
+ return status;
+}
+
+psa_status_t psa_builtin_import_key(const psa_key_attributes_t *attributes,
+ const uint8_t *data, size_t data_length,
+ uint8_t *key_buffer, size_t key_buffer_size,
+ size_t *key_buffer_length, size_t *bits)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ if (!attributes || !data || !key_buffer || !key_buffer_length || !bits) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (data_length == 0) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (data_length > key_buffer_size) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ psa_key_type_t type = attributes->type;
+
+ 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;
+ }
+
+ memcpy(key_buffer, data, data_length);
+ *key_buffer_length = data_length;
+
+ return PSA_SUCCESS;
+ }
+ else if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(type)) {
+ if (data_length > PSA_EXPORT_PUBLIC_KEY_MAX_SIZE) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ memcpy(key_buffer, data, data_length);
+ *key_buffer_length = data_length;
+ return PSA_SUCCESS;
+ }
+ return status;
+}
+
+psa_status_t psa_import_key(const psa_key_attributes_t *attributes,
+ const uint8_t *data,
+ size_t data_length,
+ psa_key_id_t *key)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot = NULL;
+ psa_se_drv_data_t *driver = NULL;
+ size_t bits;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!attributes || !data) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (attributes->bits != 0 && attributes->bits > PSA_BYTES_TO_BITS(data_length)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ *key = PSA_KEY_ID_NULL;
+
+ /* Find empty slot */
+ status = psa_start_key_creation(PSA_KEY_CREATION_IMPORT, attributes, &slot, &driver);
+ if (status != PSA_SUCCESS) {
+ psa_fail_key_creation(slot, driver);
+ return status;
+ }
+
+ bits = slot->attr.bits;
+
+ status = psa_location_dispatch_import_key(attributes, data, data_length, slot, &bits);
+
+ if (status != PSA_SUCCESS) {
+ psa_fail_key_creation(slot, driver);
+ return status;
+ }
+
+ if (slot->attr.bits == 0) {
+ slot->attr.bits = (psa_key_bits_t)bits;
+ }
+ else if (bits != slot->attr.bits) {
+ psa_fail_key_creation(slot, driver);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_finish_key_creation(slot, driver, key);
+ if (status != PSA_SUCCESS) {
+ psa_fail_key_creation(slot, driver);
+ }
+
+ return status;
+}
+
+psa_status_t psa_key_derivation_abort(psa_key_derivation_operation_t *operation)
+{
+ (void)operation;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_get_capacity(const psa_key_derivation_operation_t *operation,
+ size_t *capacity)
+{
+ (void)operation;
+ (void)capacity;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_input_bytes(psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ const uint8_t *data,
+ size_t data_length)
+{
+ (void)operation;
+ (void)step;
+ (void)data;
+ (void)data_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_input_key(psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ psa_key_id_t key)
+{
+ (void)operation;
+ (void)step;
+ (void)key;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t *operation,
+ psa_key_derivation_step_t step,
+ psa_key_id_t private_key,
+ const uint8_t *peer_key,
+ size_t peer_key_length)
+{
+ (void)operation;
+ (void)step;
+ (void)private_key;
+ (void)peer_key;
+ (void)peer_key_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_output_bytes(psa_key_derivation_operation_t *operation,
+ uint8_t *output,
+ size_t output_length)
+{
+ (void)operation;
+ (void)output;
+ (void)output_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_output_key(const psa_key_attributes_t *attributes,
+ psa_key_derivation_operation_t *operation,
+ psa_key_id_t *key)
+{
+ (void)attributes;
+ (void)operation;
+ (void)key;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *operation,
+ size_t capacity)
+{
+ (void)operation;
+ (void)capacity;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation,
+ psa_algorithm_t alg)
+{
+ (void)operation;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_mac_abort(psa_mac_operation_t *operation)
+{
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ *operation = psa_mac_operation_init();
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+/**
+ * @brief Validate algorithm and key for a MAC operation
+ *
+ * @param attr Attributes of the key that is supposed to be used
+ * @param alg Algorithm for performing the MAC operation
+ * @param mac_size Size of the MAC that is to be generated
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ * @ref PSA_ERROR_INVALID_ARGUMENT
+ */
+static psa_status_t psa_mac_validate_alg_and_key_and_size(psa_key_attributes_t *attr,
+ psa_algorithm_t alg,
+ size_t mac_size)
+{
+ psa_key_type_t type = psa_get_key_type(attr);
+ psa_key_bits_t bits = psa_get_key_bits(attr);
+
+ if (!PSA_ALG_IS_HMAC(alg) || (PSA_ALG_GET_HASH(alg) != PSA_ALG_SHA_256)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ size_t operation_mac_size = PSA_MAC_LENGTH(type, bits, alg);
+
+ if (operation_mac_size < 4) {
+ /**
+ * A very short MAC is too short for security since it can be
+ * brute-forced. Ancient protocols with 32-bit MACs do exist,
+ * so we make this our minimum, even though 32 bits is still
+ * too small for security.
+ */
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (operation_mac_size > PSA_MAC_MAX_SIZE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (mac_size < operation_mac_size) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_mac_compute(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_attributes_t attr = psa_key_attributes_init();
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!input || !mac || !mac_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_get_key_attributes(key, &attr);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ status = psa_mac_validate_alg_and_key_and_size(&attr, alg, mac_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot, attr.policy.usage, alg);
+ if (status != PSA_SUCCESS) {
+ unlock_status = psa_unlock_key_slot(slot);
+ if (unlock_status != PSA_SUCCESS) {
+ status = unlock_status;
+ }
+ return status;
+ }
+
+ status = psa_location_dispatch_mac_compute(&slot->attr, alg, slot, input, input_length, mac,
+ mac_size, mac_length);
+
+ unlock_status = psa_unlock_key_slot(slot);
+ return ((status == PSA_SUCCESS) ? unlock_status : status);
+
+}
+
+psa_status_t psa_mac_sign_finish(psa_mac_operation_t *operation,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ (void)operation;
+ (void)mac;
+ (void)mac_size;
+ (void)mac_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_mac_sign_setup(psa_mac_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ (void)operation;
+ (void)key;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_mac_update(psa_mac_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ (void)operation;
+ (void)input;
+ (void)input_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_mac_verify(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *mac,
+ size_t mac_length)
+{
+ (void)key;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)mac;
+ (void)mac_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation,
+ const uint8_t *mac,
+ size_t mac_length)
+{
+ (void)operation;
+ (void)mac;
+ (void)mac_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_mac_verify_setup(psa_mac_operation_t *operation,
+ psa_key_id_t key,
+ psa_algorithm_t alg)
+{
+ (void)operation;
+ (void)key;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_purge_key(psa_key_id_t key)
+{
+ (void)key;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
+ psa_key_id_t private_key,
+ const uint8_t *peer_key,
+ size_t peer_key_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ (void)alg;
+ (void)private_key;
+ (void)peer_key;
+ (void)peer_key_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_sign_hash(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!hash || !signature || !signature_length) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!PSA_ALG_IS_ECDSA(alg)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (hash_length != PSA_HASH_LENGTH(alg)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot, PSA_KEY_USAGE_SIGN_HASH, alg);
+ if (status != PSA_SUCCESS) {
+ unlock_status = psa_unlock_key_slot(slot);
+ return status;
+ }
+
+ if (signature_size < PSA_SIGN_OUTPUT_SIZE(slot->attr.type, slot->attr.bits, alg)) {
+ return PSA_ERROR_BUFFER_TOO_SMALL;
+ }
+
+ if (!PSA_KEY_TYPE_IS_KEY_PAIR(slot->attr.type)) {
+ unlock_status = psa_unlock_key_slot(slot);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ psa_key_attributes_t attributes = slot->attr;
+
+ status = psa_location_dispatch_sign_hash(&attributes, alg, slot, hash, hash_length, signature,
+ signature_size, signature_length);
+
+ unlock_status = psa_unlock_key_slot(slot);
+ return ((status == PSA_SUCCESS) ? unlock_status : status);
+}
+
+psa_status_t psa_sign_message(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length)
+{
+ (void)key;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)signature;
+ (void)signature_size;
+ (void)signature_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_verify_hash(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *slot;
+
+ if (!lib_initialized) {
+ return PSA_ERROR_BAD_STATE;
+ }
+
+ if (!hash || !signature) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (!PSA_ALG_IS_ECDSA(alg)) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (hash_length != PSA_HASH_LENGTH(alg)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ status = psa_get_and_lock_key_slot_with_policy(key, &slot, PSA_KEY_USAGE_VERIFY_HASH, alg);
+ if (status != PSA_SUCCESS) {
+ unlock_status = psa_unlock_key_slot(slot);
+ return status;
+ }
+
+ /**
+ * An ECC public key has the size `curve_bytes * 2 + 1`.
+ * So to get the curve size to determine the required signature
+ * size, we need to revert that calculation.
+ */
+ uint16_t curve_size = PSA_BYTES_TO_BITS(PSA_BITS_TO_BYTES(slot->attr.bits / 2) - 1);
+
+ if (signature_length != PSA_ECDSA_SIGNATURE_SIZE(curve_size)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /**
+ * When key location is a secure element, this implementation only supports
+ * the use of public keys stored on the secure element, not key pairs in
+ * which the public key is stored locally.
+ */
+ if ((PSA_KEY_LIFETIME_GET_LOCATION(slot->attr.lifetime) != PSA_KEY_LOCATION_LOCAL_STORAGE) &&
+ PSA_KEY_TYPE_IS_ECC_KEY_PAIR(slot->attr.type)) {
+ unlock_status = psa_unlock_key_slot(slot);
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ psa_key_attributes_t attributes = slot->attr;
+
+ status = psa_location_dispatch_verify_hash(&attributes, alg, slot, hash, hash_length, signature,
+ signature_length);
+
+ unlock_status = psa_unlock_key_slot(slot);
+ return ((status == PSA_SUCCESS) ? unlock_status : status);
+}
+
+psa_status_t psa_verify_message(psa_key_id_t key,
+ psa_algorithm_t alg,
+ const uint8_t *input,
+ size_t input_length,
+ const uint8_t *signature,
+ size_t signature_length)
+{
+ (void)key;
+ (void)alg;
+ (void)input;
+ (void)input_length;
+ (void)signature;
+ (void)signature_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
diff --git a/sys/psa_crypto/psa_crypto_algorithm_dispatch.c b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c
new file mode 100644
index 0000000000..caf5cda7d7
--- /dev/null
+++ b/sys/psa_crypto/psa_crypto_algorithm_dispatch.c
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto sys_psa_crypto_alg_disp
+ * @{
+ *
+ * @file
+ * @brief Dispatch calls from the PSA Crypto API to an available backend.
+ *
+ * @author Lena Boeckmann
+ *
+ * @}
+ */
+
+#include
+#include "kernel_defines.h"
+#include "psa/crypto.h"
+#include "psa_mac.h"
+#include "psa_hashes.h"
+#include "psa_ecc.h"
+#include "psa_ciphers.h"
+#include "psa_crypto_operation_encoder.h"
+
+psa_status_t psa_algorithm_dispatch_hash_setup(psa_hash_operation_t *operation,
+ psa_algorithm_t alg)
+{
+ psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
+
+ switch (alg) {
+ #if (IS_USED(MODULE_PSA_HASH_MD5))
+ case PSA_ALG_MD5:
+ status = psa_hashes_md5_setup(&operation->ctx.md5);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_1))
+ case PSA_ALG_SHA_1:
+ status = psa_hashes_sha1_setup(&operation->ctx.sha1);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_224))
+ case PSA_ALG_SHA_224:
+ status = psa_hashes_sha224_setup(&operation->ctx.sha224);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_256))
+ case PSA_ALG_SHA_256:
+ status = psa_hashes_sha256_setup(&operation->ctx.sha256);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_512))
+ case PSA_ALG_SHA_512:
+ status = psa_hashes_sha512_setup(&operation->ctx.sha512);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ #endif
+ default:
+ (void)status;
+ (void)operation;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ operation->alg = alg;
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_algorithm_dispatch_hash_update(psa_hash_operation_t *operation,
+ const uint8_t *input,
+ size_t input_length)
+{
+ switch (operation->alg) {
+ #if (IS_USED(MODULE_PSA_HASH_MD5))
+ case PSA_ALG_MD5:
+ return psa_hashes_md5_update(&operation->ctx.md5, input, input_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_1))
+ case PSA_ALG_SHA_1:
+ return psa_hashes_sha1_update(&operation->ctx.sha1, input, input_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_224))
+ case PSA_ALG_SHA_224:
+ return psa_hashes_sha224_update(&operation->ctx.sha224, input, input_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_256))
+ case PSA_ALG_SHA_256:
+ return psa_hashes_sha256_update(&operation->ctx.sha256, input, input_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_512))
+ case PSA_ALG_SHA_512:
+ return psa_hashes_sha512_update(&operation->ctx.sha512, input, input_length);
+ #endif
+ default:
+ (void)operation;
+ (void)input;
+ (void)input_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+}
+
+psa_status_t psa_algorithm_dispatch_hash_finish(psa_hash_operation_t *operation,
+ uint8_t *hash,
+ size_t hash_size,
+ size_t *hash_length)
+{
+ switch (operation->alg) {
+ #if (IS_USED(MODULE_PSA_HASH_MD5))
+ case PSA_ALG_MD5:
+ return psa_hashes_md5_finish(&operation->ctx.md5, hash, hash_size, hash_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_1))
+ case PSA_ALG_SHA_1:
+ return psa_hashes_sha1_finish(&operation->ctx.sha1, hash, hash_size, hash_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_224))
+ case PSA_ALG_SHA_224:
+ return psa_hashes_sha224_finish(&operation->ctx.sha224, hash, hash_size, hash_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_256))
+ case PSA_ALG_SHA_256:
+ return psa_hashes_sha256_finish(&operation->ctx.sha256, hash, hash_size, hash_length);
+ #endif
+ #if (IS_USED(MODULE_PSA_HASH_SHA_512))
+ case PSA_ALG_SHA_512:
+ return psa_hashes_sha512_finish(&operation->ctx.sha512, hash, hash_size, hash_length);
+ #endif
+ default:
+ (void)operation;
+ (void)hash;
+ (void)hash_size;
+ (void)hash_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+}
+
+psa_status_t psa_algorithm_dispatch_sign_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length)
+{
+ psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
+ uint8_t *key_data = NULL;
+ size_t *key_bytes = NULL;
+
+ if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) {
+ asym_key =
+ PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type));
+
+ if (asym_key == PSA_INVALID_OPERATION) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
+
+ switch (asym_key) {
+#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
+ case PSA_ECC_P192_R1:
+ return psa_ecc_p192r1_sign_hash(attributes, alg, key_data, *key_bytes, hash, hash_length,
+ signature, signature_size, signature_length);
+#endif
+#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
+ case PSA_ECC_P256_R1:
+ return psa_ecc_p256r1_sign_hash(attributes, alg, key_data, *key_bytes, hash, hash_length,
+ signature, signature_size, signature_length);
+#endif
+ default:
+ (void)alg;
+ (void)slot;
+ (void)hash;
+ (void)hash_length;
+ (void)signature;
+ (void)signature_size;
+ (void)signature_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+}
+
+psa_status_t psa_algorithm_dispatch_verify_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length)
+{
+ psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
+ uint8_t *pubkey_data = NULL;
+ size_t *pubkey_data_len = NULL;
+
+ if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
+ asym_key =
+ PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type));
+
+ if (asym_key == PSA_INVALID_OPERATION) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
+
+ switch (asym_key) {
+#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
+ case PSA_ECC_P192_R1:
+ return psa_ecc_p192r1_verify_hash(attributes, alg, pubkey_data, *pubkey_data_len, hash,
+ hash_length, signature, signature_length);
+#endif
+#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
+ case PSA_ECC_P256_R1:
+ return psa_ecc_p256r1_verify_hash(attributes, alg, pubkey_data, *pubkey_data_len, hash,
+ hash_length, signature, signature_length);
+#endif
+ default:
+ (void)alg;
+ (void)slot;
+ (void)hash;
+ (void)hash_length;
+ (void)signature;
+ (void)signature_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+}
+
+psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes,
+ psa_key_slot_t *slot)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ uint8_t *key_data = NULL;
+ size_t *key_bytes = NULL;
+
+ psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
+
+ /**
+ * Only asymmetric key generation needs special key generation algorithms. Symmetric keys can
+ * be created by generating random bytes.
+ */
+ if (PSA_KEY_TYPE_IS_ASYMMETRIC(attributes->type)) {
+ psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
+ uint8_t *pubkey_data = NULL;
+ size_t *pubkey_data_len = NULL;
+ psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
+
+ if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) {
+ asym_key =
+ PSA_ENCODE_ECC_KEY_TYPE(attributes->bits,
+ PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type));
+
+ if (asym_key == PSA_INVALID_OPERATION) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ switch (asym_key) {
+#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
+ case PSA_ECC_P192_R1:
+ return psa_generate_ecc_p192r1_key_pair(attributes, key_data, pubkey_data, key_bytes,
+ pubkey_data_len);
+#endif
+#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
+ case PSA_ECC_P256_R1:
+ return psa_generate_ecc_p256r1_key_pair(attributes, key_data, pubkey_data, key_bytes,
+ pubkey_data_len);
+#endif
+ default:
+ (void)status;
+ (void)slot;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ }
+
+ return psa_builtin_generate_key(attributes, key_data, *key_bytes, key_bytes);
+}
+
+psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type);
+ uint8_t *key_data = NULL;
+ size_t *key_bytes = NULL;
+
+ psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
+
+ if (op == PSA_INVALID_OPERATION) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ 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,
+ 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
+ default:
+ (void)slot;
+ (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_decrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type);
+ uint8_t *key_data = NULL;
+ size_t *key_bytes = NULL;
+
+ psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
+
+ if (op == PSA_INVALID_OPERATION) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ 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,
+ 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
+ default:
+ (void)slot;
+ (void)input;
+ (void)input_length;
+ (void)output;
+ (void)output_size;
+ (void)output_length;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+}
+
+psa_status_t psa_algorithm_dispatch_mac_compute(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+ psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
+ uint8_t *key_data = NULL;
+ size_t *key_bytes = NULL;
+
+ psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
+
+ switch (alg) {
+ #if IS_USED(MODULE_PSA_MAC_HMAC_SHA_256)
+ case PSA_ALG_HMAC(PSA_ALG_SHA_256):
+ status = psa_mac_compute_hmac_sha256(attributes, key_data, *key_bytes, input, input_length,
+ mac, mac_size, mac_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ break;
+ #endif
+ default:
+ (void)status;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ (void)attributes;
+ (void)input;
+ (void)input_length;
+ (void)mac;
+ (void)mac_size;
+ (void)mac_length;
+ return PSA_SUCCESS;
+}
diff --git a/sys/psa_crypto/psa_crypto_location_dispatch.c b/sys/psa_crypto/psa_crypto_location_dispatch.c
new file mode 100644
index 0000000000..c5d03c55c6
--- /dev/null
+++ b/sys/psa_crypto/psa_crypto_location_dispatch.c
@@ -0,0 +1,441 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto sys_psa_crypto_loc_disp
+ * @{
+ *
+ * @file
+ * @brief Dispatch calls from the PSA Crypto API to an available backend.
+ *
+ * @author Lena Boeckmann
+ *
+ * @}
+ */
+
+#include
+#include "kernel_defines.h"
+#include "psa/crypto.h"
+#include "psa_crypto_algorithm_dispatch.h"
+#include "psa_crypto_slot_management.h"
+#include "psa_crypto_se_management.h"
+#include "psa_crypto_se_driver.h"
+
+psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes,
+ psa_key_slot_t *slot)
+{
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ psa_status_t status;
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
+
+ uint8_t *pubkey_data = NULL;
+ size_t *pubkey_data_len = NULL;
+
+ psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
+
+ if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
+ if (drv->key_management == NULL || drv->key_management->p_generate == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ status = drv->key_management->p_generate(drv_context, *slot_number, attributes, pubkey_data,
+ *pubkey_data_len, pubkey_data_len);
+ if (status != PSA_SUCCESS) {
+ /* In case anything goes wrong, free the key slot for reuse. */
+ psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime);
+ psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number);
+ return abort_status == PSA_SUCCESS ? status : abort_status;
+ }
+ return PSA_SUCCESS;
+ }
+#endif /* MODULE_PSA_SECURE_ELEMENT */
+
+ return psa_algorithm_dispatch_generate_key(attributes, slot);
+}
+
+psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes,
+ const uint8_t *data, size_t data_length,
+ psa_key_slot_t *slot, size_t *bits)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime);
+ uint8_t *key_data = NULL;
+ size_t *key_bytes = NULL;
+ size_t key_data_size;
+
+ key_data_size = psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
+
+ if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
+ if (drv->key_management == NULL || drv->key_management->p_import == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ *bits = 0;
+
+ status = drv->key_management->p_import(drv_context, *slot_number,
+ attributes, data,
+ data_length, bits);
+ if (status != PSA_SUCCESS) {
+ /* In case anything goes wrong, free the key slot for reuse. */
+ psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime);
+ psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number);
+ return abort_status == PSA_SUCCESS ? status : abort_status;
+ }
+ return PSA_SUCCESS;
+ }
+#endif /* MODULE_PSA_SECURE_ELEMENT */
+
+ switch (location) {
+ case PSA_KEY_LOCATION_LOCAL_STORAGE:
+ return psa_builtin_import_key(attributes, data, data_length, key_data, key_data_size, key_bytes, bits);
+ default:
+ (void)status;
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+}
+
+psa_status_t psa_location_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)
+{
+#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_ENCRYPT);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ return PSA_SUCCESS;
+ }
+ }
+#endif /* MODULE_PSA_SECURE_ELEMENT */
+ (void)operation;
+ (void)attributes;
+ (void)slot;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_location_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)
+{
+ (void)operation;
+ (void)attributes;
+ (void)slot;
+ (void)alg;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+/**
+ * @brief Single part function for cipher encryption and decryption on a secure element
+ *
+ * Some secure elements don't provide single part operations for cipher encryption.
+ * This is a wrapper function, to support those.
+ *
+ * @param drv
+ * @param drv_context
+ * @param attributes
+ * @param alg
+ * @param direction
+ * @param slot
+ * @param input
+ * @param input_length
+ * @param output
+ * @param output_size
+ * @param output_length
+ * @return @ref psa_status_t
+ */
+static psa_status_t psa_se_cipher_encrypt_decrypt( const psa_drv_se_t *drv,
+ psa_drv_se_context_t *drv_context,
+ const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ psa_encrypt_or_decrypt_t direction,
+ psa_key_slot_number_t slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *output,
+ size_t output_size,
+ size_t *output_length)
+{
+ psa_status_t status;
+ psa_cipher_operation_t operation = psa_cipher_operation_init();
+ psa_se_cipher_context_t *se_ctx = &operation.backend_ctx.se_ctx;
+ size_t input_offset = 0;
+ size_t output_offset = 0;
+
+ *output_length = 0;
+
+ if (drv->cipher == NULL ||
+ drv->cipher->p_setup == NULL ||
+ drv->cipher->p_set_iv == NULL ||
+ drv->cipher->p_update == NULL ||
+ drv->cipher->p_finish == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ status = drv->cipher->p_setup(drv_context, se_ctx, slot, alg, direction);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ if (alg == PSA_ALG_CBC_NO_PADDING) {
+ operation.iv_required = 1;
+ operation.default_iv_length = PSA_CIPHER_IV_LENGTH(psa_get_key_type(attributes), alg);
+
+ if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
+ /* In case of encryption, we need to generate and set an IV. The IV will be written
+ into the first 16 bytes of the output buffer. */
+ size_t iv_length = 0;
+ status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length,
+ &iv_length);
+
+ status = drv->cipher->p_set_iv(se_ctx, output, iv_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ /* Increase output buffer offset to IV length to write ciphertext to buffer after IV */
+ output_offset += iv_length;
+ *output_length += iv_length;
+ }
+ else {
+ /* In case of decryption the IV to be used must be provided by the caller and is
+ contained in the first 16 Bytes of the input buffer. */
+ status = drv->cipher->p_set_iv(se_ctx, input, operation.default_iv_length);
+
+ /* Increase input buffer offset to IV length to start decryption
+ with actual cipher text */
+ input_offset += operation.default_iv_length;
+ }
+ }
+
+ status = drv->cipher->p_update(se_ctx, input + input_offset, input_length - input_offset,
+ output + output_offset, output_size - output_offset,
+ output_length);
+ if (status != PSA_SUCCESS) {
+ psa_cipher_abort(&operation);
+ return status;
+ }
+
+ status = drv->cipher->p_finish(se_ctx, output, output_size, output_length);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ return PSA_SUCCESS;
+}
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+
+psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ 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)
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
+
+ if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
+ if (alg == PSA_ALG_ECB_NO_PADDING) {
+ if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_ENCRYPT,
+ input, input_length, output, output_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ }
+
+ /* The SE interface does not support single part functions for other algorithms than ECB,
+ so we need to build one ourselves */
+ status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg,
+ PSA_CRYPTO_DRIVER_ENCRYPT, *slot_number, input,
+ input_length, output, output_size, output_length);
+
+ return status;
+ }
+
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+ return psa_algorithm_dispatch_cipher_encrypt(attributes, alg, slot, input, input_length, output,
+ output_size, output_length);
+}
+
+psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ 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)
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
+
+ if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
+ if (alg == PSA_ALG_ECB_NO_PADDING) {
+ if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_DECRYPT,
+ input, input_length, output, output_size);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ }
+
+ status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg,
+ PSA_CRYPTO_DRIVER_DECRYPT, *slot_number, input,
+ input_length, output, output_size, output_length);
+
+ return status;
+ }
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+ return psa_algorithm_dispatch_cipher_decrypt(attributes, alg, slot, input, input_length,
+ output, output_size, output_length);
+}
+
+psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ uint8_t *signature,
+ size_t signature_size,
+ size_t *signature_length)
+{
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ 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->asymmetric == NULL || drv->asymmetric->p_sign == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ return drv->asymmetric->p_sign(drv_context, *slot_number, alg, hash, hash_length, signature,
+ signature_size, signature_length);
+ }
+
+ (void)key_bytes;
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+
+ return psa_algorithm_dispatch_sign_hash(attributes, alg, slot, hash, hash_length, signature,
+ signature_size, signature_length);
+}
+
+psa_status_t psa_location_dispatch_verify_hash(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *hash,
+ size_t hash_length,
+ const uint8_t *signature,
+ size_t signature_length)
+{
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ 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->asymmetric == NULL || drv->asymmetric->p_verify == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+ return drv->asymmetric->p_verify(drv_context, *slot_number, alg, hash, hash_length,
+ signature, signature_length);
+ }
+
+ (void)key_bytes;
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+
+ return psa_algorithm_dispatch_verify_hash(attributes, alg, slot, hash, hash_length, signature,
+ signature_length);
+}
+
+psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes,
+ psa_algorithm_t alg,
+ const psa_key_slot_t *slot,
+ const uint8_t *input,
+ size_t input_length,
+ uint8_t *mac,
+ size_t mac_size,
+ size_t *mac_length)
+{
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ const psa_drv_se_t *drv;
+ psa_drv_se_context_t *drv_context;
+ 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->mac == NULL || drv->mac->p_mac == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ return drv->mac->p_mac(drv_context, input, input_length, *slot_number, alg, mac, mac_size,
+ mac_length);
+ }
+
+ (void)key_bytes;
+#endif /* CONFIG_PSA_SECURE_ELEMENT */
+
+ return psa_algorithm_dispatch_mac_compute(attributes, alg, slot, input, input_length, mac,
+ mac_size, mac_length);
+}
+
+psa_status_t psa_location_dispatch_generate_random(uint8_t *output,
+ size_t output_size)
+{
+ return psa_builtin_generate_random(output, output_size);
+}
diff --git a/sys/psa_crypto/psa_key_slot_mgmt/Kconfig b/sys/psa_crypto/psa_key_slot_mgmt/Kconfig
new file mode 100644
index 0000000000..a064bf1b25
--- /dev/null
+++ b/sys/psa_crypto/psa_key_slot_mgmt/Kconfig
@@ -0,0 +1,10 @@
+# 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.
+#
+
+config MODULE_PSA_KEY_SLOT_MGMT
+ bool
+ default y if PACKAGE_PSA_ARCH_TESTS
diff --git a/sys/psa_crypto/psa_key_slot_mgmt/Makefile b/sys/psa_crypto/psa_key_slot_mgmt/Makefile
new file mode 100644
index 0000000000..3d213aadd6
--- /dev/null
+++ b/sys/psa_crypto/psa_key_slot_mgmt/Makefile
@@ -0,0 +1,4 @@
+MODULE := psa_key_slot_mgmt
+INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c b/sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c
new file mode 100644
index 0000000000..e50317bde4
--- /dev/null
+++ b/sys/psa_crypto/psa_key_slot_mgmt/psa_crypto_slot_management.c
@@ -0,0 +1,539 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto sys_psa_crypto_slot_mgmt
+ * @{
+ *
+ * @file
+ * @brief PSA Crypto Key Slot Management implementation
+ *
+ * @author Lena Boeckmann
+ *
+ * @}
+ */
+
+#include "clist.h"
+#include "psa_crypto_slot_management.h"
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+/**
+ * @brief Structure for a protected key slot.
+ *
+ * These slots hold Slot Numbers for keys in protected storage and, if the key type is an
+ * asymmetric key pair, the public key.
+ */
+typedef struct {
+ clist_node_t node;
+ size_t lock_count;
+ psa_key_attributes_t attr;
+ struct prot_key_data {
+ psa_key_slot_number_t slot_number;
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC)
+ uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+ size_t pubkey_data_len;
+#endif
+ } key;
+} psa_prot_key_slot_t;
+
+/**
+ * @brief Array containing the protected key slots
+ */
+static psa_prot_key_slot_t protected_key_slots[PSA_PROTECTED_KEY_COUNT];
+
+/**
+ * @brief List pointing to empty protected key slots
+ */
+static clist_node_t protected_list_empty;
+#endif /* MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC */
+
+#if IS_USED(MODULE_PSA_ASYMMETRIC)
+/**
+ * @brief Structure for asymmetric key pairs.
+ *
+ * Contains asymmetric private and public key pairs.
+ *
+ */
+typedef struct {
+ clist_node_t node;
+ size_t lock_count;
+ psa_key_attributes_t attr;
+ struct key_pair_data {
+ /** Contains asymmetric private key*/
+ uint8_t privkey_data[PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE)];
+ /** Contains actual size of asymmetric private key */
+ size_t privkey_data_len;
+ /** Contains asymmetric public key */
+ uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+ /*!< Contains actual size of asymmetric private key */
+ size_t pubkey_data_len;
+ } key;
+} psa_key_pair_slot_t;
+
+/**
+ * @brief Array containing the asymmetric key slots
+ */
+static psa_key_pair_slot_t key_pair_slots[PSA_ASYMMETRIC_KEYPAIR_COUNT];
+
+/**
+ * @brief List pointing to empty asymmetric key slots
+ */
+static clist_node_t key_pair_list_empty;
+#endif /* MODULE_PSA_ASYMMETRIC */
+
+/**
+ * @brief Array containing the single key slots
+ */
+static psa_key_slot_t single_key_slots[PSA_SINGLE_KEY_COUNT];
+
+/**
+ * @brief List pointing to empty single key slots
+ */
+static clist_node_t single_key_list_empty;
+
+/**
+ * @brief Global list of used key slots
+ */
+static clist_node_t key_slot_list;
+
+/**
+ * @brief Counter for volatile key IDs.
+ */
+static psa_key_id_t key_id_count = PSA_KEY_ID_VOLATILE_MIN;
+
+/**
+ * @brief Get the correct empty slot list, depending on the key type
+ *
+ * @param attr
+ * @return clist_node_t* Pointer to the list the key is supposed to be stored in,
+ * according to its attributes
+ */
+static clist_node_t * psa_get_empty_key_slot_list(const psa_key_attributes_t *attr)
+{
+ if (!psa_key_lifetime_is_external(attr->lifetime)) {
+#if IS_USED(MODULE_PSA_ASYMMETRIC)
+ if (PSA_KEY_TYPE_IS_KEY_PAIR(attr->type)) {
+ return &key_pair_list_empty;
+ }
+#endif /* MODULE_PSA_ASYMMETRIC */
+ return &single_key_list_empty;
+ }
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ return &protected_list_empty;
+#else
+ return NULL;
+#endif /* MODULE_PSA_SECURE_ELEMENT */
+}
+
+void psa_init_key_slots(void)
+{
+ DEBUG("List Node Size: %d\n", sizeof(clist_node_t));
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ memset(protected_key_slots, 0, sizeof(protected_key_slots));
+
+#if PSA_PROTECTED_KEY_COUNT
+ for (size_t i = 0; i < PSA_PROTECTED_KEY_COUNT; i++) {
+ clist_rpush(&protected_list_empty, &protected_key_slots[i].node);
+ }
+#endif /* PSA_PROTECTED_KEY_COUNT */
+
+ DEBUG("Protected Slot Count: %d, Size: %d\n", PSA_PROTECTED_KEY_COUNT,
+ sizeof(psa_prot_key_slot_t));
+ DEBUG("Protected Slot Array Size: %d\n", sizeof(protected_key_slots));
+ DEBUG("Protected Slot Empty List Size: %d\n", clist_count(&protected_list_empty));
+#endif /* MODULE_PSA_SECURE_ELEMENT */
+
+#if IS_USED(MODULE_PSA_ASYMMETRIC)
+ memset(key_pair_slots, 0, sizeof(key_pair_slots));
+
+#if PSA_ASYMMETRIC_KEYPAIR_COUNT
+ for (size_t i = 0; i < PSA_ASYMMETRIC_KEYPAIR_COUNT; i++) {
+ clist_rpush(&key_pair_list_empty, &key_pair_slots[i].node);
+ }
+#endif /* PSA_ASYMMETRIC_KEYPAIR_COUNT */
+ DEBUG("Asymmetric Slot Count: %d, Size: %d\n", PSA_ASYMMETRIC_KEYPAIR_COUNT,
+ sizeof(psa_key_pair_slot_t));
+ DEBUG("Asymmetric Slot Array Size: %d\n", sizeof(key_pair_slots));
+ DEBUG("Asymmetric Slot Empty List Size: %d\n", clist_count(&key_pair_list_empty));
+#endif /* MODULE_PSA_ASYMMETRIC */
+
+ memset(single_key_slots, 0, sizeof(single_key_slots));
+#if PSA_SINGLE_KEY_COUNT
+ for (size_t i = 0; i < PSA_SINGLE_KEY_COUNT; i++) {
+ clist_rpush(&single_key_list_empty, &single_key_slots[i].node);
+ }
+#endif
+ DEBUG("Single Key Slot Count: %d, Size: %d\n", PSA_SINGLE_KEY_COUNT, sizeof(psa_key_slot_t));
+ DEBUG("Single Key Slot Array Size: %d\n", sizeof(single_key_slots));
+ DEBUG("Single Key Slot Empty List Size: %d\n", clist_count(&single_key_list_empty));
+}
+
+/**
+ * @brief Wipe key slot with correct key slot size
+ *
+ * @param slot Key sloit to be wiped
+ */
+static void psa_wipe_real_slot_type(psa_key_slot_t *slot)
+{
+ psa_key_attributes_t attr = slot->attr;
+
+ if (!psa_key_lifetime_is_external(attr.lifetime)) {
+ if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) {
+ memset(slot, 0, sizeof(psa_key_slot_t));
+ }
+#if IS_USED(MODULE_PSA_ASYMMETRIC)
+ else {
+
+ memset((psa_key_pair_slot_t *)slot, 0, sizeof(psa_key_pair_slot_t));
+ }
+#endif
+ }
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ else {
+ memset((psa_prot_key_slot_t *)slot, 0, sizeof(psa_prot_key_slot_t));
+ }
+#endif
+}
+
+psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot)
+{
+ /* Get list the slot is stored in */
+ clist_node_t *empty_list = psa_get_empty_key_slot_list(&slot->attr);
+
+ if (empty_list == NULL) {
+ return PSA_ERROR_DOES_NOT_EXIST;
+ }
+
+ /* Get node to remove from key slot list */
+ clist_node_t *n = clist_remove(&key_slot_list, &slot->node);
+
+ if (n == NULL) {
+ return PSA_ERROR_DOES_NOT_EXIST;
+ }
+
+ psa_key_slot_t *tmp = container_of(n, psa_key_slot_t, node);
+
+ /* Wipe slot associated with node */
+ psa_wipe_real_slot_type(tmp);
+
+ /* Append node to empty list for later reuse */
+ clist_rpush(empty_list, n);
+ return PSA_SUCCESS;
+}
+
+void psa_wipe_all_key_slots(void)
+{
+ /* Move all list items to empty lists */
+ while (!clist_is_empty(&key_slot_list)) {
+ clist_node_t *to_remove = clist_rpop(&key_slot_list);
+ psa_key_slot_t *slot = container_of(to_remove, psa_key_slot_t, node);
+ clist_node_t *empty_list = psa_get_empty_key_slot_list(&slot->attr);
+
+ psa_wipe_real_slot_type(slot);
+ clist_rpush(empty_list, to_remove);
+ }
+}
+
+/**
+ * @brief Check whether a given key ID equals the ID of the given node.
+ *
+ * This is the break condition of the @ref clist_foreach function used
+ * in @ref psa_get_and_lock_key_slot_in_memory.
+ * clist_foreach iterates over all key slots and calls this function
+ * to compare each slot's key ID to the given input key ID.
+ * If they are equal, this function returns True and breaks the foreach
+ * loop.
+ *
+ * For more information see core/lib/include/clist.h.
+ *
+ * @param n Pointer to clist node referencing a key slot
+ * @param arg Pointer to required key ID
+ * @return int
+ * 1 if input ID equals node ID
+ * 0 otherwise
+ */
+static int node_id_equals_key_id(clist_node_t *n, void *arg)
+{
+ psa_key_slot_t *slot = container_of(n, psa_key_slot_t, node);
+ psa_key_id_t id = *((psa_key_id_t *)arg);
+
+ if (slot->attr.id == id) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Find the key slot containing the key with a specified ID
+ *
+ * @param id ID of the required key
+ * @param p_slot Pointer to the slot that will contain the required key
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_INVALID_HANDLE
+ * @ref PSA_ERROR_CORRUPTION_DETECTED
+ * @ref PSA_ERROR_NOT_SUPPORTED
+ */
+static psa_status_t psa_get_and_lock_key_slot_in_memory(psa_key_id_t id, psa_key_slot_t **p_slot)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ if (psa_key_id_is_volatile(id)) {
+ clist_node_t *slot_node = clist_foreach(&key_slot_list, node_id_equals_key_id, &id);
+ if (slot_node == NULL) {
+ return PSA_ERROR_INVALID_HANDLE;
+ }
+
+ psa_key_slot_t *slot = container_of(slot_node, psa_key_slot_t, node);
+ status = psa_lock_key_slot(slot);
+ if (status == PSA_SUCCESS) {
+ *p_slot = slot;
+ }
+ return status;
+ }
+
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **p_slot)
+{
+ /* TODO validate ID */
+
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+
+ *p_slot = NULL;
+
+ status = psa_get_and_lock_key_slot_in_memory(id, p_slot);
+ if (status != PSA_ERROR_DOES_NOT_EXIST) {
+ return status;
+ }
+
+ /* TODO: get persistent key from storage and load into slot */
+
+ return status;
+}
+
+/**
+ * @brief Allocate a free slot for a new key creation
+ *
+ * @param p_slot Pointer that will contain the free key slot.
+ * @param attr Attributes of type @ref psa_key_attrubutes_t for the key to be created
+ *
+ * @return @ref PSA_SUCCESS
+ * @ref PSA_ERROR_DOES_NOT_EXIST No key slots for this type of key exist
+ * @ref PSA_ERROR_INSUFFICIENT_STORAGE
+ */
+static psa_status_t psa_allocate_key_slot_in_list(psa_key_slot_t **p_slot,
+ const psa_key_attributes_t *attr)
+{
+ clist_node_t *empty_list = psa_get_empty_key_slot_list(attr);
+
+ if (empty_list == NULL) {
+ return PSA_ERROR_DOES_NOT_EXIST;
+ }
+
+ /* Check if any empty elements of this key slot type are left */
+ if (clist_is_empty(empty_list)) {
+ DEBUG("Key Slot MGMT: No PSA Key Slot available\n");
+ return PSA_ERROR_INSUFFICIENT_STORAGE;
+ }
+
+ /* TODO: If no slots left: Look for slot in list with persistent key
+ (key will be stored in persistent memory and slot can be reused) */
+
+ /* Remove key slote node from empty list and append to actual list */
+ clist_node_t *new_slot = clist_rpop(empty_list);
+
+ clist_rpush(&key_slot_list, new_slot);
+
+ psa_key_slot_t *slot = container_of(new_slot, psa_key_slot_t, node);
+
+ *p_slot = slot;
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_allocate_empty_key_slot( psa_key_id_t *id,
+ const psa_key_attributes_t *attr,
+ psa_key_slot_t **p_slot)
+{
+ psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
+ psa_key_slot_t *new_slot = NULL;
+
+ /* Change later, when we also have persistent keys */
+ if (key_id_count == PSA_KEY_ID_VOLATILE_MAX) {
+ DEBUG("Key Slot MGMT: Maximum key ID reached\n");
+ return PSA_ERROR_INSUFFICIENT_STORAGE;
+ }
+
+ status = psa_allocate_key_slot_in_list(&new_slot, attr);
+ if (status != PSA_SUCCESS) {
+ *p_slot = NULL;
+ *id = 0;
+ return status;
+ }
+
+ if (new_slot != NULL) {
+ status = psa_lock_key_slot(new_slot);
+ if (status != PSA_SUCCESS) {
+ *p_slot = NULL;
+ *id = 0;
+ return status;
+ }
+ *id = key_id_count++;
+ *p_slot = new_slot;
+
+ return PSA_SUCCESS;
+ }
+
+ status = PSA_ERROR_INSUFFICIENT_MEMORY;
+ *p_slot = NULL;
+ *id = 0;
+ return status;
+}
+
+psa_status_t psa_lock_key_slot(psa_key_slot_t *slot)
+{
+ if (slot->lock_count >= SIZE_MAX) {
+ return PSA_ERROR_CORRUPTION_DETECTED;
+ }
+
+ slot->lock_count++;
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t psa_unlock_key_slot(psa_key_slot_t *slot)
+{
+ if (slot == NULL) {
+ return PSA_SUCCESS;
+ }
+
+ if (slot->lock_count > 0) {
+ slot->lock_count--;
+ return PSA_SUCCESS;
+ }
+
+ return PSA_ERROR_CORRUPTION_DETECTED;
+}
+
+psa_status_t psa_validate_key_location(psa_key_lifetime_t lifetime, psa_se_drv_data_t **p_drv)
+{
+ if (psa_key_lifetime_is_external(lifetime)) {
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+ psa_se_drv_data_t *driver = psa_get_se_driver_data(lifetime);
+ if (driver != NULL) {
+ if (p_drv != NULL) {
+ *p_drv = driver;
+ }
+ return PSA_SUCCESS;
+ }
+#else
+ (void)p_drv;
+#endif /* MODULE_PSA_SECURE_ELEMENT */
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+ else {
+ (void)p_drv;
+ return PSA_SUCCESS;
+ }
+}
+
+psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime)
+{
+ if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
+ return PSA_SUCCESS;
+ }
+ /* TODO: Implement persistent key storage */
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+int psa_is_valid_key_id(psa_key_id_t id, int vendor)
+{
+ if ((PSA_KEY_ID_USER_MIN <= id) &&
+ (id <= PSA_KEY_ID_USER_MAX)) {
+ return 1;
+ }
+
+ if (vendor
+ && (PSA_KEY_ID_VENDOR_MIN <= id)
+ && (id <= PSA_KEY_ID_VENDOR_MAX)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+size_t psa_get_key_data_from_key_slot(const psa_key_slot_t *slot, uint8_t **key_data,
+ size_t **key_bytes)
+{
+ psa_key_attributes_t attr = slot->attr;
+ size_t key_data_size = 0;
+
+ *key_data = NULL;
+ *key_bytes = NULL;
+
+
+ if (!psa_key_lifetime_is_external(attr.lifetime)) {
+ if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) {
+ *key_data = (uint8_t *)slot->key.data;
+ *key_bytes = (size_t *)&slot->key.data_len;
+ key_data_size = sizeof(slot->key.data);
+ }
+#if IS_USED(MODULE_PSA_ASYMMETRIC)
+ else {
+ *key_data = ((psa_key_pair_slot_t *)slot)->key.privkey_data;
+ *key_bytes = &((psa_key_pair_slot_t *)slot)->key.privkey_data_len;
+ key_data_size = sizeof(((psa_key_pair_slot_t *)slot)->key.privkey_data);
+ }
+#endif
+ }
+ return key_data_size;
+}
+
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
+psa_key_slot_number_t * psa_key_slot_get_slot_number(const psa_key_slot_t *slot)
+{
+ return &(((psa_prot_key_slot_t *)slot)->key.slot_number);
+}
+#endif
+
+void psa_get_public_key_data_from_key_slot(const psa_key_slot_t *slot, uint8_t **pubkey_data,
+ size_t **pubkey_data_len)
+{
+ psa_key_attributes_t attr = slot->attr;
+
+ /* If key type is not asymmetric, no public key exists */
+ if (!PSA_KEY_TYPE_IS_ASYMMETRIC(attr.type)) {
+ *pubkey_data = NULL;
+ *pubkey_data_len = NULL;
+ return;
+ }
+
+ if (!psa_key_lifetime_is_external(attr.lifetime)) {
+ if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) {
+ *pubkey_data = ((psa_key_slot_t *)slot)->key.data;
+ *pubkey_data_len = &((psa_key_slot_t *)slot)->key.data_len;
+ return;
+ }
+#if IS_USED(MODULE_PSA_ASYMMETRIC)
+ else {
+ *pubkey_data = ((psa_key_pair_slot_t *)slot)->key.pubkey_data;
+ *pubkey_data_len = &((psa_key_pair_slot_t *)slot)->key.pubkey_data_len;
+ return;
+ }
+#endif
+ }
+#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC)
+ *pubkey_data = ((psa_prot_key_slot_t *)slot)->key.pubkey_data;
+ *pubkey_data_len = &((psa_prot_key_slot_t *)slot)->key.pubkey_data_len;
+#endif
+}
diff --git a/sys/psa_crypto/psa_se_mgmt/Kconfig b/sys/psa_crypto/psa_se_mgmt/Kconfig
new file mode 100644
index 0000000000..80f017ad79
--- /dev/null
+++ b/sys/psa_crypto/psa_se_mgmt/Kconfig
@@ -0,0 +1,53 @@
+# 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.
+#
+
+menuconfig MODULE_PSA_SECURE_ELEMENT
+ bool "PSA Secure Elements"
+ select MODULE_PSA_KEY_SLOT_MGMT
+ select MODULE_PSA_SE_MGMT
+
+if MODULE_PSA_SECURE_ELEMENT
+
+config MODULE_PSA_SECURE_ELEMENT_MULTIPLE
+ bool "Use multiple secure elements"
+
+config PSA_MAX_SE_COUNT
+ int
+ prompt "Maximum number of secure elements" if MODULE_PSA_SECURE_ELEMENT_MULTIPLE
+ range 2 255 if MODULE_PSA_SECURE_ELEMENT_MULTIPLE
+ range 1 255
+
+menuconfig MODULE_PSA_SECURE_ELEMENT_ATECCX08A
+ bool "Microchip ATECCX08A"
+ select PACKAGE_CRYPTOAUTHLIB
+ select MODULE_PSA_SECURE_ELEMENT_CONFIG
+ depends on HAS_PERIPH_I2C
+ help
+ When using Cryptoauthlib as a backend for elliptic curve operations,
+ please also choose the ECC symbol.
+
+config MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256
+ bool "Microchip ATECCX08A Elliptic Curve P256"
+ select PSA_KEY_SIZE_256
+ select MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC
+ depends on MODULE_PSA_SECURE_ELEMENT_ATECCX08A
+
+config MODULE_PSA_SE_MGMT
+ bool
+
+config MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC
+ bool
+ help
+ Indicates that an asymmetric operation is used with secure elements.
+
+config MODULE_PSA_SECURE_ELEMENT_CONFIG
+ bool
+ help
+ Indicates that this SE driver defines a configuration structure for
+ persistent driver data.
+
+endif # MODULE_PSA_SECURE_ELEMENT
diff --git a/sys/psa_crypto/psa_se_mgmt/Makefile b/sys/psa_crypto/psa_se_mgmt/Makefile
new file mode 100644
index 0000000000..489bd7b228
--- /dev/null
+++ b/sys/psa_crypto/psa_se_mgmt/Makefile
@@ -0,0 +1,3 @@
+MODULE := psa_se_mgmt
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c b/sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c
new file mode 100644
index 0000000000..75598ebd14
--- /dev/null
+++ b/sys/psa_crypto/psa_se_mgmt/psa_crypto_se_management.c
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+/**
+ * @ingroup sys_psa_crypto psa_crypto_se_mgmt
+ * @{
+ *
+ * @brief PSA Crypto Secure Element Management implementation
+ *
+ * @author Lena Boeckmann
+ *
+ * @}
+ */
+
+#include "psa_crypto_se_management.h"
+#include "psa_crypto_se_driver.h"
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+/**
+ * @brief Array containing the registered driver instances.
+ */
+static psa_se_drv_data_t driver_table[PSA_MAX_SE_COUNT];
+
+/**
+ * @brief Global counter for registered SE devices.
+
+ */
+unsigned psa_se_count = 0;
+
+psa_status_t psa_register_secure_element(psa_key_location_t location,
+ const psa_drv_se_t *methods,
+ void *psa_se_configuration,
+ const void *drv_transient_data)
+{
+ size_t i;
+ psa_se_drv_data_t *temp;
+
+ if (psa_se_count >= PSA_MAX_SE_COUNT) {
+ DEBUG("SE Registration: Maximum number of Secure Elements reached.\n");
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
+ }
+
+ if (methods->hal_version != PSA_DRV_SE_HAL_VERSION) {
+ DEBUG("SE Registration: Driver HAL Version not supported.\n");
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ if (location == PSA_KEY_LOCATION_LOCAL_STORAGE) {
+ DEBUG("SE Registration: Invalid driver location value.\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (location > PSA_KEY_LOCATION_SE_MAX) {
+ DEBUG("SE Registration: Exhausted maximum number of Secure Element location values.\n");
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (methods->persistent_data_size > PSA_MAX_PERSISTENT_DATA_SIZE) {
+ DEBUG("SE Registration: Persistent Data is too large.\n");
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
+ }
+
+ /* Find next free slot in driver table */
+ for (i = 0; i < psa_se_count; i++) {
+ if (driver_table[i].location == location) {
+ DEBUG("SE Registration: Device with location 0x%x already exists.\n", (int)location);
+ return PSA_ERROR_ALREADY_EXISTS;
+ }
+
+ if (driver_table[i].location == 0) {
+ break;
+ }
+ }
+
+ temp = &driver_table[i];
+ temp->location = location;
+ temp->methods = methods;
+ temp->ctx.internal.transient_data = (uintptr_t)drv_transient_data;
+ temp->ctx.internal.persistent_data = psa_se_configuration;
+ temp->ctx.internal.persistent_data_size = methods->persistent_data_size;
+
+ /* TODO: Load Persistent data if persistent_data_size != 0 */
+ psa_se_count++;
+ return PSA_SUCCESS;
+}
+
+psa_se_drv_data_t *psa_get_se_driver_data(psa_key_lifetime_t lifetime)
+{
+ psa_se_drv_data_t *drv = NULL;
+ psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime);
+
+ if (location == 0) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < PSA_MAX_SE_COUNT; i++) {
+ if (driver_table[i].location == location) {
+ drv = &driver_table[i];
+ }
+ }
+
+ (void)lifetime;
+ return drv;
+}
+
+int psa_get_se_driver(psa_key_lifetime_t lifetime,
+ const psa_drv_se_t **p_methods,
+ psa_drv_se_context_t **p_drv_context)
+{
+ psa_se_drv_data_t *driver = psa_get_se_driver_data(lifetime);
+
+ if (p_methods != NULL) {
+ *p_methods = (driver ? driver->methods : NULL);
+ }
+ if (p_drv_context != NULL) {
+ *p_drv_context = (driver ? &driver->ctx.context : NULL);
+ }
+ return (driver != NULL);
+}
+
+const psa_drv_se_t *psa_get_se_driver_methods(const psa_se_drv_data_t *driver)
+{
+ return driver->methods;
+}
+
+psa_drv_se_context_t *psa_get_se_drv_context(psa_se_drv_data_t *driver)
+{
+ return &driver->ctx.context;
+}
+
+psa_status_t psa_find_free_se_slot(const psa_key_attributes_t *attributes,
+ psa_key_creation_method_t method,
+ psa_se_drv_data_t *driver,
+ psa_key_slot_number_t *slot_number)
+{
+ psa_status_t status;
+ psa_key_location_t key_location =
+ PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));
+
+ if (driver->location != key_location) {
+ return PSA_ERROR_CORRUPTION_DETECTED;
+ }
+
+ if (driver->methods->key_management == NULL ||
+ driver->methods->key_management->p_allocate == NULL) {
+ return PSA_ERROR_NOT_SUPPORTED;
+ }
+
+ status = driver->methods->key_management->p_allocate(&driver->ctx.context,
+ driver->ctx.internal.persistent_data,
+ attributes, method, slot_number);
+
+ return status;
+}
+
+psa_status_t psa_destroy_se_key(psa_se_drv_data_t *driver,
+ psa_key_slot_number_t slot_number)
+{
+ if (driver->methods->key_management == NULL ||
+ driver->methods->key_management->p_destroy == NULL) {
+ return PSA_ERROR_NOT_PERMITTED;
+ }
+ return driver->methods->key_management->p_destroy(&driver->ctx.context,
+ driver->ctx.internal.persistent_data,
+ slot_number);
+
+ /* TODO: Store Persistent Data */
+}
+
+psa_status_t psa_load_se_persistent_data(const psa_se_drv_data_t *driver)
+{
+ (void)driver;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_save_se_persistent_data(const psa_se_drv_data_t *driver)
+{
+ (void)driver;
+ return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location)
+{
+ (void)location;
+ return PSA_ERROR_NOT_SUPPORTED;
+}