A short while ago I needed to implement a little web safe base64 en/decoder and couldn't find any good small example in the width of the internet, so I decided to do my own dirty one. I hope I help somebody with this little demonstration code...
I used Pelles C Compiler to build this program, but I am optimistic that it works on every common C Compiler, since it's quite close to the C11 standard.
#include #include #include #include #define MAX_B64_PADDING 0x2 #define B64_PAD_CHAR "=" char * Base64Encode(char *input, unsigned int inputLen); char * Base64Decode(char *input, unsigned int inputLen); static unsigned char GetIndexByChar(unsigned char c); static char *b64alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; int main(int argc, char **argv) { if (argc != 2) { printf("Usage: %s StringToEncode\n", argv[0]); exit(EXIT_FAILURE); } printf("String \"%s\" to: " ,argv[1]); printf("%s\n", Base64Encode(argv[1], strlen(argv[1]))); exit(EXIT_SUCCESS); } /* Caller has to free the returned base64 encoded string ! */ char * Base64Encode(char *input, unsigned int inputLen) { char *encodedBuf; int fillBytes, i, k, base64StrLen; unsigned char a0, a1, a2, a3; /* Make sure there is no overflow. RAM is cheap :) */ base64StrLen = inputLen + (int)(inputLen * 0.45); encodedBuf = calloc(base64StrLen, sizeof(char)); if (encodedBuf == NULL) { printf("calloc() failed with error %d\n", errno); return NULL; } fillBytes = 3 - (inputLen % 3); /* Pad until dividable by 3 ! */ k = 0; /* Walk in 3 byte steps*/ for (i = 0; i < inputLen; i += 3) { a0 = (unsigned char)(((input[i+0] & 0xFC) >> 2)); a1 = (unsigned char)(((input[i+0] & 0x3) << 4) + ((input[i+1] & 0xF0) >> 4)); a2 = (unsigned char)(((input[i+1] & 0xF) << 2) + ((input[i+2] & 0xC0) >> 6)); a3 = (unsigned char)((input[i+2] & 0x3F)); encodedBuf[k+0] = b64alphabet[a0]; encodedBuf[k+1] = b64alphabet[a1]; encodedBuf[k+2] = b64alphabet[a2]; encodedBuf[k+3] = b64alphabet[a3]; /* Prevents buffer overflow */ if (i + (3 - fillBytes) == inputLen) { /* Check if we pad */ /* fill byte is either 0, 1 or 2 */ switch (fillBytes) { case 0: // do nothing break; case 1: // last encoded byte becomes pad value encodedBuf[k+3] = *B64_PAD_CHAR; break; case 2: // last two encoded bytes become pad value encodedBuf[k+2] = *B64_PAD_CHAR; encodedBuf[k+3] = *B64_PAD_CHAR; break; } } k += 4; } return encodedBuf; } /* Caller has to free the returned decoded ascii buffer */ char * Base64Decode(char *input, unsigned int inputLen) { char * decodedBuf; char a0, a1, a2, a3; int i, k, decodedLen; decodedLen = (int)(inputLen * 0.8); // 20 % less big than b64 encoded should be more than enough decodedBuf = calloc(decodedLen, sizeof(char)); if (decodedBuf == NULL) { printf("calloc() failed with error %d\n", errno); return NULL; } k = 0; for (i = 0; i < inputLen; i += 4) { if ((i + 4) <= inputLen) { a0 = GetIndexByChar(input[i+0]); a1 = GetIndexByChar(input[i+1]); a2 = GetIndexByChar(input[i+2]); a3 = GetIndexByChar(input[i+3]); decodedBuf[k+0] = (char)((a0 << 2) + ((a1 & 0x30) >> 4)); decodedBuf[k+1] = (char)(((a1 & 0xF) << 4) + ((a2 & 0x3C) >> 2)); decodedBuf[k+2] = (char)(((a2 & 0x3) << 6) + (a3)); /* Strip pad bytes. Ugly, but working solution... */ if (a0 == 100) { decodedBuf[k+0] = '\0'; break; } else if (a1 == 100) { decodedBuf[k+0] = '\0'; break; } else if (a2 == 100) { decodedBuf[k+1] = '\0'; break; } else if (a3 == 100) { decodedBuf[k+2] = '\0'; break; } k += 3; } } return decodedBuf; } static unsigned char GetIndexByChar(unsigned char c) { int i; for (i = 0; i < 64; i++) { if (b64alphabet[i] == c) return (unsigned char)i; } return 100; /* indicates an error */ }