--- a/libidav/utils.c Sun Dec 03 13:09:14 2017 +0100 +++ b/libidav/utils.c Wed Dec 13 19:48:44 2017 +0100 @@ -466,41 +466,139 @@ return util_base64decode_len(in, &len); } +#define WHITESPACE 64 +#define EQUALS 65 +#define INVALID 66 +static char b64dectable[] = { + 66,66,66,66,66,66,66,66,66,66,64,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,62,66,66,66,63,52,53, + 54,55,56,57,58,59,60,61,66,66,66,65,66,66,66, 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,66,66,66,66,66,66,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,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66 +}; char* util_base64decode_len(char* in, int *outlen) { - size_t len = strlen(in); - char *out = calloc(1, len); + /* code is mostly from wikibooks */ + + size_t inlen = strlen(in); + size_t bufsize = (inlen*3) / 4; + char *outbuf = malloc(bufsize+1); + *outlen = -1; + + unsigned char *out = outbuf; + + char *end = in + inlen; + char iter = 0; + uint32_t buf = 0; + size_t len = 0; - BIO *b = BIO_new_mem_buf(in, len); - BIO *d = BIO_new(BIO_f_base64()); - BIO_set_flags(d, BIO_FLAGS_BASE64_NO_NL); - b = BIO_push(d, b); + while (in < end) { + unsigned char c = b64dectable[*in++]; + + switch (c) { + case WHITESPACE: continue; /* skip whitespace */ + case INVALID: { + /* invalid input */ + outbuf[0] = 0; + return outbuf; + } + case EQUALS: { + /* pad character, end of data */ + in = end; + continue; + } + default: { + buf = buf << 6 | c; + iter++; // increment the number of iteration + /* If the buffer is full, split it into bytes */ + if (iter == 4) { + if ((len += 3) > bufsize) { + /* buffer overflow */ + outbuf[0] = 0; + return outbuf; + } + *(out++) = (buf >> 16) & 255; + *(out++) = (buf >> 8) & 255; + *(out++) = buf & 255; + buf = 0; iter = 0; - *outlen = BIO_read(b, out, len); - BIO_free_all(b); - - return out; + } + } + } + } + + if (iter == 3) { + if ((len += 2) > bufsize) { + /* buffer overflow */ + outbuf[0] = 0; + return outbuf; + } + *(out++) = (buf >> 10) & 255; + *(out++) = (buf >> 2) & 255; + } + else if (iter == 2) { + if (++len > bufsize) { + /* buffer overflow */ + outbuf[0] = 0; + return outbuf; + } + *(out++) = (buf >> 4) & 255; + } + + *outlen = len; /* modify to reflect the actual output size */ + outbuf[len] = 0; + return outbuf; } -char* util_base64encode(char *in, size_t len) { - BIO *b; - BIO *e; - BUF_MEM *mem; - e = BIO_new(BIO_f_base64()); - b = BIO_new(BIO_s_mem()); - BIO_set_flags(e, BIO_FLAGS_BASE64_NO_NL); +static char* b64enctable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +char* util_base64encode(char *in, size_t len) { + // calculate length of base64 output and create buffer + size_t outlen = 4 * ((len + 2) / 3); + int pad = len % 3; + + char *out = malloc(outlen + 1); + out[outlen] = 0; + size_t pos = 0; - e = BIO_push(e, b); - BIO_write(e, in, len); - BIO_flush(e); + // encode blocks of 3 bytes + size_t i; + size_t blockend = len - pad; + for(i=0;i<blockend;i++) { + unsigned char b1 = in[i++]; + unsigned char b2 = in[i++]; + unsigned char b3 = in[i]; + uint32_t inb = b1 << 16 | (b2 << 8) | b3; + out[pos++] = b64enctable[(inb >> 18) & 63]; + out[pos++] = b64enctable[(inb >> 12) & 63]; + out[pos++] = b64enctable[(inb >> 6) & 63]; + out[pos++] = b64enctable[(inb) & 63]; + } - BIO_get_mem_ptr(e, &mem); - char *out = malloc(mem->length + 1); - memcpy(out, mem->data, mem->length); - out[mem->length] = '\0'; - - BIO_free_all(e); - + // encode last bytes + if(pad > 0) { + char p[3] = {0, 0, 0}; + for(int j=0;i<len;i++) { + p[j++] = in[i]; + } + unsigned char b1 = p[0]; + unsigned char b2 = p[1]; + unsigned char b3 = p[2]; + uint32_t inb = (b1 << 16) | (b2 << 8) | b3; + out[pos++] = b64enctable[(inb >> 18) & 63]; + out[pos++] = b64enctable[(inb >> 12) & 63]; + out[pos++] = b64enctable[(inb >> 6) & 63]; + out[pos++] = b64enctable[(inb) & 63]; + for(int k=outlen-1;k>=outlen-(3-pad);k--) { + out[k] = '='; + } + } + return out; }