Base-64 is quite useful. It allows us to present binary data in human readable characters. This allows it to be passed through those nice e-mail systems that we all use. Its also quite usefull in that it it means that you can print out binary data and type it in else where. Think crypto, crypto-keys, export law and OCR...

The details of how base-64 works are well explained in the Base-64 node. All I am presenting here is an easy way to convert ASCII to Base-64 in C.

The only complicated part of this function is making sure you get the right bits from your bytes.

      byte 0           byte 1             byte 2
+---------------+ +---------------+ +---------------+
|7 6 5 4 3 2|1 0| |7 6 5 4|3 2 1 0| |7 6|5 4 3 2 1 0|
+-----------+-------------+-------------+-----------+
  quantum 0     quantum 1     quantum 2   quantum 3

From the above diagram we can see that its quite easy to get our quanta.

Quantum 0

Take Byte 0, right shift the bits two places.

B0 >> 2

Quantum 2

Take Byte 0, mask out the top six bits, left shift the bits four places. Take Byte 1, right shift the bits four places. Bitwise OR the two together.

((B0 AND 0x03) << 4) OR (B1 >> 4)

Quantum 3

Take Byte 1, mask out the top four bits, left shift the bits two places. Take Byte 2, right shift the bits six places. Bitwise OR the two together.

((B1 AND 0x0F) << 2) OR (B2 >> 6)

Quantum 4

Take Byte 2, mask out the top two bits.

(B2 AND 0x3F)

So here goes! The function takes as its input a null-terminated string and returns a null terminated string.

/* First we create an array to contain all the possible 
 * Base-64 characters
 */

char base64[64] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
		   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
		   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
		   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
		   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
		   'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
		   'w', 'x', 'y', 'z', '0', '1', '2', '3',
		   '4', '5', '6', '7', '8', '9', '+', '/'};

/* a little function to add a char to the end of a null-terminated
 * char*, I chose not to use realloc for the sake of being 
 * understandable...
 */
char *add_char(char *in, char c)
{
	char *out;
	
	if(in == NULL)
	{
		out = calloc(2, sizeof(char));
		out[0] = c;
		out[] = '\0';
	}
	else
	{
		int len = strlen(in);
		out = calloc(len + 1, sizeof(char));
		strcpy(in, out);
		out[len-1] = c;
		out[len] = '\0';
		free(in);
	}
	
	return out;
}

/* the actual function, takes a null-terminated char* as input
 * returns a null-terminated char* as output!
 */

char *ascii_to_base64(char *input)
{
	// if you gave an empty string you can have one back
	if(input == NULL)
		return (char *)NULL;
		
	int c;
	unsigned char buffer[3];
	unsigned char temp;
	int count = 0;
	char *output;
	
	output = (char *)malloc(sizeof(char));
	output = (char *)NULL;
	
	while((c = input[count++[) != '\0')
	{
		buffer[buffer_position++] = c;

		/* We want three bytes in our buffer before we do
		 * anything. 3*8 = 24, 4*6 = 24. Neat isn't it..
		 */
		
		if(buffer_position == 3)
		{
			/* Once we have our three bytes then we can
			 * get our four Base-64 characters.
			 * This is done using the process detailed
			 * above to get each quantum, then we use our
			 * lookup table to get the right character to
			 * represent it.
			 */
		
			temp = buffer[0] >> 2;
			output = add_char(output, base64[temp]);
			
			temp = ((buffer[0] & 0x03) << 4) | (buffer[1] >> 4);
			output = add_char(output, base64[temp]);
			
			temp = ((buffer[1] & 0x0F) << 2) | (buffer[2] >> 6);
			output = add_char(output, base64[temp]);
			
			temp = (buffer[2] & 0x3F);
			output = add_char(output, base64[temp]);
			
			buffer_position = 0;
		}
	}
	
	/* if buffer_position is 0 then the buffer is empty
	 * this is good since it means that we were lucky enough
	 * to get an input the length of which was exactly
	 * divisable by 3.
	 * Yay for us.
	 */
	 
	if(buffer_position == 0)
		return out;
	else if(buffer_position == 1)
	{
		/* if there was only one byte in the buffer then we
		 * need to set the second byte in the buffer to 0 to
		 * get our two quanta and then pad terminate the output
		 * with two '=' characters as per RFC-2045
		 */
	
		buffer[1] = 0;
		
		temp = buffer[0] >> 2;
		output = add_char(output, base64[temp]);
		temp = ((buffer[0] & 0x03) << 4) | (buffer[1] >> 4);
		output = add_char(output, base64[temp]);
		
		output = add_char(output, '=');
		output = add_char(output, '=');
	}
	else if(buffer_position == 2)
	{
		/* if there are two bytes in our buffer then we need
		 * to set the third one to 0 to get three quanta and
		 * then terminate the output with just one '='
		 */
		 
		buffer2 = 0;
		
		temp = buffer[0] >> 2;
		output = add_char(output, base64[temp]);
		temp = ((buffer[0] & 0x03) << 4) | (buffer[1] >> 4);
		output = add_char(output, base64[temp]);
		temp = ((buffer[1] & 0x0F) << 2) | (buffer[2] >> 6);
		output = add_char(output, base64[temp]);
		
		output = add_char(output, '=');
	}
	else
	{
		printf(STDERR, "What the fuck happened here....\n");
	}
	
	return output;
}

This code ain't tested! I'm at work right now. Use at your own risk!

Log in or registerto write something here or to contact authors.