/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
//** Introduction
// This header contains the hash structure definitions used in the TPM code
// to define the amount of space to be reserved for the hash state. This allows
// the TPM code to not have to import all of the symbols used by the hash
// computations. This lets the build environment of the TPM code not to have
// include the header files associated with the CryptoEngine code.

#ifndef _CRYPT_HASH_H
#define _CRYPT_HASH_H

//** Hash-related Structures

union SMAC_STATES;

// These definitions add the high-level methods for processing state that may be
// an SMAC
typedef void(* SMAC_DATA_METHOD)(
    union SMAC_STATES       *state,
    UINT32                   size,
    const BYTE              *buffer
    );

typedef UINT16(* SMAC_END_METHOD)(
    union SMAC_STATES       *state,
    UINT32                   size,
    BYTE                    *buffer
    );

typedef struct sequenceMethods {
    SMAC_DATA_METHOD          data;
    SMAC_END_METHOD           end;
} SMAC_METHODS;

#define SMAC_IMPLEMENTED (CC_MAC || CC_MAC_Start)

// These definitions are here because the SMAC state is in the union of hash states.
typedef struct tpmCmacState {
    TPM_ALG_ID              symAlg;
    UINT16                  keySizeBits;
    INT16                   bcount; // current count of bytes accumulated in IV
    TPM2B_IV                iv;     // IV buffer
    TPM2B_SYM_KEY           symKey;
} tpmCmacState_t;

typedef union SMAC_STATES {
#if ALG_CMAC
    tpmCmacState_t          cmac;
#endif
    UINT64                  pad;
} SMAC_STATES;

typedef struct SMAC_STATE {
    SMAC_METHODS            smacMethods;
    SMAC_STATES             state;
} SMAC_STATE;

#if ALG_SHA1
#   define  IF_IMPLEMENTED_SHA1(op)     op(SHA1, Sha1)
#else
#   define  IF_IMPLEMENTED_SHA1(op)
#endif
#if ALG_SHA256
#   define  IF_IMPLEMENTED_SHA256(op)     op(SHA256, Sha256)
#else
#   define  IF_IMPLEMENTED_SHA256(op)
#endif
#if ALG_SHA384
#   define  IF_IMPLEMENTED_SHA384(op)     op(SHA384, Sha384)
#else
#   define  IF_IMPLEMENTED_SHA384(op)
#endif
#if ALG_SHA512
#   define  IF_IMPLEMENTED_SHA512(op)     op(SHA512, Sha512)
#else
#   define  IF_IMPLEMENTED_SHA512(op)
#endif
#if ALG_SM3_256
#   define  IF_IMPLEMENTED_SM3_256(op)     op(SM3_256, Sm3_256)
#else
#   define  IF_IMPLEMENTED_SM3_256(op)
#endif
#if ALG_SHA3_256
#   define  IF_IMPLEMENTED_SHA3_256(op)     op(SHA3_256, Sha3_256)
#else
#   define  IF_IMPLEMENTED_SHA3_256(op)
#endif
#if ALG_SHA3_384
#   define  IF_IMPLEMENTED_SHA3_384(op)     op(SHA3_384, Sha3_384)
#else
#   define  IF_IMPLEMENTED_SHA3_384(op)
#endif
#if ALG_SHA3_512
#   define  IF_IMPLEMENTED_SHA3_512(op)     op(SHA3_512, Sha3_512)
#else
#   define  IF_IMPLEMENTED_SHA3_512(op)
#endif

#define FOR_EACH_HASH(op)           \
        IF_IMPLEMENTED_SHA1(op)     \
        IF_IMPLEMENTED_SHA256(op)   \
        IF_IMPLEMENTED_SHA384(op)   \
        IF_IMPLEMENTED_SM3_256(op)  \
        IF_IMPLEMENTED_SHA3_256(op) \
        IF_IMPLEMENTED_SHA3_384(op) \
        IF_IMPLEMENTED_SHA3_512(op) 


#define HASH_TYPE(HASH, Hash)   tpmHashState##HASH##_t  Hash;
typedef union
{
    FOR_EACH_HASH(HASH_TYPE)
// Additions for symmetric block cipher MAC
#if SMAC_IMPLEMENTED
    SMAC_STATE                 smac;
#endif
    // to force structure alignment to be no worse than HASH_ALIGNMENT
#if HASH_ALIGNMENT == 8
    uint64_t             align;
#else
    uint32_t             align;
#endif
} ANY_HASH_STATE;

