/***************************************************************************//**
 * @file
 * @brief Silicon Labs Secure Engine Manager API.
 *******************************************************************************
 * # License
 * <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
 *******************************************************************************
 *
 * SPDX-License-Identifier: Zlib
 *
 * The licensor of this software is Silicon Laboratories Inc.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 *
 ******************************************************************************/
#ifndef SL_SE_MANAGER_CIPHER_H
#define SL_SE_MANAGER_CIPHER_H

#include "sli_se_manager_features.h"

#if defined(SLI_MAILBOX_COMMAND_SUPPORTED)

/// @addtogroup sl_se_manager
/// @{

/***************************************************************************//**
 * @addtogroup sl_se_manager_cipher Cipher
 *
 * @brief
 *   Symmetric encryption, AEAD and MAC.
 *
 * @details
 *   API for performing symmetric encryption, Authenticated Encryption and
 *   Additional Data (AEAD) operations, and computing Message Authentication
 *   Codes (MACs) using the Secure Engine.
 *
 * @{
 ******************************************************************************/

#include "sl_se_manager_key_handling.h"
#include "sl_se_manager_types.h"
#include "sli_se_manager_mailbox.h"
#include "sl_status.h"
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

// -----------------------------------------------------------------------------
// Prototypes

/***************************************************************************//**
 * @brief
 *   AES-ECB block encryption/decryption.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] mode
 *   Crypto operation type (encryption or decryption).
 *
 * @param[in] length
 *   Length of the input data.
 *
 * @param[in] input
 *   Buffer holding the input data.
 *
 * @param[out] output
 *   Buffer holding the output data.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_aes_crypt_ecb(sl_se_command_context_t *cmd_ctx,
                                const sl_se_key_descriptor_t *key,
                                sl_se_cipher_operation_t mode,
                                size_t length,
                                const unsigned char *input,
                                unsigned char *output);

/***************************************************************************//**
 * @brief
 *   AES-CBC buffer encryption/decryption.
 *
 * @note
 *   Length should be a multiple of the block size (16 bytes).
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] mode
 *   Crypto operation type (encryption or decryption).
 *
 * @param[in] length
 *   Length of the input data.
 *
 * @param[in,out] iv
 *   Initialization vector (updated after use).
 *
 * @param[in] input
 *   Buffer holding the input data.
 *
 * @param[out] output
 *   Buffer holding the output data.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_aes_crypt_cbc(sl_se_command_context_t *cmd_ctx,
                                const sl_se_key_descriptor_t *key,
                                sl_se_cipher_operation_t mode,
                                size_t length,
                                unsigned char iv[16],
                                const unsigned char *input,
                                unsigned char *output);

/***************************************************************************//**
 * @brief
 *   AES-CFB128 buffer encryption/decryption.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] mode
 *   Crypto operation type (encryption or decryption).
 *
 * @param[in] length
 *   Length of the input data.
 *
 * @param[in,out] iv_off
 *   Offset in IV (updated after use).
 *
 * @param[in,out] iv
 *   Initialization vector (updated after use).
 *
 * @param[in] input
 *   Buffer holding the input data.
 *
 * @param[out] output
 *   Buffer holding the output data.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_aes_crypt_cfb128(sl_se_command_context_t *cmd_ctx,
                                   const sl_se_key_descriptor_t *key,
                                   sl_se_cipher_operation_t mode,
                                   size_t length,
                                   uint32_t *iv_off,
                                   unsigned char iv[16],
                                   const unsigned char *input,
                                   unsigned char *output);

/***************************************************************************//**
 * @brief
 *   AES-CFB8 buffer encryption/decryption.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] mode
 *   Crypto operation type (encryption or decryption).
 *
 * @param[in] length
 *   Length of the input data.
 *
 * @param[in,out] iv
 *   Initialization vector (updated after use).
 *
 * @param[in] input
 *   Buffer holding the input data.
 *
 * @param[out] output
 *   Buffer holding the output data.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_aes_crypt_cfb8(sl_se_command_context_t *cmd_ctx,
                                 const sl_se_key_descriptor_t *key,
                                 sl_se_cipher_operation_t mode,
                                 size_t length,
                                 unsigned char iv[16],
                                 const unsigned char *input,
                                 unsigned char *output);

/***************************************************************************//**
 * @brief
 *   AES-CTR buffer encryption/decryption.
 *
 * @warning
 *  Avoid passing in the same buffer for nonce_counter and
 *  stream_block as the incrementation operation of
 *  nonce_counter can lead to corruption of the ciphertext
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   Length of the input data.
 *
 * @param[in] nc_off
 *   The offset in the current stream_block (for resuming
 *   within current cipher stream). The offset pointer to
 *   should be 0 at the start of a stream.
 *
 * @param[in,out] nonce_counter
 *   The 128-bit nonce and counter.
 *
 * @param[in,out] stream_block
 *   The saved stream-block for resuming (updated after use).
 *
 * @param[in] input
 *   Buffer holding the input data.
 *
 * @param[out] output
 *   Buffer holding the output data.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_aes_crypt_ctr(sl_se_command_context_t *cmd_ctx,
                                const sl_se_key_descriptor_t *key,
                                size_t length,
                                uint32_t *nc_off,
                                unsigned char nonce_counter[16],
                                unsigned char stream_block[SLI_SE_AES_CTR_NUM_BLOCKS_BUFFERED * SL_SE_AES_BLOCK_SIZE],
                                const unsigned char *input,
                                unsigned char *output);

/***************************************************************************//**
 * @brief
 *   AES-CCM buffer encryption.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   The length of the input data in Bytes.
 *
 * @param[in] iv
 *   Initialization vector (nonce).
 *
 * @param[in] iv_len
 *   The length of the IV in Bytes: 7, 8, 9, 10, 11, 12, or 13.
 *
 * @param[in] add
 *   The additional data field.
 *
 * @param[in] add_len
 *   The length of additional data in Bytes.
 *
 * @param[in] input
 *   The buffer holding the input data.
 *
 * @param[out] output
 *   The buffer holding the output data. Must be at least @p length Bytes wide.
 *
 * @param[in,out] tag
 *   The buffer holding the tag.
 *
 * @param[in] tag_len
 *   The length of the tag to generate in Bytes: 4, 6, 8, 10, 12, 14 or 16.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_ccm_encrypt_and_tag(sl_se_command_context_t *cmd_ctx,
                                      const sl_se_key_descriptor_t *key,
                                      size_t length,
                                      const unsigned char *iv, size_t iv_len,
                                      const unsigned char *add, size_t add_len,
                                      const unsigned char *input,
                                      unsigned char *output,
                                      unsigned char *tag, size_t tag_len);

/***************************************************************************//**
 * @brief
 *   AES-CCM buffer decryption.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   The length of the input data in Bytes.
 *
 * @param[in] iv
 *   Initialization vector.
 *
 * @param[in] iv_len
 *   The length of the IV in Bytes: 7, 8, 9, 10, 11, 12, or 13.
 *
 * @param[in] add
 *   The additional data field.
 *
 * @param[in] add_len
 *   The length of additional data in Bytes.
 *
 * @param[in] input
 *   The buffer holding the input data.
 *
 * @param[out] output
 *   The buffer holding the output data. Must be at least @p length Bytes wide.
 *
 * @param[in] tag
 *   The buffer holding the tag.
 *
 * @param[in] tag_len
 *   The length of the tag in Bytes. Must be 4, 6, 8, 10, 12, 14 or 16.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_ccm_auth_decrypt(sl_se_command_context_t *cmd_ctx,
                                   const sl_se_key_descriptor_t *key,
                                   size_t length,
                                   const unsigned char *iv, size_t iv_len,
                                   const unsigned char *add, size_t add_len,
                                   const unsigned char *input,
                                   unsigned char *output,
                                   const unsigned char *tag, size_t tag_len);

/***************************************************************************//**
 * @brief
 *   Prepare a CCM streaming command context object.
 *
 * @details
 *   Prepare a CCM streaming command context object to be used in subsequent
 *   CCM streaming function calls.
 *
 * @param[in] ccm_ctx
 *   Pointer to a CCM streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to a SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] mode
 *   The operation to perform: SL_SE_ENCRYPT or SL_SE_DECRYPT.
 *
 * @param[in] total_message_length
 *   The total length of the text to encrypt/decrypt
 *
 * @param[in] iv
 *   The initialization vector (commonly referred to as nonce for CCM).
 *
 * @param[in] iv_len
 *   The length of the IV.
 *
 * @param[in] add
 *   The buffer holding the additional data.
 *
 * @param[in] add_len
 *   The length of the additional data.
 *
 * @param[in] tag_len
 *   Encryption: The length of the tag to generate. Must be 0, 4, 6, 8, 10, 12, 14 or 16.
 *   Decryption: The length of the tag to authenticate. Must be 0, 4, 6, 8, 10, 12, 14 or 16.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_ccm_multipart_starts(sl_se_ccm_multipart_context_t *ccm_ctx,
                                       sl_se_command_context_t *cmd_ctx,
                                       const sl_se_key_descriptor_t *key,
                                       sl_se_cipher_operation_t mode,
                                       uint32_t total_message_length,
                                       const uint8_t *iv,
                                       size_t iv_len,
                                       const uint8_t *add,
                                       size_t add_len,
                                       size_t tag_len);

/***************************************************************************//**
 * @brief
 *   This function feeds an input buffer into an ongoing CCM computation.
 *
 *   It is called between sl_se_ccm_multipart_starts() and sl_se_ccm_multipart_finish().
 *   Can be called repeatedly.
 *
 * @param[in] ccm_ctx
 *   Pointer to a CCM streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to a SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   The length of the input data. This must be a multiple of 16 except in
 *   the last call before sl_se_ccm_multipart_finish().
 *
 * @param[in] input
 *   Buffer holding the input data, must be at least @p length bytes wide.
 *
 * @param[out] output
 *   Buffer for holding the output data, must be at least @p length bytes wide.
 *
 * @param[out] output_length
 *   Length of data that has been encrypted/decrypted.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/

sl_status_t sl_se_ccm_multipart_update(sl_se_ccm_multipart_context_t *ccm_ctx,
                                       sl_se_command_context_t *cmd_ctx,
                                       const sl_se_key_descriptor_t *key,
                                       size_t length,
                                       const uint8_t *input,
                                       uint8_t *output,
                                       size_t *output_length);

/***************************************************************************//**
 * @brief
 *   Finish a CCM streaming operation and return the resulting CCM tag.
 *
 *   It is called after sl_se_ccm_multipart_update().
 *
 * @param[in] ccm_ctx
 *   Pointer to a CCM streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in, out] tag
 *   Encryption: The buffer for holding the tag.
 *   Decryption: The tag to authenticate.
 *
 * @param[in]  tag_size
 *   The size of the tag buffer. Must be equal or greater to the length of the expected tag.
 *
 * @param[out] output
 *   Buffer for holding the output data.
 *
 * @param[in] output_size
 *   Output buffer size. Must be equal or greater to the stored data from
 *   sl_se_ccm_multipart_update (maximum 16 bytes).
 *
 * @param[out] output_length
 *   Length of data that has been encrypted/decrypted.
 *
 * @return
 *   Returns SL_SE_INVALID_SIGNATURE if authentication step fails.
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_ccm_multipart_finish(sl_se_ccm_multipart_context_t *ccm_ctx,
                                       sl_se_command_context_t *cmd_ctx,
                                       const sl_se_key_descriptor_t *key,
                                       uint8_t *tag,
                                       uint8_t  tag_size,
                                       uint8_t *output,
                                       uint8_t output_size,
                                       uint8_t *output_length);

/***************************************************************************//**
 * @brief
 *   This function performs GCM encryption or decryption of a buffer.
 *
 * @note
 *   For encryption, the output buffer can be the same as the input buffer.
 *   For decryption, the output buffer cannot be the same as input buffer.
 *   If the buffers overlap, the output buffer must trail at least 8 bytes
 *   behind the input buffer.
 *
 * @warning
 *   When this function performs a decryption, it outputs the authentication
 *   tag and does not verify that the data is authentic. You should use this
 *   function to perform encryption only. For decryption, use
 *   sl_se_gcm_auth_decrypt() instead.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] mode
 *   Crypto operation type (encryption or decryption).
 *     - SL_SE_ENCRYPT: The ciphertext is written to @p output and the
 *                      authentication tag is written to @p tag.
 *     - SL_SE_DECRYPT: The plaintext is written to @p output and the
 *                      authentication tag is written to @p tag.
 *                      Note that this mode is not recommended, because it does
 *                      not verify the authenticity of the data. For this
 *                      reason, you should use sl_se_gcm_auth_decrypt() instead.
 *
 * @param[in] length
 *   The length of the input data, which is equal to the length of the output
 *   data.
 *
 * @param[in] iv
 *   The initialization vector.
 *
 * @param[in] iv_len
 *   The length of the iv. Must be @b 12 bytes.
 *
 * @param[in] add
 *   The buffer holding the additional data.
 *
 * @param[in] add_len
 *   The length of the additional data in bytes.
 *
 * @param[in] input
 *   The buffer holding the input data. Its size is @b length bytes.
 *
 * @param[out] output
 *   The buffer for holding the output data. It must have room for @b length
 *   bytes.
 *
 * @param[in] tag_len
 *   The length of the tag to generate (in bytes).
 *
 * @param[out] tag
 *   The buffer for holding the tag.
 *
 * @return
 *   SL_STATUS_OK when the command was executed successfully, otherwise an
 *   appropriate error code (@ref sl_status.h).
 ******************************************************************************/
