#define _DEFAULT_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <time.h>
#include <sys/time.h>
#include <sched.h>


#ifdef HAVE_LIBGCRYPT
#include "gcrypt.h"
#define HMAC_SHA256_DIGEST_SIZE 32
#else
#include "../../src/lib/third_party/include/gcrypt_light.h"
#include "../../src/lib/third_party/src/gcrypt_light.c"
void * ndpi_malloc(size_t size) {
  return malloc(size);
}
void * ndpi_calloc(unsigned long count, size_t size) {
  return calloc(count,size);
}
void   ndpi_free(void *ptr) {
  free(ptr);
}
#endif

    const uint8_t key1[16] = {
      0x53,0x13,0x18,0x3f,0x44,0x02,0x57,0xfe,0xf2,0x90,0x24,0x52,0x2b,0x5f,0x4d,0x90
    };
    const uint8_t enc1_src[16] = {
      0xe6,0x94,0x8d,0x6d,0x85,0x81,0xb5,0xa6,0x5e,0x33,0x2a,0x4b,0xee,0xba,0xdd,0x46
    };
    const uint8_t enc1_res[16] = {
      0x10,0x43,0xdd,0xb6,0xc5,0xb8,0xa0,0xe6,0x9e,0x0f,0xee,0x97,0x7f,0xa0,0xaa,0x4c
    };

    const uint8_t key2[16] = {
      0xee,0x38,0x7c,0xee,0x69,0x03,0x96,0x53,0xa1,0x0a,0x1b,0x62,0xa5,0x39,0x01,0x37
    };
    const uint8_t au2[80] = {
      0xc3,0xff,0x00,0x00,0x1c,0x08,0x42,0x35,0xd5,0xab,0xad,0xbe,0x3e,0x55,0x08,0xb0,0xec,0xb0,0xf5,0x44,0x63,0x0d,0xfb,0x32,0xfb,0x3a,0x43,0xcc,0x02,0xd5,0xe9,0x36
     ,0x55,0xb9,0x3b,0x46,0xf6,0xfe,0xaf,0xb7,0x29,0xd7,0x0e,0xb6,0x86,0x05,0xa8,0x12,0x30,0x3a,0x2e,0x00,0x6d,0xe3,0x99,0x4c,0x0f,0x6b,0xf2,0xca,0x71,0x47,0xcf,0x44
     ,0xce,0xe1,0xac,0x48,0xc1,0xff,0x6d,0x41,0xfd,0x7a,0x41,0xc4,0x00,0x00,0x00,0x00 };

    const uint8_t de2_src[432] = {
 0xe6,0x94,0x8d,0x6d,0x85,0x81,0xb5,0xa6,0x5e,0x33,0x2a,0x4b,0xee,0xba,0xdd,0x46,0x3a,0xec,0xd2,0x08,0x4d,0x7a,0x64,0x17,0x1c,0x11,0xdb,0x63,0x7e,0x78,0xc1,0xaf
,0x94,0xb5,0x71,0xab,0x50,0xcf,0xca,0xf1,0xa2,0x66,0x24,0xdc,0xa8,0x24,0x9a,0x09,0x9d,0x09,0x62,0xa2,0xad,0xfa,0xf7,0x6b,0x20,0x1a,0x74,0xc3,0x72,0xb8,0xf5,0x05
,0x1a,0x5a,0x6d,0x43,0xb8,0x97,0x7e,0x71,0x02,0x09,0xcc,0x27,0x33,0xf7,0x78,0x0a,0x5c,0x0f,0x9a,0x42,0x7f,0x2a,0x26,0xe3,0xbe,0x94,0x41,0xc6,0xca,0x20,0x8b,0x56
,0x07,0x96,0x23,0xdf,0xdd,0x93,0xba,0xb8,0x7e,0x24,0xa7,0xc9,0x56,0x01,0xf1,0x9f,0xfc,0xf3,0xfd,0x4f,0x1a,0xc4,0x8f,0xaf,0xbc,0xcc,0x9d,0xa8,0x62,0x74,0xf9,0x7c
,0xb0,0x69,0xd3,0x1b,0xd3,0x13,0xfa,0x9c,0x78,0x9b,0x25,0x84,0x10,0x73,0xa3,0xa1,0x25,0x34,0xc9,0x6f,0x43,0x94,0xd4,0x04,0x96,0x43,0xa0,0x8a,0xdc,0xd9,0x8e,0x59
,0x46,0xbc,0x68,0x54,0x86,0x20,0x48,0x20,0x23,0x05,0xe1,0x00,0x14,0xbf,0x7f,0xee,0x3f,0x65,0x08,0xa0,0xe9,0x4e,0xe5,0x78,0xaf,0x12,0x46,0xfe,0x4c,0x49,0x03,0x63
,0xe4,0xde,0x46,0x54,0x0e,0x00,0x82,0x14,0x6e,0xc1,0x99,0x36,0x8a,0x31,0x20,0xe7,0xbd,0x4d,0x02,0x7c,0xd9,0x3b,0xc0,0xec,0x2a,0xc4,0x55,0x32,0x81,0x6b,0xfd,0x14
,0xc0,0x45,0x5b,0x0c,0x0f,0x9e,0x81,0x55,0x2f,0x89,0x94,0x22,0x1f,0x98,0x9b,0xdc,0x47,0xed,0xef,0x28,0xd1,0x4b,0x0a,0xcb,0xa2,0xc2,0x6b,0xf8,0x96,0x0b,0x13,0xf6
,0xf5,0x80,0xf0,0x90,0xa9,0x5d,0xff,0x5f,0xd0,0x23,0x5c,0x6a,0xdd,0xd7,0xce,0x15,0xfc,0x8d,0x3a,0xf4,0x0c,0x4b,0xd5,0x6d,0xe1,0xad,0xf8,0xe1,0x73,0xd9,0x13,0xc6
,0xbe,0xb5,0x15,0x06,0xf7,0x88,0x17,0x8f,0xa4,0x74,0x0d,0x3e,0xb9,0x96,0x3e,0x95,0xb3,0x83,0xae,0x65,0x06,0xfa,0xf6,0xef,0x2c,0xb3,0xa2,0x3e,0xb0,0x61,0x24,0xdb
,0x3b,0xbf,0x35,0x97,0x46,0x1a,0xb5,0xf0,0xe5,0xfd,0xd0,0xef,0x75,0x02,0x1f,0x2a,0xbd,0x8f,0xea,0xe2,0xcc,0x1b,0x32,0x49,0x66,0x40,0x7e,0x11,0xfe,0x9a,0x11,0xe8
,0x51,0x39,0xcd,0x34,0x4d,0xd7,0xb8,0x98,0xbb,0xd2,0xdc,0xab,0x4d,0xd1,0x3e,0xe2,0x1f,0x82,0x04,0xb1,0x87,0x37,0x0d,0xbf,0x64,0xd2,0xc7,0x21,0xa3,0xd1,0x8c,0x08
,0x14,0x81,0x22,0x21,0x0f,0xbe,0x01,0x91,0xd1,0x8e,0xbb,0x76,0xf3,0xd5,0xe6,0xc9,0x64,0xb5,0x62,0x16,0xb8,0x0a,0xe0,0xfd,0x59,0x58,0x8d,0x85,0xf9,0xc2,0x76,0x91
,0x7d,0x5e,0x7a,0xdd,0x68,0xd7,0x6d,0x36,0x0d,0x19,0x4b,0x18,0x1f,0xac,0x89,0xd7
    };
    const uint8_t de2_res[432] = {
0x06,0x00,0x41,0xac,0x01,0x00,0x01,0xa8,0x03,0x03,0xc8,0x51,0xa2,0xeb,0x93,0x4c,0x0b,0xa4,0x12,0xe1,0xc4,0xa4,0x23,0xea,0x3f,0xd9,0x14,0xf2,0xfe,0x1c,0x8b,0x35
,0x1b,0xf6,0xac,0x36,0xdd,0xb8,0x5a,0x00,0xa6,0x90,0x00,0x00,0x06,0x13,0x01,0x13,0x02,0x13,0x03,0x01,0x00,0x01,0x79,0x00,0x33,0x00,0x47,0x00,0x45,0x00,0x17,0x00
,0x41,0x04,0x1f,0x32,0x49,0x4e,0x18,0x73,0x5e,0xa1,0x24,0x8f,0x95,0x39,0xb9,0xb8,0x21,0x47,0x77,0xc6,0xc7,0x8e,0x95,0x8a,0x27,0xc2,0x78,0x97,0x6f,0x30,0x8a,0xa7
,0x60,0x25,0xd4,0xae,0x83,0xe4,0x9a,0x32,0xc3,0x39,0x81,0x69,0x41,0x43,0x81,0x1a,0x54,0xa5,0x6b,0x45,0xba,0x30,0xb4,0x29,0x9d,0xf6,0x75,0xe9,0x74,0x53,0x9f,0xda
,0xf7,0xfd,0x00,0x00,0x00,0x09,0x00,0x07,0x00,0x00,0x04,0x61,0x62,0x63,0x64,0x00,0x10,0x00,0x08,0x00,0x06,0x05,0x68,0x33,0x2d,0x33,0x32,0x00,0x2b,0x00,0x09,0x08
,0x03,0x04,0x7f,0x1c,0x7f,0x1b,0x7f,0x1a,0x00,0x0d,0x00,0x0a,0x00,0x08,0x08,0x04,0x04,0x03,0x04,0x01,0x02,0x01,0x00,0x0a,0x00,0x06,0x00,0x04,0x00,0x17,0x00,0x1d
,0xff,0xa5,0x00,0x53,0x05,0x04,0x80,0x20,0x00,0x00,0x04,0x04,0x80,0x10,0x00,0x00,0x08,0x02,0x42,0x01,0x01,0x04,0x80,0x00,0x75,0x30,0x03,0x02,0x45,0xa0,0x09,0x02
,0x42,0x01,0x06,0x04,0x80,0x01,0x00,0x63,0x07,0x04,0x80,0x00,0xff,0xff,0x0e,0x01,0x08,0x0b,0x01,0x0a,0x0f,0x08,0xb0,0xec,0xb0,0xf5,0x44,0x63,0x0d,0xfb,0x48,0x38
,0x02,0x75,0xd5,0x50,0x57,0x01,0x01,0x80,0x00,0xde,0x1a,0x02,0x43,0xe8,0x80,0x00,0x71,0x58,0x01,0x03,0x6a,0xb2,0x00,0x00,0x2d,0x00,0x02,0x01,0x01,0x00,0x2a,0x00
,0x00,0x00,0x29,0x00,0x8b,0x00,0x66,0x00,0x60,0xe8,0xde,0x51,0xcd,0x3e,0xfe,0x73,0x59,0x6e,0xdf,0x58,0x7b,0x3a,0x20,0xa4,0x4f,0x09,0x87,0x57,0x71,0x0e,0x4f,0x7f
,0x3c,0xd0,0xae,0x86,0x66,0x29,0xde,0xd7,0x3c,0x40,0x6e,0xac,0xe4,0x3e,0x96,0x28,0x53,0xc3,0x37,0xb1,0xb2,0xb6,0xe1,0x21,0x5f,0xe3,0x66,0xa7,0x72,0x68,0x1e,0x7e
,0xab,0x79,0xe2,0xda,0x9a,0x20,0x42,0xd8,0xdb,0x27,0x0d,0x9b,0x9f,0x48,0xbc,0xf6,0xe8,0xf3,0x9a,0x42,0x34,0xea,0x86,0x4c,0x86,0x9d,0x7d,0x57,0x79,0xed,0xa6,0x6c
,0xfe,0x03,0xfc,0x2b,0x25,0x68,0x77,0x48,0x22,0xda,0xb8,0x49,0xc0,0x00,0x21,0x20,0x17,0x04,0x68,0xd7,0xe9,0xae,0x79,0x02,0xb8,0xcb,0xd2,0x3a,0x35,0xf8,0x70,0x94
,0x1e,0x5f,0x9d,0xaf,0x7f,0x05,0x44,0xe4,0xd5,0x84,0x9e,0x52,0x0c,0x1b,0x14,0xa9
    };

    const uint8_t iv2[12] = {
	    0xb9,0xd1,0x33,0xc4,0x86,0x8e,0x17,0xb1,0xbd,0xcd,0xf7,0xee
    };
    const uint8_t ct2[16] = { 
        0x62,0xb7,0xf4,0xf2,0xdd,0xfb,0xdb,0x31,0x1a,0xe0,0xec,0x0e,0xfe,0xf0,0xb8,0xe1 
    };