typedef ANY_HASH_STATE *PANY_HASH_STATE;
typedef const ANY_HASH_STATE    *PCANY_HASH_STATE;

#define ALIGNED_SIZE(x, b) ((((x) + (b) - 1) / (b)) * (b))
// MAX_HASH_STATE_SIZE will change with each implementation. It is assumed that
// a hash state will not be larger than twice the block size plus some
// overhead (in this case, 16 bytes). The overall size needs to be as
// large as any of the hash contexts. The structure needs to start on an
// alignment boundary and be an even multiple of the alignment
#define MAX_HASH_STATE_SIZE ((2 * MAX_HASH_BLOCK_SIZE) + 16)
#define MAX_HASH_STATE_SIZE_ALIGNED                                                 \
                    ALIGNED_SIZE(MAX_HASH_STATE_SIZE, HASH_ALIGNMENT)

// This is an aligned byte array that will hold any of the hash contexts.
typedef  ANY_HASH_STATE ALIGNED_HASH_STATE;

// The header associated with the hash library is expected to define the methods
// which include the calling sequence. When not compiling CryptHash.c, the methods
// are not defined so we need placeholder functions for the structures

#ifndef HASH_START_METHOD_DEF
#   define HASH_START_METHOD_DEF    void (HASH_START_METHOD)(void)
#endif
#ifndef HASH_DATA_METHOD_DEF
#   define HASH_DATA_METHOD_DEF     void (HASH_DATA_METHOD)(void)
#endif
#ifndef HASH_END_METHOD_DEF
#   define HASH_END_METHOD_DEF      void (HASH_END_METHOD)(void)
#endif
#ifndef HASH_STATE_COPY_METHOD_DEF
#   define HASH_STATE_COPY_METHOD_DEF     void (HASH_STATE_COPY_METHOD)(void)
#endif
#ifndef  HASH_STATE_EXPORT_METHOD_DEF
#   define  HASH_STATE_EXPORT_METHOD_DEF   void (HASH_STATE_EXPORT_METHOD)(void)
#endif
#ifndef  HASH_STATE_IMPORT_METHOD_DEF
#   define  HASH_STATE_IMPORT_METHOD_DEF   void (HASH_STATE_IMPORT_METHOD)(void)
#endif

// Define the prototypical function call for each of the methods. This defines the
// order in which the parameters are passed to the underlying function.
typedef HASH_START_METHOD_DEF;
typedef HASH_DATA_METHOD_DEF;
typedef HASH_END_METHOD_DEF;
typedef HASH_STATE_COPY_METHOD_DEF;
typedef HASH_STATE_EXPORT_METHOD_DEF;
typedef HASH_STATE_IMPORT_METHOD_DEF;


typedef struct _HASH_METHODS
{
    HASH_START_METHOD           *start;
    HASH_DATA_METHOD            *data;
    HASH_END_METHOD             *end;
    HASH_STATE_COPY_METHOD      *copy;      // Copy a hash block
    HASH_STATE_EXPORT_METHOD    *copyOut;   // Copy a hash block from a hash
                                            // context
    HASH_STATE_IMPORT_METHOD    *copyIn;    // Copy a hash block to a proper hash
                                            // context
} HASH_METHODS, *PHASH_METHODS;

#define HASH_TPM2B(HASH, Hash)  TPM2B_TYPE(HASH##_DIGEST, HASH##_DIGEST_SIZE);

FOR_EACH_HASH(HASH_TPM2B)

// When the TPM implements RSA, the hash-dependent OID pointers are part of the
// HASH_DEF. These macros conditionally add the OID reference to the HASH_DEF and the
// HASH_DEF_TEMPLATE.
#if ALG_RSA
#define PKCS1_HASH_REF   const BYTE  *PKCS1;
#define PKCS1_OID(NAME)  , OID_PKCS1_##NAME
#else
#define PKCS1_HASH_REF
#define PKCS1_OID(NAME)
#endif

// When the TPM implements ECC, the hash-dependent OID pointers are part of the
// HASH_DEF. These macros conditionally add the OID reference to the HASH_DEF and the
// HASH_DEF_TEMPLATE.
#if ALG_ECDSA 
#define ECDSA_HASH_REF    const BYTE  *ECDSA;
#define ECDSA_OID(NAME)  , OID_ECDSA_##NAME
#else
#define ECDSA_HASH_REF
#define ECDSA_OID(NAME)
#endif