sl_status_t sl_se_gcm_crypt_and_tag(sl_se_command_context_t *cmd_ctx,
                                    const sl_se_key_descriptor_t *key,
                                    sl_se_cipher_operation_t mode,
                                    size_t length,
                                    const unsigned char *iv,
                                    size_t iv_len,
                                    const unsigned char *add,
                                    size_t add_len,
                                    const unsigned char *input,
                                    unsigned char *output,
                                    size_t tag_len,
                                    unsigned char *tag);

/***************************************************************************//**
 * @brief
 *   This function performs a GCM authenticated decryption of a buffer.
 *
 * @note
 *   The output buffer cannot be the same as input buffer. If the buffers
 *   overlap, the output buffer must trail at least 8 bytes behind the input
 *   buffer.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   The length of the ciphertext to decrypt, which is also the length of the
 *   decrypted plaintext.
 *
 * @param[in] iv
 *   The initialization vector.
 *
 * @param[in] iv_len
 *   The length of the iv. Must be @b 12 bytes.
 *
 * @param[in] add
 *   The buffer holding the additional data.
 *
 * @param[in] add_len
 *   The length of the additional data in bytes.
 *
 * @param[in] tag
 *   The buffer holding the tag to verify.
 *
 * @param[in] tag_len
 *   The length of the tag to verify (in bytes).
 *
 * @param[in] input
 *   The buffer holding the ciphertext. Its size is @b length bytes.
 *
 * @param[out] output
 *   The buffer for holding the decrypted plaintext. It must have room for
 *   @b length bytes.
 *
 * @return
 *   SL_STATUS_OK when the command was executed successfully, otherwise an
 *   appropriate error code (@ref sl_status.h).
 ******************************************************************************/
