#include "pch.h"



/**
	Takes data, allocate a buffer in heap of size 4/3 + 2 to handle the result,
	base64 encode it and returns a pointer to result buffer.


	@param		const unsigned char* data				The data to be encoded.
	@param		unsigned short		 input_length		Length of unencoded data (length of previous arg)
	@param		unsigned short		 input_length		An address to handle the length of b64 encoded result data.
														Will be 4/3 + 2 of input_length

	@return		char*									A pointer to the heap buffer containing the b64 encoded result
 */
char* base64_encode(const unsigned char* data,
	unsigned short input_length,
	unsigned short* output_length)
{
	char* encoded_data = NULL;
	DWORD local_output_len = 0;

	if (!CryptBinaryToStringA
	(
		data,
		input_length,
		CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
		NULL,
		&local_output_len
	))
	{
		return NULL;
	}

	encoded_data = (char*)calloc(local_output_len, sizeof(char));
	if (!encoded_data)
	{
		return NULL;
	}

	if (!CryptBinaryToStringA
	(
		data,
		input_length,
		CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
		encoded_data,
		&local_output_len
	))
	{
		return NULL;
	}

	if (local_output_len <= 65535)
	{
		*output_length = (unsigned short)local_output_len;
	}
	else
		return NULL;

	return encoded_data;
}



/**
	Builds a decoding table in heap. Then takes base 64 encoded data data,
	allocate a buffer in heap of size 3/4 of input length to handle the result,
	base64 decode it and returns a pointer to the result buffer. Then, free the
	base64 decoding table.


	@param		const unsigned char* data				The data to be decoded.
	@param		unsigned short		 input_length		Length of encoded data (length of previous arg)
	@param		unsigned short		 input_length		An address to handle the length of b64 encoded result data.
														Will be 3/4 of input_length

	@return		char*									A pointer to the heap buffer containing the decoded result
 */
unsigned char* base64_decode(const char* data,
	unsigned short input_length,
	unsigned short* output_length)
{
	unsigned char* decoded_data = NULL;
	DWORD local_output_len = 0;

	if (!CryptStringToBinaryA
	(
		data,
		0,
		CRYPT_STRING_BASE64,
		NULL,
		&local_output_len,
		NULL,
		NULL
	))
	{
		return NULL;
	}

	decoded_data = (unsigned char*)calloc(local_output_len, sizeof(char));
	if (!decoded_data)
	{
		return NULL;
	}

	if (!CryptStringToBinaryA
	(
		data,
		0,
		CRYPT_STRING_BASE64,
		decoded_data,
		&local_output_len,
		NULL,
		NULL
	))
	{
		return NULL;
	}

	if (local_output_len <= 65535)
	{
		*output_length = (unsigned short)local_output_len;
	}
	else
		return NULL;

	return decoded_data;
}
