Skip to content

Instantly share code, notes, and snippets.

@Voldrix
Last active January 29, 2024 03:49
Show Gist options
  • Save Voldrix/9e6b67ef00b4fd937a68cb4499d16d89 to your computer and use it in GitHub Desktop.
Save Voldrix/9e6b67ef00b4fd937a68cb4499d16d89 to your computer and use it in GitHub Desktop.
Simple Base64 Encoder / Decoder in C
static const unsigned char digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//if you trust your input only has valid characters (defined above), you can cut this in half (123 instead of 256)
//probably not recommended, just in case, as invalid characters could cause a seg fault
unsigned char digitsDecode[256] = {0};
for(int i = 0; i < 64; i++)
digitsDecode[digits[i]] = i;
int base64_encode(register unsigned char *buff, unsigned char* str, int len) {
//assumes buffer is long enough (for simplicity)
register int r, len3 = len / 3;
int lenRemainder = len % 3;
len = 0; //reuse for return string length
/* base64 encodes data as 6-bit bytes instead of 8.
The lowest common multiple of 6 and 8 is 24 bits (3 8-bit bytes, or 4 6-bit bytes).
So 3 unencoded bytes will yield exactly 4 encoded bytes.
*/
while(len3--) {
r = *str++ << 16;
r |= *str++ << 8;
r |= *str++;
*buff++ = digits[r >> 18];
*buff++ = digits[r >> 12 & 63];
*buff++ = digits[r >> 6 & 63];
*buff++ = digits[r & 63];
len += 4;
}
if(lenRemainder == 1) {
r = *str;
*buff++ = digits[r >> 2];
*buff++ = digits[r << 4 & 63];
*buff++ = '='; //special remainder padding character
*buff++ = '=';
len += 4;
}
if(lenRemainder == 2) {
r = *str++ << 8;
r |= *str;
*buff++ = digits[r >> 10];
*buff++ = digits[r >> 4 & 63];
*buff++ = digits[r << 2 & 63];
*buff++ = '=';
len += 4;
}
*buff = 0; //null terminate string
return len;
}
int base64_decode(register unsigned char *buff, unsigned char* str) {
register int len = 0;
while(str[len] != 0 && str[len] != '=')
len += 1;
register int len4 = len >> 2;
int lenRemainder = len & 3;
len = 0; //reuse for return string length
/* base64 encodes data as 6-bit bytes instead of 8.
The lowest common multiple of 6 and 8 is 24 bits (4 6-bit bytes, or 3 8-bit bytes).
So 4 encoded bytes will yield exactly 3 decoded bytes.
*/
while(len4--) {
*buff = digitsDecode[*str++] << 2; //str bits 2-7 => buff bits 0-5
*buff++ |= digitsDecode[*str] >> 4;//str bits 2-3 => buff bits 6-7
*buff = digitsDecode[*str++] << 4; //str bits 4-7 => buff bits 0-3
*buff++ |= digitsDecode[*str] >> 2;//str bits 2-5 => buff bits 4-7
*buff = digitsDecode[*str++] << 6; //str bits 6-7 => buff bits 0-1
*buff++ |= digitsDecode[*str++];//str bits 2-7 => buff bits 2-7
len += 3;
}
if(lenRemainder) {
*buff = digitsDecode[*str++] << 2; //str bits 2-7 => buff bits 0-5
}
if(lenRemainder > 1) {
*buff++ |= digitsDecode[*str] >> 4;//str bits 2-3 => buff bits 6-7
*buff = digitsDecode[*str++] << 4; //str bits 4-7 => buff bits 0-3
}
if(lenRemainder == 3) {
*buff++ |= digitsDecode[*str] >> 2;//str bits 2-5 => buff bits 4-7
*buff = digitsDecode[*str++] << 6; //str bits 6-7 => buff bits 0-1
}
*++buff = 0; //null terminate string
return len + lenRemainder;
}
/*
Even though base64 encoded strings only use 6 bits for each character,
they are still stored in 8-bit bytes in order for the ASCII text encoding to work.
This inefficiency is to avoid the unprintable special characters.
Otherwise we could just print the full 8-bit byte values and this encoding wouldn't be needed at all.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment