#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>

void sec_hash_48(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt);
void sec_hash_aes_256_cbc_sha(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt);
void printmem(char *str, unsigned char *mem, unsigned int len, unsigned char hex);
unsigned long stampstart(char *str);
unsigned long stampstop(char *str, unsigned long start);
unsigned long min(int num1, int num2);
unsigned long max(int num1, int num2);
void my_hash(unsigned char *out, unsigned char *in, unsigned char *salt1, unsigned char *salt2, unsigned char salt);
unsigned char to_decrypt_key[1024] = "\x65\x51\x2d\xa6\xd4\xa7\x38\xdf\xac\x79\x1f\x0b\xd9\xb2\x61\x7d\x73\x88\x32\xd9\xf2\x62\x3a\x8b\x11\x04\x75\xca\x42\xff\x4e\xd9\xcc\xb9\xfa\x86\xf3\x16\x2f\x09\x73\x51\x66\xaa\x29\xcd\x80\x61\x0f\xe8\x13\xce\x5b\x8e\x0a\x23\xf8\x91\x5e\x5f\x54\x70\x80\x8e\x7b\x28\xef\xb6\x69\xb2\x59\x85\x74\x98\xe2\x7e\xd8\xcc\x76\x80\xe1\xb6\x45\x4d\xc7\xcd\x84\xce\xb4\x52\x79\x74\xcd\xe6\xd7\xd1\x9c\xad\xef\x63\x6c\x0f\xf7\x05\xe4\x4d\x1a\xd3\xcb\x9c\xd2\x51\xb5\x61\xcb\xff\x7c\xee\xc7\xbc\x5e\x15\xa3\xf2\x52\x0f\xbb\x32";
unsigned char inbuf[4096]= "\x4a\xc3\x3e\x9d\x77\x78\x01\x2c\xb4\xbc\x4c\x9a\x84\xd7\xb9\x90\x0c\x21\x10\xf0\xfa\x00\x7c\x16\xbb\x77\xfb\x72\x42\x4f\xad\x50\x4a\xd0\xaa\x6f\xaa\x44\x6c\x62\x94\x1b\xc5\xfe\xe9\x1c\x5e\xde\x85\x0b\x0e\x05\xe4\x18\x6e\xd2\xd3\xb5\x20\xab\x81\xfd\x18\x9a\x73\xb8\xd7\xef\xc3\xdd\x74\xd7\x9c\x1e\x6f\x21\x6d\xf8\x24\xca\x3c\x70\x78\x36\x12\x7a\x8a\x9c\xac\x4e\x1c\xa8\xfb\x27\x30\xba\x9a\xf4\x2f\x0a\xab\x80\x6a\xa1\x60\x74\xf0\xe3\x91\x84\xe7\x90\x88\xcc\xf0\x95\x7b\x0a\x22\xf2\xf9\x27\xe0\xdd\x38\x0c\xfd\xe9\x03\x71\xdc\x70\xa4\x6e\xdf\xe3\x72\x9e\xa1\xf0\xc9\x00\xd6\x03\x55\x6a\x67\x5d\x9c\xb8\x75\x01\xb0\x01\x9f\xe6\xd2\x44\x18\xbc\xca\x7a\x10\x39\xa6\xcf\x15\xc7\xf5\x35\xd4\xb3\x6d\x91\x23\x84\x99\xba\xb0\x7e\xd0\xc9\x4c\xbf\x3f\x33\x68\x37\xb7\x7d\x44\xb0\x0b\x2c\x0f\xd0\x75\xa2\x6b\x5b\xe1\x9f\xd4\x69\x9a\x14\xc8\x29\xb7\xd9\x10\xbb\x99\x30\x9a\xfb\xcc\x13\x1f\x76\x4e\xe6\xdf\x14\xaa\xd5\x60\xbf\x91\x49\x0d\x64\x42\x29\xa8\x64\x27\xd4\x5e\x1b\x18\x03\xa8\x73\xd6\x05\x6e\xf7\x50\xb0\x09\x6b\x69\x7a\x12\x28\x58\xef\x5a\x86\x11\xde\x71\x71\x9f\xca\xbd\x79\x2a\xc2\xe5\x9b\x5e\x32\xe7\xcb\x97\x6e\xa0\xea\xa4\xa4\x6a\x32\xf9\x37\x39\xd8\x37\x6d\x63\xf3\x08\x1c\xdd\x06\xdd\x2c\x2b\x9f\x04\x88\x5f\x36\x42\xc1\xb1\xc7\xe8\x2d\x5d\xa4\x6c\xe5\x60\x94\xae\xd0\x90\x1e\x88\xa0\x87\x52\xfb\xed\x97\xa5\x25\x5a\xb7\x55\xc5\x13\x07\x85\x27\x40\xed\xb8\xa0\x26\x13\x44\x0c\xfc\xcc\x5a\x09\xe5\x44\xb5\x63\xa1\x43\x51\x23\x4f\x17\x21\x89\x2e\x58\xfd\xf9\x63\x74\x04\x70\x1e\x7d\xd0\x66\xba\x40\x5e\x45\xdc\x39\x7c\x53\x0f\xa8\x38\xb2\x13\x99\x27\xd9\x4a\x51\xe9\x9f\x2a\x92\xbb\x9c\x90\xab\xfd\xf1\xb7\x40\x05\xa9\x7a\x20\x63\x36\xc1\xef\xb9\xad\xa2\xe0\x1d\x20\x4f\xb2\x34\xbd\xea\x07\xac\x21\xce\xf6\x8a\xa2\x9e\xcd\xfa";
unsigned char server_random[] = "\x44\x4c\x94\x8f\xfe\x81\xed\x93\x65\x02\x88\xa3\xf8\xeb\x63\x86\x0e\x2c\xf6\x8d\xd0\x0f\x2c\x2a\xd6\x4f\xcd\x2d\x3c\x16\xd7\xd6";
unsigned char client_random[] = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\xb8\x93\xbb\x90\xe9\x2a\xa2\x4d\x6d\xcc\x1c\xe7\x2a\x80\x21";
unsigned char iv[] = "\xf3\x9d\x13\x79\x67\x1e\x37\xf6\x98\xbe\x59\x18\x4c\xfc\x75\x56";

