#include "stdafx.h"
#include "Encrypt.h"
#include <openssl/pem.h>
//#include <openssl/ossl_typ.h>
//#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include "hmacsha1.h"
#include "md5.h"

namespace base {

	static const std::string base64_chars =
		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		"abcdefghijklmnopqrstuvwxyz"
		"0123456789+/";

	//////////////////////////
	CEncrypt::CEncrypt()
	{
	}


	CEncrypt::~CEncrypt()
	{
	}
	
	std::string CEncrypt::EncodeBase64(unsigned char* sData, int nDataByte)
	{
		unsigned char const* bytes_to_encode = sData;
		int in_len = nDataByte;

		std::string ret;
		int i = 0;
		int j = 0;
		unsigned char char_array_3[3];
		unsigned char char_array_4[4];

		while (in_len--) {
			char_array_3[i++] = *(bytes_to_encode++);
			if (i == 3) {
				char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
				char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
				char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
				char_array_4[3] = char_array_3[2] & 0x3f;

				for (i = 0; (i < 4); i++)
					ret += base64_chars[char_array_4[i]];
				i = 0;
			}
		}

		if (i)
		{
			for (j = i; j < 3; j++)
				char_array_3[j] = '\0';

			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for (j = 0; (j < i + 1); j++)
				ret += base64_chars[char_array_4[j]];

			while ((i++ < 3))
				ret += '=';
		}
		return ret;
		/*const char EncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		string strEncode;
		unsigned char Tmp[4] = { 0 };
		int LineLength = 0;
		for (int i = 0; i < (int)(nDataByte / 3); i++)
		{
			Tmp[1] = *sData++;
			Tmp[2] = *sData++;
			Tmp[3] = *sData++;
			strEncode += EncodeTable[Tmp[1] >> 2];
			strEncode += EncodeTable[((Tmp[1] << 4) | (Tmp[2] >> 4)) & 0x3F];
			strEncode += EncodeTable[((Tmp[2] << 2) | (Tmp[3] >> 6)) & 0x3F];
			strEncode += EncodeTable[Tmp[3] & 0x3F];
			if (LineLength += 4, LineLength == 76) { strEncode += "\r\n"; LineLength = 0; }
		}

		int Mod = nDataByte % 3;
		if (Mod == 1)
		{
			Tmp[1] = *sData++;
			strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
			strEncode += EncodeTable[((Tmp[1] & 0x03) << 4)];
			strEncode += "==";
		}
		else if (Mod == 2)
		{
			Tmp[1] = *sData++;
			Tmp[2] = *sData++;
			strEncode += EncodeTable[(Tmp[1] & 0xFC) >> 2];
			strEncode += EncodeTable[((Tmp[1] & 0x03) << 4) | ((Tmp[2] & 0xF0) >> 4)];
			strEncode += EncodeTable[((Tmp[2] & 0x0F) << 2)];
			strEncode += "=";
		}

		return strEncode;*/
	}

	std::string CEncrypt::DecodeBase64(const char* sData, int nDataByte)
	{
		int nOutByte = 0;
		const char DecodeTable[] =
		{
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			62, // '+'
			0, 0, 0,
			63, // '/'
			52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
			0, 0, 0, 0, 0, 0, 0,
			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
			13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
			0, 0, 0, 0, 0, 0,
			26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
			39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
		};

		string strDecode;
		int nValue;
		int i = 0;
		while (i < nDataByte)
		{
			if (*sData != '\r' && *sData != '\n')
			{
				nValue = DecodeTable[*sData++] << 18;
				nValue += DecodeTable[*sData++] << 12;
				strDecode += (nValue & 0x00FF0000) >> 16;
				nOutByte++;
				if (*sData != '=')
				{
					nValue += DecodeTable[*sData++] << 6;
					strDecode += (nValue & 0x0000FF00) >> 8;
					nOutByte++;
					if (*sData != '=')
					{
						nValue += DecodeTable[*sData++];
						strDecode += nValue & 0x000000FF;
						nOutByte++;
					}
				}
				i += 4;
			}
			else
			{
				sData++;
				i++;
			}
		}
		return strDecode;
	}

