/* SPDX-License-Identifier: BSD-2-Clause */
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 ******************************************************************************/
#ifndef ESYS_CRYPTO_H
#define ESYS_CRYPTO_H

#ifdef HAVE_CONFIG_H
#include "config.h" // for OSSL
#endif

#include <stddef.h> // for size_t, NULL
#include <stdint.h> // for uint8_t, uint32_t

#include "tss2_common.h"     // for TSS2_RC, BYTE, BOOL, UINT32
#include "tss2_esys.h"       // for ESYS_CRYPTO_CALLBACKS, ESYS_CRYPTO_CONT...
#include "tss2_tpm2_types.h" // for TPM2_ALG_ID, TPM2B_NONCE, TPM2B_ECC_PAR...
#include "util/tpm2b.h"      // for TPM2B
#if defined(OSSL)
#include "esys_crypto_ossl.h"
#elif defined(MBED)
#include "esys_crypto_mbed.h"
#else
#define iesys_crypto_aes_decrypt_internal    NULL;
#define iesys_crypto_aes_encrypt_internal    NULL;
#define iesys_crypto_sm4_decrypt_internal    NULL;
#define iesys_crypto_sm4_encrypt_internal    NULL;
#define iesys_crypto_get_ecdh_point_internal NULL;
#define iesys_crypto_hash_abort_internal     NULL;
#define iesys_crypto_hash_finish_internal    NULL;
#define iesys_crypto_hash_start_internal     NULL;
#define iesys_crypto_hash_update_internal    NULL;
#define iesys_crypto_hmac_abort_internal     NULL;
#define iesys_crypto_hmac_finish_internal    NULL;
#define iesys_crypto_hmac_start_internal     NULL;
#define iesys_crypto_hmac_update_internal    NULL;
#define iesys_crypto_init_internal           NULL;
#define iesys_crypto_get_random2b_internal   NULL;
#define iesys_crypto_rsa_pk_encrypt_internal NULL;
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define AES_BLOCK_SIZE_IN_BYTES 16
#define SM4_BLOCK_SIZE_IN_BYTES 16

TSS2_RC iesys_crypto_hash_get_digest_size(TPM2_ALG_ID hashAlg, size_t *size);

TSS2_RC iesys_crypto_pHash(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                           TPM2_ALG_ID            alg,
                           const uint8_t          rcBuffer[4],
                           const uint8_t          ccBuffer[4],
                           const TPM2B_NAME      *name1,
                           const TPM2B_NAME      *name2,
                           const TPM2B_NAME      *name3,
                           const uint8_t         *pBuffer,
                           size_t                 pBuffer_size,
                           uint8_t               *pHash,
                           size_t                *pHash_size);

#define iesys_crypto_cpHash(ectx, alg, ccBuffer, name1, name2, name3, cpBuffer, cpBuffer_size,     \
                            cpHash, cpHash_size)                                                   \
    iesys_crypto_pHash(ectx, alg, NULL, ccBuffer, name1, name2, name3, cpBuffer, cpBuffer_size,    \
                       cpHash, cpHash_size)
#define iesys_crypto_rpHash(ectx, alg, rcBuffer, ccBuffer, rpBuffer, rpBuffer_size, rpHash,        \
                            rpHash_size)                                                           \
    iesys_crypto_pHash(ectx, alg, rcBuffer, ccBuffer, NULL, NULL, NULL, rpBuffer, rpBuffer_size,   \
                       rpHash, rpHash_size)

TSS2_RC iesys_crypto_hmac_finish2b(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                   ESYS_CRYPTO_CONTEXT_BLOB **context,
                                   TPM2B                     *tpm2b);

TSS2_RC iesys_crypto_hmac_update2b(ESYS_CRYPTO_CALLBACKS    *crypto_cb,
                                   ESYS_CRYPTO_CONTEXT_BLOB *context,
                                   TPM2B                    *tpm2b);

TSS2_RC iesys_crypto_hash_update2b(ESYS_CRYPTO_CALLBACKS    *crypto_cb,
                                   ESYS_CRYPTO_CONTEXT_BLOB *context,
                                   TPM2B                    *tpm2b);

TSS2_RC iesys_crypto_rsa_pk_encrypt(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                    TPM2B_PUBLIC          *pub_tpm_key,
                                    size_t                 in_size,
                                    BYTE                  *in_buffer,
                                    size_t                 max_out_size,
                                    BYTE                  *out_buffer,
                                    size_t                *out_size,
                                    const char            *label);

TSS2_RC iesys_crypto_hash_start(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                ESYS_CRYPTO_CONTEXT_BLOB **context,
                                TPM2_ALG_ID                hashAlg);

TSS2_RC iesys_crypto_hash_update(ESYS_CRYPTO_CALLBACKS    *crypto_cb,
                                 ESYS_CRYPTO_CONTEXT_BLOB *context,
                                 const uint8_t            *buffer,
                                 size_t                    size);

TSS2_RC iesys_crypto_hash_finish(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                 ESYS_CRYPTO_CONTEXT_BLOB **context,
                                 uint8_t                   *buffer,
                                 size_t                    *size);

TSS2_RC iesys_crypto_hash_abort(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                ESYS_CRYPTO_CONTEXT_BLOB **context);

TSS2_RC iesys_crypto_hmac_start(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                ESYS_CRYPTO_CONTEXT_BLOB **context,
                                TPM2_ALG_ID                hashAlg,
                                const uint8_t             *key,
                                size_t                     size);

