#ifndef CKSUM_H_
#define CKSUM_H_

#include <sys/types.h>
#include <stdint.h>


/* +++++++++++++ */
/* +++ md5.c +++ */
/* +++++++++++++ */

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;

typedef struct {
	MD5_u32plus lo, hi;
	MD5_u32plus a, b, c, d;
	unsigned char buffer[64];
	MD5_u32plus block[16];
} MD5_CTX;

extern void cksum_MD5_Init(MD5_CTX *);
extern void cksum_MD5_Update(MD5_CTX *, const void *, unsigned long);
extern void cksum_MD5_Final(unsigned char *, MD5_CTX *);


/* ++++++++++++++ */
/* +++ sha1.c +++ */
/* ++++++++++++++ */

#define SHA1_HASH_LENGTH 20
#define SHA1_BLOCK_LENGTH 64

typedef struct sha1nfo {
	uint32_t buffer[SHA1_BLOCK_LENGTH/4];
	uint32_t state[SHA1_HASH_LENGTH/4];
	uint32_t byteCount;
	uint8_t bufferOffset;
	uint8_t keyBuffer[SHA1_BLOCK_LENGTH];
	uint8_t innerHash[SHA1_HASH_LENGTH];
} sha1nfo;


extern void cksum_sha1_init(sha1nfo *);
extern void cksum_sha1_write(sha1nfo *, const char *, size_t);
extern uint8_t * cksum_sha1_result(sha1nfo *);
extern void cksum_sha1_initHmac(sha1nfo *, const uint8_t *, int);
extern uint8_t * cksum_sha1_resultHmac(sha1nfo *);


/* ++++++++++++++++++++++++++++++ */
/* +++ sha2.c und hmac_sha2.c +++ */
/* ++++++++++++++++++++++++++++++ */

#define SHA224_DIGEST_SIZE ( 224 / 8)
#define SHA256_DIGEST_SIZE ( 256 / 8)
#define SHA384_DIGEST_SIZE ( 384 / 8)
#define SHA512_DIGEST_SIZE ( 512 / 8)

#define SHA256_BLOCK_SIZE  ( 512 / 8)
#define SHA512_BLOCK_SIZE  (1024 / 8)
#define SHA384_BLOCK_SIZE  SHA512_BLOCK_SIZE
#define SHA224_BLOCK_SIZE  SHA256_BLOCK_SIZE

/* +++ sha2.c +++ */

typedef unsigned char sha2_uint8;
typedef unsigned int  sha2_uint32;
typedef unsigned long long sha2_uint64;

typedef struct {
    unsigned int tot_len;
    unsigned int len;
    unsigned char block[2 * SHA256_BLOCK_SIZE];
    sha2_uint32 h[8];
} sha256_ctx;

typedef struct {
    unsigned int tot_len;
    unsigned int len;
    unsigned char block[2 * SHA512_BLOCK_SIZE];
    sha2_uint64 h[8];
} sha512_ctx;

typedef sha512_ctx sha384_ctx;
typedef sha256_ctx sha224_ctx;

void cksum_sha224_init(sha224_ctx *);
void cksum_sha224_update(sha224_ctx *, const unsigned char *, unsigned int);
void cksum_sha224_final(sha224_ctx *, unsigned char *);

void cksum_sha256_init(sha256_ctx *);
void cksum_sha256_update(sha256_ctx *, const unsigned char *, unsigned int);
void cksum_sha256_final(sha256_ctx *, unsigned char *);

void cksum_sha384_init(sha384_ctx *);
void cksum_sha384_update(sha384_ctx *, const unsigned char *, unsigned int);
void cksum_sha384_final(sha384_ctx *, unsigned char *);

void cksum_sha512_init(sha512_ctx *);
void cksum_sha512_update(sha512_ctx *, const unsigned char *, unsigned int);
void cksum_sha512_final(sha512_ctx *, unsigned char *);

/* +++ hmac_sha2.c +++ */

typedef struct {
    sha224_ctx ctx_inside;
    sha224_ctx ctx_outside;

    /* for hmac_reinit */
    sha224_ctx ctx_inside_reinit;
    sha224_ctx ctx_outside_reinit;

    unsigned char block_ipad[SHA224_BLOCK_SIZE];
    unsigned char block_opad[SHA224_BLOCK_SIZE];
} hmac_sha224_ctx;

typedef struct {
    sha256_ctx ctx_inside;
    sha256_ctx ctx_outside;

    /* for hmac_reinit */
    sha256_ctx ctx_inside_reinit;
    sha256_ctx ctx_outside_reinit;

    unsigned char block_ipad[SHA256_BLOCK_SIZE];
    unsigned char block_opad[SHA256_BLOCK_SIZE];
} hmac_sha256_ctx;

typedef struct {
    sha384_ctx ctx_inside;
    sha384_ctx ctx_outside;

    /* for hmac_reinit */
    sha384_ctx ctx_inside_reinit;
    sha384_ctx ctx_outside_reinit;

    unsigned char block_ipad[SHA384_BLOCK_SIZE];
    unsigned char block_opad[SHA384_BLOCK_SIZE];
} hmac_sha384_ctx;

typedef struct {
    sha512_ctx ctx_inside;
    sha512_ctx ctx_outside;

    /* for hmac_reinit */
    sha512_ctx ctx_inside_reinit;
    sha512_ctx ctx_outside_reinit;

    unsigned char block_ipad[SHA512_BLOCK_SIZE];
    unsigned char block_opad[SHA512_BLOCK_SIZE];
} hmac_sha512_ctx;

void cksum_hmac_sha224_init(hmac_sha224_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha224_update(hmac_sha224_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha224_final(hmac_sha224_ctx *, unsigned char *, unsigned int);

void cksum_hmac_sha256_init(hmac_sha256_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha256_update(hmac_sha256_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha256_final(hmac_sha256_ctx *, unsigned char *, unsigned int);

void cksum_hmac_sha384_init(hmac_sha384_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha384_update(hmac_sha384_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha384_final(hmac_sha384_ctx *, unsigned char *, unsigned int);

void cksum_hmac_sha512_init(hmac_sha512_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha512_update(hmac_sha512_ctx *, const unsigned char *, unsigned int);
void cksum_hmac_sha512_final(hmac_sha512_ctx *, unsigned char *, unsigned int);

#endif /* CKSUM_H_ */