sl_status_t sl_se_gcm_auth_decrypt(sl_se_command_context_t *cmd_ctx,
                                   const sl_se_key_descriptor_t *key,
                                   size_t length,
                                   const unsigned char *iv,
                                   size_t iv_len,
                                   const unsigned char *add,
                                   size_t add_len,
                                   const unsigned char *input,
                                   unsigned char *output,
                                   size_t tag_len,
                                   const unsigned char *tag);

/***************************************************************************//**
 * @brief
 *   This function calculates the full generic CMAC on the input buffer with
 *   the provided key.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] input
 *   Buffer holding the input data, must be at least @p input_len bytes wide.
 *
 * @param[in] input_len
 *   The length of the input data in bytes.
 *
 * @param[out] output
 *   Buffer holding the 16-byte output data, must be at least 16 bytes wide.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_cmac(sl_se_command_context_t *cmd_ctx,
                       const sl_se_key_descriptor_t *key,
                       const unsigned char *input,
                       size_t input_len,
                       unsigned char *output);

/***************************************************************************//**
 * @brief
 *   Prepare a CMAC streaming command context object.
 *
 * @details
 *   Prepare a CMAC streaming command context object to be used in subsequent
 *   CMAC streaming function calls.
 *
 * @param[in] cmac_ctx
 *   Pointer to a CMAC streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_cmac_multipart_starts(sl_se_cmac_multipart_context_t *cmac_ctx,
                                        sl_se_command_context_t *cmd_ctx,
                                        const sl_se_key_descriptor_t *key);

/***************************************************************************//**
 * @brief
 *   This function feeds an input buffer into an ongoing CMAC computation.
 *
 * @details
 *   It is called between sl_se_cmac_multipart_starts() and sl_se_cmac_multipart_finish().
 *   Can be called repeatedly.
 *
 * @param[in,out] cmac_ctx
 *   Pointer to a CMAC streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] input
 *   Buffer holding the input data, must be at least @p input_len bytes wide.
 *
 * @param[in] input_len
 *   The length of the input data in bytes.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_cmac_multipart_update(sl_se_cmac_multipart_context_t *cmac_ctx,
                                        sl_se_command_context_t *cmd_ctx,
                                        const sl_se_key_descriptor_t *key,
                                        const uint8_t *input,
                                        size_t input_len);

/***************************************************************************//**
 * @brief
 *   Finish a CMAC streaming operation and return the resulting CMAC tag.
 *
 * @details
 *   It is called after sl_se_cmac_multipart_update().
 *
 * @param[in,out] cmac_ctx
 *   Pointer to a CMAC streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[out] output
 *   Buffer holding the 16-byte CMAC tag, must be at least 16 bytes wide.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_cmac_multipart_finish(sl_se_cmac_multipart_context_t *cmac_ctx,
                                        sl_se_command_context_t *cmd_ctx,
                                        const sl_se_key_descriptor_t *key,
                                        uint8_t *output);

/***************************************************************************//**
 * @brief
 *   Prepare a GCM streaming command context object.
 *
 * @details
 *   Prepare a GCM streaming command context object to be used in subsequent
 *   GCM streaming function calls.
 *
 * @param[in, out] gcm_ctx
 *   Pointer to a GCM streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to @c sl_se_key_descriptor_t structure specifying the key to use in
 *   the GCM computation.
 *
 * @param[in] mode
 *   The operation to perform: SL_SE_ENCRYPT or SL_SE_DECRYPT.
 *
 * @param[in] iv
 *   The initialization vector.
 *
 * @param[in] iv_len
 *   The length of the IV.
 *
 * @param[in] add
 *   The buffer holding the additional data, or NULL if @p add_len is 0.
 *
 * @param[in] add_len
 *   The length of the additional data. If 0, @p  add is NULL.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_gcm_multipart_starts(sl_se_gcm_multipart_context_t *gcm_ctx,
                                       sl_se_command_context_t *cmd_ctx,
                                       const sl_se_key_descriptor_t *key,
                                       sl_se_cipher_operation_t mode,
                                       const uint8_t *iv,
                                       size_t iv_len,
                                       const uint8_t *add,
                                       size_t add_len);

/***************************************************************************//**
 * @brief
 *   This function feeds an input buffer into an ongoing GCM computation.
 *
 *   It is called between sl_se_gcm_multipart_starts() and sl_se_gcm_multiapart_finish().
 *   Can be called repeatedly.
 *
 * @param[in, out] gcm_ctx
 *   Pointer to a GCM streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to @c sl_se_key_descriptor_t structure specifying the key to used in
 *   the GCM computation.
 *
 * @param[in] length
 *   The length of the input data.
 *
 * @param[in] input
 *   Buffer holding the input data, must be at least @p length bytes wide.
 *
 * @param[out] output
 *   Buffer for holding the output data, must be at least @p length bytes wide.
 *
 * @param[out] output_length
 *   Length of data that has been encrypted/decrypted.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_gcm_multipart_update(sl_se_gcm_multipart_context_t *gcm_ctx,
                                       sl_se_command_context_t *cmd_ctx,
                                       const sl_se_key_descriptor_t *key,
                                       size_t length,
                                       const uint8_t *input,
                                       uint8_t *output,
                                       size_t *output_length);

/***************************************************************************//**
 * @brief
 *   Finish a GCM streaming operation and return the resulting GCM tag.
 *
 *   It is called after sl_se_gcm_multipart_update().
 *
 * @param[in, out] gcm_ctx
 *   Pointer to a GCM streaming context object.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to @c sl_se_key_descriptor_t structure specifying the key to use in
 *   the GCM computation.
 *
 * @param[in, out] tag
 *   Encryption: The buffer for holding the tag.
 *   Decryption: The tag to authenticate.
 *
 * @param[in]  tag_length
 *   Encryption: Length of the output tag.
 *   Decryption: Length of tag to verify
 *
 * @param[out] output
 *   Buffer for holding the output data.
 *
 * @param[in] output_size
 *   Output buffer size. Must be equal or greater to the stored data from
 *   sl_se_gcm_multipart_update (stored data is maximum 16 bytes).
 *
 * @param[out] output_length
 *   Length of data that has been encrypted/decrypted.
 *
 * @return
 *   Returns SL_SE_INVALID_SIGNATURE if authentication step fails.
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_gcm_multipart_finish(sl_se_gcm_multipart_context_t *gcm_ctx,
                                       sl_se_command_context_t *cmd_ctx,
                                       const sl_se_key_descriptor_t *key,
                                       uint8_t *tag,
                                       uint8_t tag_length,
                                       uint8_t *output,
                                       uint8_t output_size,
                                       uint8_t *output_length);

/***************************************************************************//**
 * @brief
 *   Compute a HMAC on a full message.
 *
 * @details
 *   This function computes a Keyed-Hashed Message Authentication Code (HMAC)
 *   for the given input message. HMAC can be used with any iterative
 *   cryptographic hash function, e.g., SHA-1 in combination with a
 *   secret shared key.  The cryptographic strength of HMAC depends on the
 *   properties of the underlying hash function. For instance, if the algorithm
 *   is chosen to be SHA-256, it will generate a 32 bytes HMAC.
 *   This function supports SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512.
 *   The key can be of any length. If the key is shorter than the block size
 *   of the hash function the SE will append zeros to the key so the key size
 *   matches the block size of the hash function. If the key is longer than the
 *   block size of the hash function the key will be hashed to
 *   produce a key digest, then append zeros so the resulting 'hashed' key size
 *   matches the block size of the hash function. In any case the minimal
 *   recommended key length is the digest size of the hash function.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure specifying the key to use in
 *   the HMAC computation.
 *
 * @param[in] hash_type
 *   Which hashing algorithm to use.
 *
 * @param[in] message
 *   Pointer to the message buffer to compute the hash/digest from.
 *
 * @param[in] message_len
 *   Number of bytes in message.
 *
 * @param[out] output
 *   Pointer to memory buffer to store the final HMAC output.
 *
 * @param[in]  output_len
 *   The length of the HMAC output memory buffer, must be at least the size
 *   of the corresponding hash type.
 *
 * @return Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_hmac(sl_se_command_context_t *cmd_ctx,
                       const sl_se_key_descriptor_t *key,
                       sl_se_hash_type_t hash_type,
                       const uint8_t *message,
                       size_t message_len,
                       uint8_t *output,
                       size_t output_len);

#if (_SILICON_LABS_SECURITY_FEATURE == _SILICON_LABS_SECURITY_FEATURE_VAULT)
/***************************************************************************//**
 * @brief
 *   ChaCha20 buffer encryption/decryption, as defined by RFC8439 section 2.4.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] mode
 *   Crypto operation type (encryption or decryption).
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   Length of the input data.
 *
 * @param[in] initial_counter
 *   The initial counter value as defined in RFC8439 section 2.4.
 *
 * @param[in] nonce
 *   The nonce, also called initialisation vector, as defined in RFC8439 section
 *   2.4.
 *
 * @param[in] input
 *   Buffer holding the input data.
 *
 * @param[out] output
 *   Buffer holding the output data.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_chacha20_crypt(sl_se_command_context_t *cmd_ctx,
                                 sl_se_cipher_operation_t mode,
                                 const sl_se_key_descriptor_t *key,
                                 size_t length,
                                 const unsigned char initial_counter[4],
                                 const unsigned char nonce[12],
                                 const unsigned char *input,
                                 unsigned char *output);

/***************************************************************************//**
 * @brief
 *   ChaCha20-Poly1305 authenticated encryption with additional data, as defined
 *   by RFC8439 section 2.8.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   The length of the input data in bytes.
 *
 * @param[in] nonce
 *   The nonce, also called initialisation vector, as defined in RFC8439 section
 *   2.8.
 *
 * @param[in] add
 *   The buffer holding additional authenticated data. Can be NULL if @p add_len
 *   equals 0.
 *
 * @param[in] add_len
 *   The length of the additional authenticated data in bytes.
 *
 * @param[in] input
 *   The buffer holding the plaintext input.
 *
 * @param[out] output
 *   The buffer holding the ciphertext output. Can be NULL, in which case the
 *   generated ciphertext will be discarded. Must be at least @p length bytes
 *   wide.
 *
 * @param[out] tag
 *   The buffer holding the tag. This function will produce a 128-bit tag, so
 *   this buffer must be at least 16 bytes wide. Can be NULL, in which case the
 *   generated tag will be discarded.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_chacha20_poly1305_encrypt_and_tag(sl_se_command_context_t *cmd_ctx,
                                                    const sl_se_key_descriptor_t *key,
                                                    size_t length,
                                                    const unsigned char nonce[12],
                                                    const unsigned char *add, size_t add_len,
                                                    const unsigned char *input,
                                                    unsigned char *output,
                                                    unsigned char *tag);

/***************************************************************************//**
 * @brief
 *   ChaCha20-Poly1305 authenticated decryption with additional data, as defined
 *   by RFC8439 section 2.8.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure.
 *
 * @param[in] length
 *   The length of the input data in Bytes.
 *
 * @param[in] nonce
 *   The nonce, also called initialisation vector, as defined in RFC8439 section
 *   2.8.
 *
 * @param[in] add
 *   The buffer holding additional authenticated data. Can be NULL if @p add_len
 *   equals 0.
 *
 * @param[in] add_len
 *   The length of the additional authenticated data in bytes.
 *
 * @param[in] input
 *   The buffer holding the ciphertext to decrypt. Can be NULL if @p length
 *   equals 0.
 *
 * @param[out] output
 *   The buffer holding the plaintext output. Can be NULL, in which case the
 *   decrypted plaintext will be discarded, or when @p length equals 0. Must be
 *   at least @p length bytes wide.
 *
 * @param[in] tag
 *   The buffer holding the tag to verify.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_chacha20_poly1305_auth_decrypt(sl_se_command_context_t *cmd_ctx,
                                                 const sl_se_key_descriptor_t *key,
                                                 size_t length,
                                                 const unsigned char nonce[12],
                                                 const unsigned char *add, size_t add_len,
                                                 const unsigned char *input,
                                                 unsigned char *output,
                                                 const unsigned char tag[16]);

/***************************************************************************//**
 * @brief
 *   Generate a Poly1305 MAC (message authentication code) for a given message
 *   using an ephemeral key derived using ChaCha20.
 *
 * @note
 *   This function first derives a Poly1305 key based on a ChaCha20 key and
 *   nonce, which are input to this function. The key derivation adheres to
 *   RFC8439 section 2.6. The derived key is then used to calculate a MAC of the
 *   input data, according to RFC8439 section 2.5.
 *
 * @param[in] cmd_ctx
 *   Pointer to an SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure containing a ChaCha20 key.
 *
 * @param[in] length
 *   The length of the input data in Bytes.
 *
 * @param[in] nonce
 *   The nonce, also called initialisation vector, as defined in RFC8439 section
 *   2.6.
 *
 * @param[in] input
 *   The buffer holding the input data.
 *
 * @param[out] tag
 *   The buffer holding the tag. This function will produce a 128-bit tag, so
 *   this buffer must be at least 16 bytes wide.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_poly1305_genkey_tag(sl_se_command_context_t *cmd_ctx,
                                      const sl_se_key_descriptor_t *key,
                                      size_t length,
                                      const unsigned char nonce[12],
                                      const unsigned char *input,
                                      unsigned char *tag);

#endif // (_SILICON_LABS_SECURITY_FEATURE == _SILICON_LABS_SECURITY_FEATURE_VAULT)

#if defined(_SILICON_LABS_32B_SERIES_3)

/***************************************************************************//**
 * @brief
 *   Prepare a HMAC streaming command context object to be used in subsequent
 *   HMAC streaming function calls.
 *
 * @param[in] cmd_ctx
 *   Pointer to a SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure specifying the key to use in
 *   the HMAC computation.
 *
 * @param[in] hash_type
 *   Which hashing algorithm to use.
 *
 * @param[in] message
 *   Pointer to the message buffer to compute the hash/digest from.
 *
 * @param[in] message_len
 *   Number of bytes in message.
 *
 * @param[out] state_out
 *   Pointer to memory buffer to store the final HMAC output.
 *
 * @param[in]  state_out_len
 *   The length of the HMAC output memory buffer, must be at least the size
 *   of the corresponding hash type + 8 bytes.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_hmac_multipart_starts(sl_se_command_context_t *cmd_ctx,
                                        const sl_se_key_descriptor_t *key,
                                        sl_se_hash_type_t hash_type,
                                        const uint8_t *message,
                                        size_t message_len,
                                        uint8_t *state_out,
                                        size_t state_out_len);

/***************************************************************************//**
 * @brief
 *   This function feeds an input buffer into an ongoing HMAC computation.
 *
 * @param[in] cmd_ctx
 *   Pointer to a SE command context object.
 *
 * @param[in] hash_type
 *   Which hashing algorithm to use.
 *
 * @param[in] message
 *   Pointer to the message buffer to compute the hash/digest from.
 *
 * @param[in] message_len
 *   Number of bytes in message.
 *
 * @param[in,out] state_in_out
 *   Pointer to memory buffer to store the HMAC state.
 *
 * @param[in]  state_in_out_len
 *   The length of the HMAC state buffer, must be at least the size
 *   of the corresponding hash type + 8 bytes.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_hmac_multipart_update(sl_se_command_context_t *cmd_ctx,
                                        sl_se_hash_type_t hash_type,
                                        const uint8_t *message,
                                        size_t message_len,
                                        uint8_t *state_in_out,
                                        size_t state_in_out_len);

/***************************************************************************//**
 * @brief
 *   Finish a HMAC streaming operation and return the resulting HMAC.
 *
 * @param[in] cmd_ctx
 *   Pointer to a SE command context object.
 *
 * @param[in] key
 *   Pointer to sl_se_key_descriptor_t structure specifying the key to use in
 *   the HMAC computation.
 *
 * @param[in] hash_type
 *   Which hashing algorithm to use.
 *
 * @param[in] message
 *   Pointer to the message buffer to compute the hash/digest from.
 *
 * @param[in] message_len
 *   Number of bytes in message.
 *
 * @param[in] state_in
 *   Pointer to memory buffer containing the HMAC state.
 *
 * @param[in] state_in_len
 *   The length of the HMAC state buffer, must be at least the size
 *   of the corresponding hash type + 8 bytes.
 *
 * @param[out] output
 *   Pointer to memory buffer to store the final HMAC output.
 *
 * @param[in] output_len
 *   The length of the HMAC output memory buffer, must be at least the size
 *   of the corresponding hash type.
 *
 * @return
 *   Status code, @ref sl_status.h.
 ******************************************************************************/
sl_status_t sl_se_hmac_multipart_finish(sl_se_command_context_t *cmd_ctx,
                                        const sl_se_key_descriptor_t *key,
                                        sl_se_hash_type_t hash_type,
                                        const uint8_t *message,
                                        size_t message_len,
                                        uint8_t *state_in,
                                        size_t state_in_len,
                                        uint8_t *output,
                                        size_t output_len);

#endif // defined(_SILICON_LABS_32B_SERIES_3)

#ifdef __cplusplus
}
#endif

/// @} (end addtogroup sl_se_manager_cipher)
/// @} (end addtogroup sl_se_manager)

#endif // defined(SLI_MAILBOX_COMMAND_SUPPORTED)

#endif // SL_SE_MANAGER_CIPHER_H