TSS2_RC iesys_crypto_hmac_update(ESYS_CRYPTO_CALLBACKS    *crypto_cb,
                                 ESYS_CRYPTO_CONTEXT_BLOB *context,
                                 const uint8_t            *buffer,
                                 size_t                    size);

TSS2_RC iesys_crypto_hmac_finish(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                 ESYS_CRYPTO_CONTEXT_BLOB **context,
                                 uint8_t                   *buffer,
                                 size_t                    *size);

TSS2_RC iesys_crypto_hmac_abort(ESYS_CRYPTO_CALLBACKS     *crypto_cb,
                                ESYS_CRYPTO_CONTEXT_BLOB **context);

TSS2_RC
iesys_crypto_get_random2b(ESYS_CRYPTO_CALLBACKS *crypto_cb, TPM2B_NONCE *nonce, size_t num_bytes);

TSS2_RC iesys_crypto_get_ecdh_point(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                    TPM2B_PUBLIC          *key,
                                    size_t                 max_out_size,
                                    TPM2B_ECC_PARAMETER   *Z,
                                    TPMS_ECC_POINT        *Q,
                                    BYTE                  *out_buffer,
                                    size_t                *out_size);

TSS2_RC iesys_crypto_aes_encrypt(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                 uint8_t               *key,
                                 TPM2_ALG_ID            tpm_sym_alg,
                                 TPMI_AES_KEY_BITS      key_bits,
                                 TPM2_ALG_ID            tpm_mode,
                                 uint8_t               *buffer,
                                 size_t                 buffer_size,
                                 uint8_t               *iv);

TSS2_RC iesys_crypto_aes_decrypt(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                 uint8_t               *key,
                                 TPM2_ALG_ID            tpm_sym_alg,
                                 TPMI_AES_KEY_BITS      key_bits,
                                 TPM2_ALG_ID            tpm_mode,
                                 uint8_t               *buffer,
                                 size_t                 buffer_size,
                                 uint8_t               *iv);

TSS2_RC iesys_crypto_sm4_encrypt(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                 uint8_t               *key,
                                 TPM2_ALG_ID            tpm_sym_alg,
                                 TPMI_SM4_KEY_BITS      key_bits,
                                 TPM2_ALG_ID            tpm_mode,
                                 uint8_t               *buffer,
                                 size_t                 buffer_size,
                                 uint8_t               *iv);

TSS2_RC iesys_crypto_sm4_decrypt(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                 uint8_t               *key,
                                 TPM2_ALG_ID            tpm_sym_alg,
                                 TPMI_SM4_KEY_BITS      key_bits,
                                 TPM2_ALG_ID            tpm_mode,
                                 uint8_t               *buffer,
                                 size_t                 buffer_size,
                                 uint8_t               *iv);

TSS2_RC iesys_crypto_authHmac(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                              TPM2_ALG_ID            alg,
                              uint8_t               *hmacKey,
                              size_t                 hmacKeySize,
                              const uint8_t         *pHash,
                              size_t                 pHash_size,
                              const TPM2B_NONCE     *nonceNewer,
                              const TPM2B_NONCE     *nonceOlder,
                              const TPM2B_NONCE     *nonceDecrypt,
                              const TPM2B_NONCE     *nonceEncrypt,
                              TPMA_SESSION           sessionAttributes,
                              TPM2B_AUTH            *hmac);

TSS2_RC iesys_crypto_KDFaHmac(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                              TPM2_ALG_ID            alg,
                              uint8_t               *hmacKey,
                              size_t                 hmacKeySize,
                              uint32_t               counter,
                              const char            *label,
                              TPM2B_NONCE           *contextU,
                              TPM2B_NONCE           *contextV,
                              uint32_t               bitlength,
                              uint8_t               *hmac,
                              size_t                *hmacSize);

TSS2_RC iesys_crypto_KDFa(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                          TPM2_ALG_ID            hashAlg,
                          uint8_t               *hmacKey,
                          size_t                 hmacKeySize,
                          const char            *label,
                          TPM2B_NONCE           *contextU,
                          TPM2B_NONCE           *contextV,
                          uint32_t               bitLength,
                          uint32_t              *counterInOut,
                          BYTE                  *outKey,
                          BOOL                   use_digest_size);

TSS2_RC iesys_xor_parameter_obfuscation(ESYS_CRYPTO_CALLBACKS *cryto_cb,
                                        TPM2_ALG_ID            hash_alg,
                                        uint8_t               *key,
                                        size_t                 key_size,
                                        TPM2B_NONCE           *contextU,
                                        TPM2B_NONCE           *contextV,
                                        BYTE                  *data,
                                        size_t                 data_size);

TSS2_RC iesys_crypto_KDFe(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                          TPM2_ALG_ID            hashAlg,
                          TPM2B_ECC_PARAMETER   *Z,
                          const char            *label,
                          TPM2B_ECC_PARAMETER   *partyUInfo,
                          TPM2B_ECC_PARAMETER   *partyVInfo,
                          UINT32                 bit_size,
                          BYTE                  *key);

TSS2_RC iesys_initialize_crypto_backend(ESYS_CRYPTO_CALLBACKS *crypto_cb,
                                        ESYS_CRYPTO_CALLBACKS *user_cb);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* ESYS_CRYPTO_H */
