Last active
November 11, 2022 04:22
-
-
Save KokoseiJ/acc1a7649e7b5e50f6b2237602f8e45d to your computer and use it in GitHub Desktop.
Simple (and portable) Base64 implementation in C
This file contains 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
#include <stdio.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <time.h> | |
int countchr(char *str, char chr) { | |
int i; | |
for (i=0; *str != '\0'; *str++ == chr ? i++ : 0); | |
return i; | |
} | |
size_t b64enclen(size_t datalen) { | |
if (datalen % 3 == 0) return datalen / 3 * 4; | |
else return (datalen + 3 - datalen % 3) / 3 * 4; | |
} | |
size_t b64declen(char *data) { | |
size_t datalen; | |
datalen = strlen(data); | |
assert(datalen % 4 == 0); | |
return datalen / 4 * 3 - countchr(data, '='); | |
} | |
int b64encode(void *in, size_t inlen, char *out, size_t outlen) { | |
char B64CHR[] = | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | |
char PAD = '='; | |
uint8_t num3[3], num4[4], padnum, j; | |
uint32_t tempnum; | |
size_t i, outptr = 0; | |
if (outlen < b64enclen(inlen)) return 1; | |
for (i=0; i<inlen; i+=3) { | |
num3[0] = ((uint8_t *)in)[i]; | |
if (inlen - i > 1) | |
num3[1] = ((uint8_t *)in)[i+1]; | |
else | |
num3[1] = 0; | |
if (inlen - i > 2) | |
num3[2] = ((uint8_t *)in)[i+2]; | |
else | |
num3[2] = 0; | |
tempnum = num3[0] << 16; | |
tempnum += num3[1] << 8; | |
tempnum += num3[2]; | |
num4[0] = (tempnum >> 18) & 63; | |
num4[1] = (tempnum >> 12) & 63; | |
num4[2] = (tempnum >> 6) & 63; | |
num4[3] = tempnum & 63; | |
for (j=0; j<4; j++) { | |
out[outptr++] = B64CHR[num4[j]]; | |
} | |
} | |
if (inlen % 3 == 0) padnum = 0; | |
else padnum = 3 - inlen % 3; | |
for (i=0; i<padnum; i++) { | |
out[--outptr] = PAD; | |
} | |
return 0; | |
} | |
int b64decode(char *in, size_t inlen, void *out, size_t outlen) { | |
uint8_t B64TABLE[] = { | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, | |
0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, | |
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, | |
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
}; | |
uint8_t num3[3], num4[4], j; | |
uint32_t tempnum; | |
size_t i, outptr = 0; | |
i = b64declen(in); | |
if (outlen < i) return 1; | |
outlen = i; | |
for (i=0; i<inlen; i += 4) { | |
num4[0] = B64TABLE[(uint8_t)(in[i])]; | |
num4[1] = B64TABLE[(uint8_t)(in[i+1])]; | |
num4[2] = B64TABLE[(uint8_t)(in[i+2])]; | |
num4[3] = B64TABLE[(uint8_t)(in[i+3])]; | |
tempnum = (num4[0] & 63) << 18; | |
tempnum += (num4[1] & 63) << 12; | |
tempnum += (num4[2] & 63) << 6; | |
tempnum += (num4[3] & 63); | |
num3[0] = (tempnum >> 16) & 255; | |
num3[1] = (tempnum >> 8) & 255; | |
num3[2] = tempnum & 255; | |
for (j=0; j<3 && outptr < outlen; j++) { | |
((uint8_t *)out)[outptr++] = num3[j]; | |
} | |
if (outptr >= outlen) break; | |
} | |
return 0; | |
} | |
void fillrandom(void *buf, size_t bufsize) { | |
size_t i; | |
for (i=0; i<bufsize; i++) | |
((uint8_t *)buf)[i] = rand() % 255; | |
return; | |
} | |
int main() { | |
char teststr[] = "Aah! Natsu Wo Ima Mou Ikkai!", *in, *out; | |
size_t inlen, outlen; | |
inlen = sizeof(teststr) / sizeof(char); | |
outlen = b64enclen(inlen); | |
out = calloc(outlen + 1, sizeof(char)); | |
b64encode(teststr, inlen, out, outlen); | |
printf("[*] %lu %lu %s %s\n", inlen, outlen, teststr, out); | |
in = out; | |
inlen = outlen; | |
outlen = b64declen(in); | |
out = calloc(inlen + 1, sizeof(char)); | |
b64decode(in, inlen, out, outlen); | |
printf("[*] %lu %lu %s %s\n", inlen, outlen, in, out); | |
free(in); | |
free(out); | |
int i; | |
size_t origlen; | |
void *origbuf; | |
srand(time(NULL)); | |
for (i=0; 1; i++) { | |
origlen = 1000 + rand() % 4000; | |
origbuf = malloc(origlen); | |
fillrandom(origbuf, origlen); | |
outlen = b64enclen(origlen); | |
out = calloc(outlen + 1, sizeof(char)); | |
b64encode(origbuf, origlen, out, outlen); | |
in = out; | |
inlen = outlen; | |
outlen = b64declen(in); | |
out = malloc(outlen); | |
b64decode(in, inlen, out, outlen); | |
//printf("[*] %lu %lu %lu %d\n", origlen, inlen, outlen, memcmp(origbuf, out, origlen)); | |
assert(origlen == outlen); | |
assert(memcmp(origbuf, out, origlen) == 0); | |
printf("%d passed\r", i); | |
free(origbuf); | |
free(in); | |
free(out); | |
} | |
return 0; | |
} |
This file contains 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
------------------------------------------------- | |
| h | e | l | | |
|0 1 1 0 1 0 0 0|0 1 1 0 0 1 0 1|0 1 1 0 1 1 0 0| | |
|0 1 1 0 1 0|0 0 0 1 1 0|0 1 0 1 0 1|1 0 1 1 0 0| | |
| a | G | V | s | | |
------------------------------------------------- | |
------------------------------------------------------------------------------------------------- | |
| h | e | l | l | # | # | | |
|0 1 1 0 1 0 0 0|0 1 1 0 0 1 0 1|0 1 1 0 1 1 0 0|0 1 1 0 1 1 0 0|# # # # # # # #|# # # # # # # #| | |
|0 1 1 0 1 0|0 0 0 1 1 0|0 1 0 1 0 1|1 0 1 1 0 0|0 1 1 0 1 1|0 0 0 0 0 0|# # # # # #|# # # # # #| | |
| a | G | V | s | b | G | = | = | | |
------------------------------------------------------------------------------------------------- | |
------------------------------------------------------------------------------------------------- | |
| h | e | l | l | o | # | | |
|0 1 1 0 1 0 0 0|0 1 1 0 0 1 0 1|0 1 1 0 1 1 0 0|0 1 1 0 1 1 0 0|0 1 1 0 1 1 1 1|# # # # # # # #| | |
|0 1 1 0 1 0|0 0 0 1 1 0|0 1 0 1 0 1|1 0 1 1 0 0|0 1 1 0 1 1|0 0 0 1 1 0|1 1 1 1 0 0|# # # # # #| | |
| a | G | V | s | b | G | 8 | = | | |
------------------------------------------------------------------------------------------------- | |
------------------------------------------------------------------------------------------------- | |
| h | e | l | l | o | w | | |
|0 1 1 0 1 0 0 0|0 1 1 0 0 1 0 1|0 1 1 0 1 1 0 0|0 1 1 0 1 1 0 0|0 1 1 0 1 1 1 1|0 1 1 1 0 1 1 1| | |
|0 1 1 0 1 0|0 0 0 1 1 0|0 1 0 1 0 1|1 0 1 1 0 0|0 1 1 0 1 1|0 0 0 1 1 0|1 1 1 1 0 1|1 1 0 1 1 1| | |
| a | G | V | s | b | G | 9 | 3 | | |
------------------------------------------------------------------------------------------------- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment