diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 0000000..52eb64a --- /dev/null +++ b/src/base64.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2006-2007 Bjorn Andersson , Erik Ekman + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "encoding.h" +#include "base64.h" + +static const char cb64[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789."; +static unsigned char rev64[128]; +static int reverse_init = 0; + +static struct encoder base64_encoder = +{ + "BASE64", + base64_encode, + base64_decode, + base64_handles_dots, + base64_handles_dots +}; + +struct encoder +*get_base64_encoder() +{ + return &base64_encoder; +} + +int +base64_handles_dots() +{ + return 1; +} + +int +base64_encode(char *buf, size_t *buflen, const void *data, size_t size) +{ + size_t newsize; + size_t maxsize; + unsigned char *s; + unsigned char *p; + unsigned char *q; + int i; + + memset(buf, 0, *buflen); + + /* how many chars can we encode within the buf */ + maxsize = 3 * (*buflen / 4 - 1) - 1; + /* how big will the encoded data be */ + newsize = 4 * (size / 3 + 1) + 1; + /* if the buffer is too small, eat some of the data */ + if (*buflen < newsize) { + size = maxsize; + } + + p = s = (unsigned char *) buf; + q = (unsigned char *)data; + + for(i=0;i> 2)]; + p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))]; + p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0'; + p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0'; + + q += 3; + p += 4; + } + *p = 0; + + /* store number of bytes from data that was used */ + *buflen = size; + + return strlen(buf) - 1; +} + +#define DECODE_ERROR 0xffffffff +#define REV64(x) rev64[(int) (x)] + +static int +decode_token(const unsigned char *t, unsigned char *data, size_t len) +{ + if (len < 2) + return 0; + + data[0] = ((REV64(t[0]) & 0x3f) << 2) | + ((REV64(t[1]) & 0x30) >> 4); + + if (len < 3) + return 1; + + data[1] = ((REV64(t[1]) & 0x0f) << 4) | + ((REV64(t[2]) & 0x3c) >> 2); + + if (len < 4) + return 2; + + data[2] = ((REV64(t[2]) & 0x03) << 6) | + (REV64(t[3]) & 0x3f); + + return 3; +} + +int +base64_decode(void *buf, size_t *buflen, const char *str, size_t slen) +{ + unsigned char *q; + size_t newsize; + size_t maxsize; + const char *p; + unsigned char c; + int len; + int i; + + if (!reverse_init) { + for (i = 0; i < 64; i++) { + c = cb64[i]; + rev64[(int) c] = i; + } + reverse_init = 1; + } + + /* chars needed to decode slen */ + newsize = 3 * (slen / 4 + 1) + 1; + /* encoded chars that fit in buf */ + maxsize = 4 * (*buflen / 3 + 1) + 1; + /* if the buffer is too small, eat some of the data */ + if (*buflen < newsize) { + slen = maxsize; + } + + q = buf; + for (p = str; *p && strchr(cb64, *p); p += 4) { + len = decode_token((unsigned char *) p, (unsigned char *) q, slen); + q += len; + slen -= 4; + + if (len < 3) + break; + } + *q = '\0'; + + return q - (unsigned char *) buf; +} + diff --git a/src/base64.h b/src/base64.h new file mode 100644 index 0000000..6ee0656 --- /dev/null +++ b/src/base64.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2006-2007 Bjorn Andersson , Erik Ekman + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __BASE64_H__ +#define __BASE64_H__ + +struct encoder *get_base64_encoder(void); +int base64_handles_dots(); +int base64_encode(char *, size_t *, const void *, size_t); +int base64_decode(void *, size_t *, const char *, size_t); + +#endif diff --git a/tests/base64.c b/tests/base64.c new file mode 100644 index 0000000..52406dd --- /dev/null +++ b/tests/base64.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2006 Bjorn Andersson , Erik Ekman + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "encoding.h" +#include "base64.h" +#include "test.h" + +static struct tuple +{ + char *a; + char *b; +} testpairs[] = { + { "iodinetestingtesting", "Aw8KAw4LDgvZDgLUz2rLC2rPBMC" }, + { "abc123", "ywjJmtiZ" }, + { NULL, NULL } +}; + +START_TEST(test_base64_encode) +{ + size_t len; + char buf[4096]; + int val; + int i; + + for (i = 0; testpairs[i].a != NULL; i++) { + len = sizeof(buf); + val = base64_encode(buf, &len, testpairs[i].a, strlen(testpairs[i].a)); + + fail_unless(val > 0, strerror(errno)); + fail_unless(strcmp(buf, testpairs[i].b) == 0, + va_str("'%s' != '%s'", buf, testpairs[i].b)); + } +} +END_TEST + +START_TEST(test_base64_decode) +{ + size_t len; + char buf[4096]; + int val; + int i; + + for (i = 0; testpairs[i].a != NULL; i++) { + len = sizeof(buf); + val = base64_decode(buf, &len, testpairs[i].b, strlen(testpairs[i].b)); + + fail_unless(val > 0, strerror(errno)); + fail_unless(buf != NULL, "buf == NULL"); + fail_unless(strcmp(buf, testpairs[i].a) == 0, + va_str("'%s' != '%s'", buf, testpairs[i].a)); + } +} +END_TEST + +TCase * +test_base64_create_tests() +{ + TCase *tc; + + tc = tcase_create("Base64"); + tcase_add_test(tc, test_base64_encode); + tcase_add_test(tc, test_base64_decode); + + return tc; +}