	std::string CEncrypt::EncryptRsa(string sKey, string sValue)
	{
		string strPublicKey = sKey;
		int nPublicKeyLen = strPublicKey.size();
		for (int i = 64; i < nPublicKeyLen; i += 64)
		{
			if (strPublicKey[i] != '\n')
			{
				strPublicKey.insert(i, "\n");
			}
			i++;
		}
		strPublicKey.insert(0, "-----BEGIN PUBLIC KEY-----\n");
		strPublicKey.append("\n-----END PUBLIC KEY-----\n");

		BIO *bio = NULL;
		RSA *rsa = NULL;
		char *chPublicKey = const_cast<char *>(strPublicKey.c_str());
		if ((bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL)       //从字符串读取RSA公钥
		{
			return "";
		}
		rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);   //从bio结构中得到rsa结构
		if (!rsa)
		{
			ERR_load_crypto_strings();
			char errBuf[512];
			ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf));
			BIO_free_all(bio);
			return "";
		}

		int rsa_len = sValue.length();
		unsigned char enc_text[1024] = { 0 };

		if (RSA_public_encrypt(rsa_len, (unsigned char *)sValue.c_str(), enc_text, rsa, RSA_PKCS1_PADDING) < 0)
		{
			char cerr[1024];
			ERR_error_string(1024, cerr);
			return "";
		}

		BIO_free_all(bio);

		int nout = 0;
		string strTmpResult = EncodeBase64(enc_text, 128);
		return strTmpResult;
	}

	std::string CEncrypt::DecryptRsa(string sKey, string sValue)
	{
		int nPublicKeyLen = sKey.size();
		for (int i = 64; i < nPublicKeyLen; i += 64)
		{
			if (sKey[i] != '\n')
			{
				sKey.insert(i, "\n");
			}
			i++;
		}
		sKey.insert(0, "-----BEGIN RSA PRIVATE KEY-----\n");
		sKey.append("\n-----END RSA PRIVATE KEY-----\n");

		BIO *bio = NULL;
		RSA *rsa = NULL;
		char *chKey = const_cast<char *>(sKey.c_str());
		if ((bio = BIO_new_mem_buf(chKey, -1)) == NULL)
		{
			return "";
		}
		rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
		if (!rsa)
		{
			ERR_load_crypto_strings();
			char errBuf[512];
			ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf));
			BIO_free_all(bio);
			return "";
		}


		string strEn64 = sValue;// DecodeBase64((char*)sValue.c_str(), sValue.length());

		int rsa_len = strEn64.length();
		char enc_text[1024] = { 0 };

		if (RSA_private_decrypt(128, (unsigned char *)strEn64.c_str(), (unsigned char*)enc_text, rsa, RSA_PKCS1_PADDING) < 0)
		{
			char cerr[1024];
			ERR_error_string(1024, cerr);
			return "";
		}
		string sRet = enc_text;
		return sRet;
	}

	std::string CEncrypt::PubkeyDecryptRsa(string sKey, string sValue)
	{
		int nPublicKeyLen = sKey.size();
		for (int i = 64; i < nPublicKeyLen; i += 64)
		{
			if (sKey[i] != '\n')
			{
				sKey.insert(i, "\n");
			}
			i++;
		}
		sKey.insert(0, "-----BEGIN PUBLIC KEY-----\n");
		sKey.append("\n-----END PUBLIC KEY-----\n");

		BIO *bio = NULL;
		RSA *rsa = NULL;
		char *chKey = const_cast<char *>(sKey.c_str());
		if ((bio = BIO_new_mem_buf(chKey, -1)) == NULL)
		{
			return "";
		}
		rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
		if (!rsa)
		{
			ERR_load_crypto_strings();
			char errBuf[512];
			ERR_error_string_n(ERR_get_error(), errBuf, sizeof(errBuf));
			BIO_free_all(bio);
			return "";
		}

		string strEn64 = DecodeBase64((char*)sValue.c_str(), sValue.length());

		int rsa_len = strEn64.length();
		char enc_text[1024] = { 0 };

		if (RSA_public_decrypt(128, (unsigned char *)strEn64.c_str(), (unsigned char*)enc_text, rsa, RSA_PKCS1_PADDING) < 0)
		{
			char cerr[1024];
			ERR_error_string(1024, cerr);
			return "";
		}
		string sRet = enc_text;
		return sRet;
	}

	unsigned char CEncrypt::ToHex(unsigned char x)
	{
		return  x > 9 ? x + 55 : x + 48;
	}

	unsigned char CEncrypt::FromHex(unsigned char x)
	{
		unsigned char ch = x;
		if (x >= 'A' && x <= 'Z')
		{
			ch = x - 'A' + 10;
		}
		else if (x >= 'a' && x <= 'z')
		{
			ch = x - 'a' + 10;
		}
		else if (x >= '0' && x <= '9')
		{
			ch = x - '0';
		}
		return ch;
	}

	std::string CEncrypt::EncodeUrl(string str)
	{
		std::string strTemp = "";
		size_t length = str.length();
		for (size_t i = 0; i < length; i++)
		{
			//绝对不编码的，只有字母、数字、短横线(-)、下划线(_)、点(.)和波浪号(~)
			if (isalnum((unsigned char)str[i]) || (str[i] == '-') || (str[i] == '_') || (str[i] == '.') || (str[i] == '~'))
			{
				strTemp += str[i];
			}
			else if (str[i] == ' ')
			{
				strTemp += "+";
			}
			else
			{
				strTemp += '%';
				strTemp += ToHex((unsigned char)str[i] >> 4);
				strTemp += ToHex((unsigned char)str[i] % 16);
			}
		}
		return strTemp;
	}

	std::string CEncrypt::DecodeUrl(string str)
	{
		std::string strTemp = "";
		size_t length = str.length();
		for (size_t i = 0; i < length; i++)
		{
			if (str[i] == '+') strTemp += ' ';
			else if (str[i] == '%')
			{
				//assert(i + 2 < length);
				unsigned char high = FromHex((unsigned char)str[++i]);
				unsigned char low = FromHex((unsigned char)str[++i]);
				strTemp += high * 16 + low;
			}
			else strTemp += str[i];
		}
		return strTemp;
	}

	std::string CEncrypt::EncryptSha1(string str, string sKey)
	{
		unsigned char digest[20];
		hmac_sha1((unsigned char*)sKey.c_str(), sKey.length(), (unsigned char*)str.c_str(), str.length(), digest);

		string sRet = EncodeBase64(digest, 20);
		return sRet;
	}

	std::string CEncrypt::Md5String(string str)
	{
		unsigned char szOut[16] = { 0 };

		ctx_md5 md5;
		md5.update((unsigned char*)str.c_str(), str.length());
		md5.finish(szOut);

		string sMd5 = BytesToHexString(szOut, 16);
		return sMd5;
	}

	string CEncrypt::BytesToHexString(unsigned char * pbBytes, unsigned nSize)
	{
		char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		char * out = new char[nSize * 2 + 1];
		for (unsigned i = 0; i < nSize; i++)
		{
			out[i * 2] = hex[pbBytes[i] / 16];
			out[i * 2 + 1] = hex[pbBytes[i] % 16];
		}
		out[nSize * 2] = '\0';

		string s = out;
		delete[]out;
		return s;
	}

};//namespace