/*
unsigned char to_decrypt_key[1024] = "\x49\x22\x4e\x73\x16\xa7\xc1\x60\x67\xaa\xd5\xc9\x9e\x1c\x00\x1a\x11\x04\xec\x1b\xe0\xba\xa9\xa1\x2d\x22\xa0\x94\xe9\x6c\xf1\xd9\xc2\xa6\x4b\xc3\xc9\x78\x5b\x2b\xd3\x79\x29\x18\x91\x81\xf0\x71\x6b\x56\x0f\x0e\x98\x87\xd3\x22\xca\xf8\x35\x50\x56\x3e\x6b\xc2";
unsigned char server_random[] = "\x00\x00\x00\x00\x67\x3a\xfa\xce\xd9\x51\xba\xe4\xfc\x64\x95\x03\x82\x63\x0f\xe3\x39\x6b\xc7\xbd\x2b\xe5\x51\x37\x23\x48\x5b\xfb";
unsigned char client_random[] = "\x00\x00\x00\x00\xcc\x10\x93\xb0\x7d\x56\x45\x6c\x32\xd2\xd6\x48\x96\xf2\xde\x96\x4d\x6c\x85\xc5\xe2\x33\x30\xf5\xf3\x67\x26\x7f";
//unsigned char iv[] = "\x31\xab\xa3\x02\xd4\x27\xd9\xe6\x77\x3c\x1c\xb6\x3a\xbd\x23\xff";
unsigned char iv[] = "\x77\x3c\x1c\xb6\x3a\xbd\x23\xff";
unsigned char inbuf[4096] = "\x1a\xab\x72\xa9\x9f\xae\xed\x99\x88\x38\xfd\xc3\xf8\x26\x27\x08\x2e\x5b\x3a\xa7\xb4\xb7\x11\x58\x31\x70\x31\x28\x7e\xba\x13\xcb\xdc\x3a\xdb\xbd\x1c\x95\x4c\x87\x7f\x44\x44\x97\xbe\xb5\x92\xa7\x83\x9d\x73\xb0\xe2\x62\x60\x4e\xf7\x74\x97\xc8\x16\xa0\xdc\x9a\x5c\x33\x7c\x7d\x1b\x70\xdc\xe8\xa9\x59\x9b\xb4\xe1\xc8\xd5\x84\x63\x88\xee\xb2\xb4\xba\xf3\x2f\x2b\xf3\x84\x32\x15\xc8\x9a\x3e\x6b\xd9\x30\x87\x5b\x0a\x66\x47\xa3\x6f\x88\x12\x16\x7a\x52\x2e\x76\x67\x89\x73\x69\xff\x86\x45\x6d\x93\x79\x4e\x98\xb9\x65\x1b\x33\xaf\xd5\xa6\x99\xe6\xdb\x20\xc7\xc0\x3d\x56\xd2\x95\xc3\x30\x43\xf4\x7a\x44\x9e\x03\xc8\xad\xb3\x29\xc3\x6b\x70\xc0\x23\xde\x2b\x05\x6d\x0b\x1f\x80\x70\xdc\x7d\xbe\xe2\xab\x64\x95\x16\xb3\x60\x07\x43\xb2\x42\x28\x99\x79\x18\xec\x33\xd4\x7c\x9c\x3e\x62\xc5\x06\xb3\x4c\xbd\xc6\xee\x59\x92\xc2\xc0\x47\x9d\xfb\xfc\xe1\x07\x07\xea\x91\xd3\xa9\x47\x5d\x26\x6f\x31\x0c\xe7\xbc\x37\x9d\x76\x0a\xd0\x11\x6e\x07\x96\xad\x6c\x66\xde\xb0\x97\x66\x17\x34\x8a\x11\x99\x5b\x3f\x39\x5c\xe8\x61\x12\x15\x18\xf0\xda\xd7\x7c\xc7\x51\x57\x8d\x9c\xa1\x75\xd4\x6b\xd7\x8a\xd6\x25\xd9\xb4\x14\x03\x6c\xb7\xd9\x18\x31\x84\x31\xab\x03\x53\xe6\x2f\xb5\xfd\x60\xf7\x95\x7e\xe7\x89\x9b\x99\x44\x03\xd1\xae\xa6\xcf\xd1\x10\x5c\x6a\x49\x0a\x10\x72\x8e\xfb\x67\x7a\x10\xe6\x7b\x60\xa1\xe6\xd3\x12\x28\xf4\x07\x18\x96\x50\x14\x71\x40\x65\x8a\x0c\x5b\xb4\xca\x85\xdf\x87\x12\x10\xe7\x81\x99";
*/
#define DEBUG

