#ifndef __FIPSAPI_H__
#define __FIPSAPI_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <windef.h>
#include <des.h>
#include <tripldes.h>
#include <sha.h>
#include <modes.h>
#include <md5.h>

#if DEBUG 
#define FipsDebug(LEVEL, STRING) \
        { \
          DbgPrint STRING; \
        }
#else
#define FipsDebug(LEVEL, STRING)
#endif

#define     FIPS_DEVICE_NAME            L"\\Device\\Fips"

#define FIPS_CTL_CODE(code)         CTL_CODE(FILE_DEVICE_FIPS, \
                                            (code), \
                                            METHOD_BUFFERED, \
                                            FILE_ANY_ACCESS)

#define IOCTL_FIPS_GET_FUNCTION_TABLE   FIPS_CTL_CODE( 1)

#define     FIPS_CBC_DES    0x1
#define     FIPS_CBC_3DES   0x2

//
// Defines for IPSEC HMAC use
//
#define     MAX_LEN_PAD     65
#define     MAX_KEYLEN_SHA  64
#define     MAX_KEYLEN_MD5  64   

//
//     Fill in the DESTable struct with the decrypt and encrypt
//     key expansions.
//
//     Assumes that the second parameter points to DES_BLOCKLEN
//     bytes of key.
//
//

VOID FipsDesKey(DESTable *DesTable, UCHAR *pbKey);

//
//     Encrypt or decrypt with the key in DESTable
//
//

VOID FipsDes(UCHAR *pbOut, UCHAR *pbIn, void *pKey, int iOp);

//
//   Fill in the DES3Table structs with the decrypt and encrypt
//   key expansions.
//
//   Assumes that the second parameter points to 2 * DES_BLOCKLEN
//   bytes of key.
//
//

VOID Fips3Des3Key(PDES3TABLE pDES3Table, UCHAR *pbKey);

//
//   Encrypt or decrypt with the key in pKey
//

VOID Fips3Des(UCHAR *pbIn, UCHAR *pbOut, void *pKey, int op);

//
//   Initialize the SHA context.
//

VOID FipsSHAInit(A_SHA_CTX *pShaCtx);

//
//   Hash data into the hash context.
//

VOID FipsSHAUpdate(A_SHA_CTX *pShaCtx, UCHAR *pb, unsigned int cb);

//
//   Finish the SHA hash and copy the final hash value into the pbHash out param.
//

VOID FipsSHAFinal(A_SHA_CTX *pShaCtx, UCHAR *pbHash);

//
// FipsCBC (cipher block chaining) performs a XOR of the feedback register
// with the plain text before calling the block cipher
//
// NOTE - Currently this function assumes that the block length is
// DES_BLOCKLEN (8 bytes).
//
// Return: Failure if FALSE is returned, TRUE if it succeeded.
//

BOOL FipsCBC(
    ULONG  EncryptionAlg,
    BYTE   *pbOutput,
    BYTE   *pbInput,
    void   *pKeyTable,
    int    Operation,
    BYTE   *pbFeedback
    );

//
// FipsBlockCBC (cipher block chaining) performs a XOR of the feedback register
// with the plain text before calling the block cipher
//
// NOTE - The Length must be multiple of DES_BLOCKLEN (8)
// All the input buffer must be aligned on LONGLONG for performane reason.
//
// Return: Failure if FALSE is returned, TRUE if it succeeded.
//

BOOL FipsBlockCBC(
    ULONG  EncryptionAlg,
    BYTE   *pbOutput,
    BYTE   *pbInput,
    ULONG  Length,
    void   *pKeyTable,
    int    Operation,
    BYTE   *pbFeedback
    );

//
// Function : FIPSGenRandom
//
// Description : FIPS 186 RNG, the seed is generated by calling NewGenRandom.
//

BOOL FIPSGenRandom(
    IN OUT UCHAR *pb,
    IN ULONG cb
    );

//
// Function: FipsHmacSHAInit
//
// Description: Initialize a SHA-HMAC context 
//

VOID FipsHmacSHAInit(
    OUT A_SHA_CTX *pShaCtx,
    IN UCHAR *pKey,
    IN unsigned int cbKey
    );

//
// Function: FipsHmacSHAUpdate
//
// Description: Add more data to a SHA-HMAC context
//

VOID FipsHmacSHAUpdate(
    IN OUT A_SHA_CTX *pShaCtx,
    IN UCHAR *pb,
    IN unsigned int cb
    );

//
// Function: FipsHmacSHAFinal
//
// Description: Return result of SHA-HMAC 
//

VOID FipsHmacSHAFinal(
    IN A_SHA_CTX *pShaCtx,
    IN UCHAR *pKey,
    IN unsigned int cbKey,
    OUT UCHAR *pHash
    );

//
// Function: HmacMD5Init
//
// Description: Initialize a MD5-HMAC context 
//

VOID HmacMD5Init(
    OUT MD5_CTX *pMD5Ctx,
    IN UCHAR *pKey,
    IN unsigned int cbKey
    );