void test_md(void) {
    gcry_md_hd_t hh;
    gcry_error_t result;
    static uint8_t out[HMAC_SHA256_DIGEST_SIZE];
    static uint8_t key[20] = { 
        0xaf,0xbf,0xec,0x28,0x99,0x93,0xd2,0x4c,0x9e,0x97,0x86,0xf1,0x9c,0x61,0x11,0xe0,0x43,0x90,0xa8,0x99
    };
    static uint8_t src[12] = {
        0xb7,0x12,0x29,0x3a,0x9b,0x14,0xf2,0x0c,0xd0,0x59,0xdc,0xa8
    };
    static uint8_t orig[32] = {
        0x9a,0x27,0xd3,0x3b,0xfa,0xe8,0x46,0xc8,0x59,0xec,0x3a,0x7b,0xd1,0x01,0x6a,0xb1,0xb9,0xbd,0xf7,0x22,0x0f,0xb8,0x90,0xac,0x8d,0x19,0xf4,0xa6,0x97,0x4f,0xba,0x2a
    };

    result = gcry_md_open(&hh,GCRY_MD_SHA256,GCRY_MD_FLAG_HMAC);
    if(result) abort();
    gcry_md_reset(hh);
    result = gcry_md_setkey(hh, key,sizeof(key));
    if(result) abort();
    gcry_md_write(hh,src,sizeof src);
    memcpy(out, gcry_md_read(hh, 0), gcry_md_get_algo_dlen(GCRY_MD_SHA256));
    gcry_md_close(hh);
    if(memcmp(out,orig,32)) abort();
    //printf("MD OK\n");
}
#define gcr_err(name) if (err) { \
        fprintf (stderr, "Failure: %s %d\n", name, err);\
        break; }