#ifdef DEBUG
#define PRINT(str, mem, len, hex) printmem(str, mem, len, hex);
#else
#define PRINT(str, mem, len, hex) 0
#endif

int main(void)
{
	unsigned long key_calc_start, key_calc_end;
	RSA *rsa;
	FILE *fp;
	int i, check, pre_master_len = 128;
	unsigned char pre_master[64]; 
        unsigned char outbuf[4096];
        AES_KEY aeskey, aeskey1;
	unsigned char master_secret[48];
	unsigned char key_block[144];
	unsigned int  rid = 0;
	int rc = 0;
	unsigned char iv_input[8];
        
	rsa = RSA_new();
	/* 1 Open server's private key file */
	if((fp = fopen("server.key", "rb")) == NULL)
		{
		printf("Cannot open server key file.\n");
		return;
	}

	/* 2 Generate RSA struct from private key file */
	PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL);

	/* 3 Check for successful key generation */
	if(RSA_check_key(rsa) != 1)
		{
		printf("RSA_check_key(): PrivateKey check failed\n");
		return;
		}

	/* 4 Using Private RSA Key, decode the client_pre_master_secret */
	check = RSA_private_decrypt(pre_master_len, to_decrypt_key,
	pre_master, rsa, RSA_PKCS1_PADDING);
	if(check == -1)
		{
		printf("RSA_private_decrypt() failed");
		exit(1);
		}
	PRINT("\nPremaster: ",pre_master,check,1);

	/* 5 Generate master secret */
	sec_hash_48(master_secret, pre_master, client_random, server_random, 'A');
	PRINT("\nMaster secret: ",master_secret,48,1);

	/* 6 Generate key block */
	sec_hash_aes_256_cbc_sha(key_block, master_secret, server_random, client_random, 'A'); 
	PRINT("\nkey block: ",key_block,144,1);
        AES_set_decrypt_key(&key_block[40], 32*8, &aeskey);

        memset(outbuf, 0, sizeof(outbuf));
        /* 7 Decrypt data */
	printf("Decrypt using OpenSSL.\n");
	AES_cbc_encrypt(inbuf, outbuf, 432, &aeskey, iv , AES_DECRYPT);

        if (rc) {
                printf("Error!! Decryption failed - rc = 0x%X\n", rc);
                return -1;
        }
	printf("%s", outbuf);	
	PRINT("Http : \n",outbuf,4096,1);
	printf("\n");

	return;
}

