#include <string.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/sha.h>
#include <openssl/md5.h>


//去填充函数
int cutFillPart(unsigned long signType, unsigned char* input, unsigned long inputLen, unsigned char* output, unsigned long* outputLen)
{
	if (0 == signType)//MD5
	{
		memcpy(output, input+(inputLen-16), 16);
		*outputLen = 16;
	}
	else if (1 == signType)//SHA1
	{
		memcpy(output, input+(inputLen-20), 20);
		*outputLen = 20;
	}
	else if (2 == signType)//SHA224
	{
		memcpy(output, input+(inputLen-28), 28);
		*outputLen = 28;
	}
	else if (3 == signType)//SHA256
	{
		memcpy(output, input+(inputLen-32), 32);
		*outputLen = 32;
	}
	else if (4 == signType)//SHA384
	{
		memcpy(output, input+(inputLen-48), 48);
		*outputLen = 48;
	}
	else if (5 == signType)//SHA512
	{
		memcpy(output, input+(inputLen-64), 64);
		*outputLen = 64;
	}
	else
	{
		*outputLen = 0;
		return 1;
	}
	return 0;
}

//获得公钥函数
int getPubKey(unsigned char* cert, unsigned long certLen, unsigned char* pubkey, unsigned long* pubkeyLen, unsigned long definedLen)
{
	int i;
	bool finded = false;
	unsigned char pubkey1024bitTitle[] = {0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00};
	unsigned long pubkey1024bitTitleLen = 7;
	unsigned char* title;
	unsigned long titleLen;
	if (definedLen == 128)
	{
		title = pubkey1024bitTitle;
		titleLen = pubkey1024bitTitleLen;
	}
	else
	{
		return 1;
	}

	for (i = 0; i<certLen - definedLen; ++i) //根据definedLen来寻找公钥
	{
		if(0 == memcmp((unsigned char*)(cert+i),title, titleLen))//找到公钥
		{
			memcpy(pubkey, (unsigned char*)(cert+i+titleLen),definedLen);
			*pubkeyLen = definedLen;
			finded = true;
			break;
		}
		continue;
	}
	if (!finded)
	{
		return 1;
	}
	return 0;
}

//HASH函数
int getPubTextHash(unsigned long signType, unsigned char* input, unsigned long inputLen, unsigned char* output, unsigned long* outputLen)
{
	int ret;
	if (0 == signType)//MD5
	{
		MD5_CTX c;
		ret = MD5_Init(&c);
		ret = MD5_Update(&c, input, inputLen);
		ret = MD5_Final(output, &c);
		*outputLen = 16;
	}
	else if (1 == signType)//SHA1
	{
		SHA_CTX c;
		ret = SHA1_Init(&c);
		ret = SHA1_Update(&c, input, inputLen);
		ret = SHA1_Final(output, &c);
		*outputLen = 20;
	}
	else if (2 == signType)//SHA224
	{
		SHA256_CTX c;
		ret = SHA224_Init(&c);
		ret = SHA224_Update(&c, input, inputLen);
		ret = SHA224_Final(output, &c);
		*outputLen = 28;
	}
	else if (3 == signType)//SHA256
	{
		SHA256_CTX c;
		ret = SHA256_Init(&c);
		ret = SHA256_Update(&c, input, inputLen);
		ret = SHA256_Final(output, &c);
		*outputLen = 32;
	}
	else if (4 == signType)//SHA384
	{
		SHA512_CTX c;
		ret = SHA384_Init(&c);
		ret = SHA384_Update(&c, input, inputLen);
		ret = SHA384_Final(output, &c);
		*outputLen = 32;
	}
	else if (5 == signType)//SHA512
	{
		SHA512_CTX c;
		ret = SHA512_Init(&c);
		ret = SHA512_Update(&c, input, inputLen);
		ret = SHA512_Final(output, &c);
		*outputLen = 64;
	}
	else
	{
		*outputLen = 0;
		return 1;
	}
	return 0;
}

unsigned long VerifySign(int signType, 
						 unsigned char* cert, unsigned long certLen,
						 unsigned char* pubText, unsigned long pubTextLen,
						 unsigned char* encryptedData, unsigned long encryptedDataLen)
{
	int ret;

	unsigned char decryptedData[256];
	memset(decryptedData, 0x00, 256);
	unsigned long decryptedDataLen = encryptedDataLen;

	unsigned char cuttedData[256];
	memset(cuttedData, 0x00, 256);
	unsigned long cuttedDataLen = encryptedDataLen;

	unsigned char public_exponent[256] = {0x01,0x00,0x01};
	int public_exponent_len = 3;

	unsigned char PubKey[256];
	memset(PubKey, 0x00, 256);
	unsigned long PubKeyLen = 0;

	ret = getPubKey(cert, certLen, PubKey, &PubKeyLen, encryptedDataLen);
	if (ret != 0)
	{
		return 5;
	}	

	if (PubKeyLen != encryptedDataLen)
	{
		return 1;
	}

	RSA* rsa;	
	rsa = RSA_new();
	rsa->n = BN_bin2bn(PubKey, PubKeyLen, rsa->n);
	rsa->e = BN_bin2bn(public_exponent, public_exponent_len, rsa->e);
	int flen = RSA_size(rsa);
	if (flen != PubKeyLen)
	{
		return 2;
	}
	ret = RSA_public_encrypt(flen, encryptedData, decryptedData, rsa, RSA_NO_PADDING);
	if (ret == 0xffffffff)
	{
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		return 3;
	}

	//释放RSA结构资源
	RSA_free(rsa);
	rsa = NULL;

	ret = cutFillPart(signType, decryptedData, flen, cuttedData, &cuttedDataLen);
	if (ret != 0)
	{
		printf("cut failed!");
	}

	ret = getPubTextHash(signType, pubText, pubTextLen, decryptedData, &decryptedDataLen);
	if (memcmp(cuttedData, decryptedData, cuttedDataLen) != 0)
	{
		return 4;
	}

	return 0;
}