static void single_encryption1(void) {
    gcry_cipher_hd_t handle1;
    gcry_error_t err = 0;

    // 32 bytes.. that's 256 bits
    unsigned char enc1_out[16] = {0, };

do {
    err = gcry_cipher_open (&handle1, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,0);
    gcr_err("gcry_cipher_open1");
    err = gcry_cipher_setkey (handle1, (char *)key1, sizeof(key1));
    gcr_err("gcry_cipher_setkey1");
    err =  gcry_cipher_encrypt (handle1,
                        enc1_out, sizeof(enc1_out), (const unsigned char *)enc1_src,sizeof enc1_src);
    gcr_err("gcry_cipher_encrypt1");


    if (!err && memcmp(enc1_out, enc1_res, 16) == 0) {
        //printf("my local test aes_ecb also works\n");
    } else {
        printf("local test aes_ecb failed\n");
        abort();
    }
} while(0);
    gcry_cipher_close(handle1);
}

static void single_encryption2(void) {
    gcry_cipher_hd_t handle2;
    uint8_t de2_out[sizeof de2_src];
    gcry_error_t err;

do {
    err = gcry_cipher_open (&handle2, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_GCM,0);
    gcr_err("gcry_cipher_open2");
    err = gcry_cipher_setkey (handle2, (char *)key2, sizeof(key2));
    gcr_err("gcry_cipher_setkey2");
    gcry_cipher_reset(handle2);
    gcr_err("gcry_cipher_setiv2");
    err = gcry_cipher_setiv (handle2, (char *)iv2, sizeof iv2);
    gcr_err("gcry_cipher_setiv2");
    err = gcry_cipher_authenticate (handle2, (char *)au2, sizeof au2);
    gcr_err("gcry_cipher_authenticate2");
    err =  gcry_cipher_decrypt (handle2,
            de2_out, sizeof de2_out, de2_src,sizeof de2_src);
    gcr_err("gcry_cipher_decrypt2");

    if (!err && memcmp(de2_out, de2_res, sizeof de2_res) == 0) {
      //  printf("My local test gcm_aes works\n");
    } else {
        printf("local test gcm_aes failed\n");
        abort();
    }

    err = gcry_cipher_checktag (handle2, (char *)ct2, sizeof ct2);
    gcr_err("gcry_cipher_checktag2");


} while(0);
    gcry_cipher_close(handle2);
}