//
// Function: HmacMD5Update
//
// Description: Add more data to a MD5-HMAC context
//

VOID HmacMD5Update(
    IN OUT MD5_CTX *pMD5Ctx,
    IN UCHAR *pb,
    IN unsigned int cb
    );

//
// Function: HmacMD5Final
//
// Description: Return result of MD5-HMAC 
//

VOID HmacMD5Final(
    IN MD5_CTX *pMD5Ctx,
    IN UCHAR *pKey,
    IN unsigned int cbKey,
    OUT UCHAR *pHash
    );

// 
// Current FIPS function table
// Includes HMAC entry points
//
typedef struct _FIPS_FUNCTION_TABLE {

    VOID (*FipsDesKey)(DESTable *DesTable, UCHAR *pbKey);
    VOID (*FipsDes)(UCHAR *pbOut, UCHAR *pbIn, void *pKey, int iOp);
    VOID (*Fips3Des3Key)(PDES3TABLE pDES3Table, UCHAR *pbKey);
    VOID (*Fips3Des)(UCHAR *pbIn, UCHAR *pbOut, void *pKey, int op);
    VOID (*FipsSHAInit)(A_SHA_CTX *pShaCtx);
    VOID (*FipsSHAUpdate)(A_SHA_CTX *pShaCtx, UCHAR *pb, unsigned int cb);
    VOID (*FipsSHAFinal)(A_SHA_CTX *pShaCtx, UCHAR *pbHash);
    BOOL (*FipsCBC)(
        ULONG  EncryptionAlg,
        BYTE   *pbOutput,
        BYTE   *pbInput,
        void   *pKeyTable,
        int    Operation,
        BYTE   *pbFeedback
        );
    BOOL (*FIPSGenRandom)(
        IN OUT UCHAR *pb,
        IN ULONG cb
        );
    BOOL (*FipsBlockCBC)(
        ULONG  EncryptionAlg,
        BYTE   *pbOutput,
        BYTE   *pbInput,
        ULONG  Length,
        void   *pKeyTable,
        int    Operation,
        BYTE   *pbFeedback
        );
    VOID (*FipsHmacSHAInit)(
        OUT A_SHA_CTX *pShaCtx,
        IN UCHAR *pKey,
        IN unsigned int cbKey
        );   
    VOID (*FipsHmacSHAUpdate)(
        IN OUT A_SHA_CTX *pShaCtx,
        IN UCHAR *pb,
        IN unsigned int cb
        );
    VOID (*FipsHmacSHAFinal)(
        IN A_SHA_CTX *pShaCtx,
        IN UCHAR *pKey,
        IN unsigned int cbKey,
        OUT UCHAR *pHash
        );
    VOID (*HmacMD5Init)(
        OUT MD5_CTX *pMD5Ctx,
        IN UCHAR *pKey,
        IN unsigned int cbKey
        );
    VOID (*HmacMD5Update)(
        IN OUT MD5_CTX *pMD5Ctx,
        IN UCHAR *pb,
        IN unsigned int cb
        );
    VOID (*HmacMD5Final)(
        IN MD5_CTX *pMD5Ctx,
        IN UCHAR *pKey,
        IN unsigned int cbKey,
        OUT UCHAR *pHash
        );

} FIPS_FUNCTION_TABLE, *PFIPS_FUNCTION_TABLE;

//
// Old FIPS function table - please don't use
//
typedef struct _FIPS_FUNCTION_TABLE_1 {

    VOID (*FipsDesKey)(DESTable *DesTable, UCHAR *pbKey);
    VOID (*FipsDes)(UCHAR *pbOut, UCHAR *pbIn, void *pKey, int iOp);
    VOID (*Fips3Des3Key)(PDES3TABLE pDES3Table, UCHAR *pbKey);
    VOID (*Fips3Des)(UCHAR *pbIn, UCHAR *pbOut, void *pKey, int op);
    VOID (*FipsSHAInit)(A_SHA_CTX *pShaCtx);
    VOID (*FipsSHAUpdate)(A_SHA_CTX *pShaCtx, UCHAR *pb, unsigned int cb);
    VOID (*FipsSHAFinal)(A_SHA_CTX *pShaCtx, UCHAR *pbHash);
    BOOL (*FipsCBC)(
        ULONG  EncryptionAlg,
        BYTE   *pbOutput,
        BYTE   *pbInput,
        void   *pKeyTable,
        int    Operation,
        BYTE   *pbFeedback
        );
    BOOL (*FIPSGenRandom)(
        IN OUT UCHAR *pb,
        IN ULONG cb
        );
    BOOL (*FipsBlockCBC)(
        ULONG  EncryptionAlg,
        BYTE   *pbOutput,
        BYTE   *pbInput,
        ULONG  Length,
        void   *pKeyTable,
        int    Operation,
        BYTE   *pbFeedback
        );

} FIPS_FUNCTION_TABLE_1, *PFIPS_FUNCTION_TABLE_1;


#ifdef __cplusplus
}
#endif

#endif // __FIPSAPI_H__