/* 48-byte transformation used to generate master secret and key material. Both SHA1 and MD5 algorithms are used. */
void sec_hash_48(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt)
{
	unsigned char shasig[20];
	unsigned char pad[4];
	SHA_CTX sha;
	MD5_CTX md5;
	int i;

	for (i = 0; i < 3; i++)
	{
		memset(pad, salt + i, i + 1);

		SHA1_Init(&sha);
		SHA1_Update(&sha, pad, i + 1);
		SHA1_Update(&sha, in, 48);
		SHA1_Update(&sha, salt1, 32);
		SHA1_Update(&sha, salt2, 32);
		SHA1_Final(shasig, &sha);

		MD5_Init(&md5);
		MD5_Update(&md5, in, 48);
		MD5_Update(&md5, shasig, 20);
		MD5_Final(&out[i * 16], &md5);
	}
}

void sec_hash_aes_256_cbc_sha(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt)
{
        unsigned char shasig[20];
        unsigned char pad[10];
        SHA_CTX sha;
        MD5_CTX md5;
        int i;

        for (i = 0; i < 7; i++)
        {
                memset(pad, salt + i, i + 1);

                SHA1_Init(&sha);
                SHA1_Update(&sha, pad, i + 1);
                SHA1_Update(&sha, in, 48);
                SHA1_Update(&sha, salt1, 32);
                SHA1_Update(&sha, salt2, 32);
                SHA1_Final(shasig, &sha);

                MD5_Init(&md5);
                MD5_Update(&md5, in, 48);
                MD5_Update(&md5, shasig, 20);
                MD5_Final(&out[i * 16], &md5);
        }
}
#if 0
void my_hash(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt)
{
        unsigned char shasig[20];
        unsigned char pad[10];
        SHA_CTX sha;
        MD5_CTX md5;
        int i;

        for (i = 0; i < 1; i++)
        {
                memset(pad, salt + i, i + 1);

                SHA1_Init(&sha);
                SHA1_Update(&sha, pad, i + 1);
                SHA1_Update(&sha, in, 48);
                SHA1_Update(&sha, salt1, 32);
                SHA1_Update(&sha, salt2, 32);
                SHA1_Final(shasig, &sha);

                MD5_Init(&md5);
                MD5_Update(&md5, in, 48);
                MD5_Update(&md5, shasig, 20);
                MD5_Final(&out[i * 16], &md5);
        }
}
#endif

void printmem(char *str, unsigned char *mem, unsigned int len, unsigned char hex)
{
        int i=0;
	printf("\n%s",str);
        if(hex)
                while(i<len)
                        printf("%x ", mem[i++]);
        else
                while(i<len)
                        printf("%c",mem[i++]);
        return;
}