u_int64_t timeval2usec(const struct timeval *tv) {
  return(tv->tv_sec*1000000+tv->tv_usec);
}

int tdiff2sec(const struct timeval *begin, const struct timeval *end) {
  u_int64_t b = timeval2usec(begin);
  u_int64_t e = timeval2usec(end);
  u_int64_t diff = (e - b) / 1000;

  return (int)diff;
}

int main(void) {
  struct timeval begin, end;
  int i,num_md = 2000000,num_enc = 10000000, num_dec = 1000000;

    gettimeofday(&begin, NULL);
    for(i=0; i < num_md; i++) {
        test_md();
    }
    gettimeofday(&end, NULL);
    printf("Test md %6d ms ", tdiff2sec(&begin, &end)); fflush(stdout);

    gettimeofday(&begin, NULL);
    for(i=0; i < num_enc; i++) {
        single_encryption1();
    }
    gettimeofday(&end, NULL);
    printf("enc %6d ms ", tdiff2sec(&begin, &end)); fflush(stdout);

    gettimeofday(&begin, NULL);
    for(i=0; i < num_dec; i++) {
        single_encryption2();
    }
    gettimeofday(&end, NULL);
    printf("dec %6d ms\n", tdiff2sec(&begin, &end));
    
    return 0;
}

/*
 * vim: set ts=4 sw=4 et foldmethod=marker foldmarker={{{{,}}}}:
 */