typedef const struct HASH_DEF
{
    HASH_METHODS         method;
    uint16_t             blockSize;
    uint16_t             digestSize;
    uint16_t             contextSize;
    uint16_t             hashAlg;
    const BYTE          *OID;
    PKCS1_HASH_REF      // PKCS1 OID
    ECDSA_HASH_REF      // ECDSA OID
} HASH_DEF, *PHASH_DEF;

// Macro to fill in the HASH_DEF for an algorithm. For SHA1, the instance would be:
//  HASH_DEF_TEMPLATE(Sha1, SHA1)
// This handles the difference in capitalization for the various pieces.
#define HASH_DEF_TEMPLATE(HASH, Hash)                                               \
    HASH_DEF    Hash##_Def= {                                                       \
                        {(HASH_START_METHOD *)&tpmHashStart_##HASH,                 \
                         (HASH_DATA_METHOD *)&tpmHashData_##HASH,                   \
                         (HASH_END_METHOD *)&tpmHashEnd_##HASH,                     \
                         (HASH_STATE_COPY_METHOD *)&tpmHashStateCopy_##HASH,        \
                         (HASH_STATE_EXPORT_METHOD *)&tpmHashStateExport_##HASH,    \
                         (HASH_STATE_IMPORT_METHOD *)&tpmHashStateImport_##HASH,    \
                        },                                                          \
                        HASH##_BLOCK_SIZE,     /*block size */                      \
                        HASH##_DIGEST_SIZE,    /*data size */                       \
                        sizeof(tpmHashState##HASH##_t),                             \
                        TPM_ALG_##HASH, OID_##HASH                                  \
                        PKCS1_OID(HASH) ECDSA_OID(HASH)};

// These definitions are for the types that can be in a hash state structure.
// These types are used in the cryptographic utilities. This is a define rather than
// an enum so that the size of this field can be explicit.
typedef BYTE    HASH_STATE_TYPE;
#define HASH_STATE_EMPTY        ((HASH_STATE_TYPE) 0)
#define HASH_STATE_HASH         ((HASH_STATE_TYPE) 1)
#define HASH_STATE_HMAC         ((HASH_STATE_TYPE) 2)
#if CC_MAC || CC_MAC_Start
#define HASH_STATE_SMAC         ((HASH_STATE_TYPE) 3)
#endif


// This is the structure that is used for passing a context into the hashing
// functions. It should be the same size as the function context used within
// the hashing functions. This is checked when the hash function is initialized.
// This version uses a new layout for the contexts and a different definition. The
// state buffer is an array of HASH_UNIT values so that a decent compiler will put
// the structure on a HASH_UNIT boundary. If the structure is not properly aligned,
// the code that manipulates the structure will copy to a properly aligned
// structure before it is used and copy the result back. This just makes things
// slower.
// NOTE: This version of the state had the pointer to the update method in the
// state. This is to allow the SMAC functions to use the same structure without 
// having to replicate the entire HASH_DEF structure.
typedef struct _HASH_STATE
{
    HASH_STATE_TYPE          type;               // type of the context
    TPM_ALG_ID               hashAlg;
    PHASH_DEF                def;
    ANY_HASH_STATE           state;
} HASH_STATE, *PHASH_STATE;
typedef const HASH_STATE *PCHASH_STATE;


//** HMAC State Structures

// An HMAC_STATE structure contains an opaque HMAC stack state. A caller would
// use this structure when performing incremental HMAC operations. This structure
// contains a hash state and an HMAC key and allows slightly better stack
// optimization than adding an HMAC key to each hash state.
typedef struct hmacState
{
    HASH_STATE           hashState;          // the hash state
    TPM2B_HASH_BLOCK     hmacKey;            // the HMAC key
} HMAC_STATE, *PHMAC_STATE;

// This is for the external hash state. This implementation assumes that the size
// of the exported hash state is no larger than the internal hash state.
typedef struct
{
    BYTE                     buffer[sizeof(HASH_STATE)];
} EXPORT_HASH_STATE, *PEXPORT_HASH_STATE;

typedef const EXPORT_HASH_STATE *PCEXPORT_HASH_STATE;

#endif //  _CRYPT_HASH_H
