Last active
January 29, 2024 03:49
-
-
Save Voldrix/9e6b67ef00b4fd937a68cb4499d16d89 to your computer and use it in GitHub Desktop.
Simple Base64 Encoder / Decoder in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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