X-Git-Url: https://git.toastfreeware.priv.at/debian/iodine.git/blobdiff_plain/fd46ed085eb846701d0f8511de424e8f41cba64b..9f5e4e5c1cf6959b8c243fd1f10597786b6bc81e:/src/base32.c diff --git a/src/base32.c b/src/base32.c index 7357604..d971ce2 100644 --- a/src/base32.c +++ b/src/base32.c @@ -1,5 +1,7 @@ /* - * Copyright (c) 2006-2007 Bjorn Andersson + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson + * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,140 +20,252 @@ #include #include +#include "encoding.h" #include "base32.h" -static const char cb32[] = - "abcdefghijklmnopqrstuvwxyz0123456789"; +#define BLKSIZE_RAW 5 +#define BLKSIZE_ENC 8 -int -base32_encode(char **buf, size_t *buflen, const void *data, size_t size) +static const char cb32[] = + "abcdefghijklmnopqrstuvwxyz012345"; +static const char cb32_ucase[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; +static unsigned char rev32[256]; +static int reverse_init = 0; + +static int base32_encode(char *, size_t *, const void *, size_t); +static int base32_decode(void *, size_t *, const char *, size_t); +static int base32_handles_dots(); +static int base32_blksize_raw(); +static int base32_blksize_enc(); + +static struct encoder base32_encoder = +{ + "Base32", + base32_encode, + base32_decode, + base32_handles_dots, + base32_handles_dots, + base32_blksize_raw, + base32_blksize_enc +}; + +struct encoder +*get_base32_encoder() +{ + return &base32_encoder; +} + +static int +base32_handles_dots() +{ + return 0; +} + +static int +base32_blksize_raw() +{ + return BLKSIZE_RAW; +} + +static int +base32_blksize_enc() +{ + return BLKSIZE_ENC; +} + +inline static void +base32_reverse_init() { - size_t newsize; - char *newbuf; - char *s; - char *p; - char *q; int i; + unsigned char c; - newsize = 8 * (size / 5 + 1) + 1; - if (newsize > *buflen) { - if ((newbuf = realloc(*buf, newsize)) == NULL) { - free(*buf); - *buf = NULL; - *buflen = 0; - return 0; + if (!reverse_init) { + memset (rev32, 0, 256); + for (i = 0; i < 32; i++) { + c = cb32[i]; + rev32[(int) c] = i; + c = cb32_ucase[i]; + rev32[(int) c] = i; } - - *buf = newbuf; - *buflen = newsize; + reverse_init = 1; } - - p = s = *buf; - q = (char*)data; - - for(i=0;i> 3)]; - p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)]; - p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0'; - p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0'; - p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0'; - p[5] = (i+3 < size) ? cb32[((q[3] & 0x3e) >> 2)] : '\0'; - p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\0'; - p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0'; - - q += 5; - p += 8; - } - *p = 0; - return strlen(s); } -#define DECODE_ERROR 0xffffffff +int +b32_5to8(int in) +{ + return cb32[in & 31]; +} -static int -pos(char c) +int +b32_8to5(int in) { - const char *p; - for (p = cb32; *p; p++) - if (*p == c) - return p - cb32; - return -1; + base32_reverse_init(); + return rev32[in]; } static int -decode_token(const char *t, char *data) +base32_encode(char *buf, size_t *buflen, const void *data, size_t size) +/* + * Fills *buf with max. *buflen characters, encoding size bytes of *data. + * + * NOTE: *buf space should be at least 1 byte _more_ than *buflen + * to hold the trailing '\0'. + * + * return value : #bytes filled in buf (excluding \0) + * sets *buflen to : #bytes encoded from data + */ { - int len; + unsigned char *udata = (unsigned char *) data; + int iout = 0; /* to-be-filled output char */ + int iin = 0; /* one more than last input byte that can be + successfully decoded */ - len = strlen(t); + /* Note: Don't bother to optimize manually. GCC optimizes + better(!) when using simplistic array indexing. */ + + while (1) { + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)]; + iout++; - if (len < 2) - return 0; + if (iout >= *buflen || iin >= size) { + iout--; /* previous char is useless */ + break; + } + buf[iout] = cb32[((udata[iin] & 0x07) << 2) | + ((iin + 1 < size) ? + ((udata[iin + 1] & 0xc0) >> 6) : 0)]; + iin++; /* 0 complete, iin=1 */ + iout++; - data[0] = ((pos(t[0]) & 0x1f) << 3) | - ((pos(t[1]) & 0x1c) >> 2); - - if (len < 4) - return 1; + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)]; + iout++; - data[1] = ((pos(t[1]) & 0x03) << 6) | - ((pos(t[2]) & 0x1f) << 1) | - ((pos(t[3]) & 0x10) >> 4); + if (iout >= *buflen || iin >= size) { + iout--; /* previous char is useless */ + break; + } + buf[iout] = cb32[((udata[iin] & 0x01) << 4) | + ((iin + 1 < size) ? + ((udata[iin + 1] & 0xf0) >> 4) : 0)]; + iin++; /* 1 complete, iin=2 */ + iout++; - if (len < 5) - return 2; + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb32[((udata[iin] & 0x0f) << 1) | + ((iin + 1 < size) ? + ((udata[iin + 1] & 0x80) >> 7) : 0)]; + iin++; /* 2 complete, iin=3 */ + iout++; - data[2] = ((pos(t[3]) & 0x0f) << 4) | - ((pos(t[4]) & 0x1e) >> 1); + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)]; + iout++; - if (len < 7) - return 3; + if (iout >= *buflen || iin >= size) { + iout--; /* previous char is useless */ + break; + } + buf[iout] = cb32[((udata[iin] & 0x03) << 3) | + ((iin + 1 < size) ? + ((udata[iin + 1] & 0xe0) >> 5) : 0)]; + iin++; /* 3 complete, iin=4 */ + iout++; - data[3] = ((pos(t[4]) & 0x01) << 7) | - ((pos(t[5]) & 0x1f) << 2) | - ((pos(t[6]) & 0x18) >> 3); + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb32[((udata[iin] & 0x1f))]; + iin++; /* 4 complete, iin=5 */ + iout++; + } - if (len < 8) - return 4; + buf[iout] = '\0'; - data[4] = ((pos(t[6]) & 0x07) << 5) | - ((pos(t[7]) & 0x1f)); + /* store number of bytes from data that was used */ + *buflen = iin; - return 5; + return iout; } -int -base32_decode(void **buf, size_t *buflen, const char *str) +#define REV32(x) rev32[(int) (x)] + +static int +base32_decode(void *buf, size_t *buflen, const char *str, size_t slen) +/* + * Fills *buf with max. *buflen bytes, decoded from slen chars in *str. + * Decoding stops early when *str contains \0. + * Illegal encoded chars are assumed to decode to zero. + * + * NOTE: *buf space should be at least 1 byte _more_ than *buflen + * to hold a trailing '\0' that is added (though *buf will usually + * contain full-binary data). + * + * return value : #bytes filled in buf (excluding \0) + */ { - unsigned char *q; - size_t newsize; - const char *p; - char *newbuf; - int len; - - newsize = 5 * (strlen(str) / 8 + 1) + 1; - if (newsize > *buflen) { - if ((newbuf = realloc(*buf, newsize)) == NULL) { - free(*buf); - *buf = NULL; - *buflen = 0; - return 0; - } + unsigned char *ubuf = (unsigned char *) buf; + int iout = 0; /* to-be-filled output byte */ + int iin = 0; /* next input char to use in decoding */ - *buf = newbuf; - *buflen = newsize; - } + base32_reverse_init (); + + /* Note: Don't bother to optimize manually. GCC optimizes + better(!) when using simplistic array indexing. */ + + while (1) { + if (iout >= *buflen || iin + 1 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0') + break; + ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) | + ((REV32(str[iin + 1]) & 0x1c) >> 2); + iin++; /* 0 used up, iin=1 */ + iout++; + + if (iout >= *buflen || iin + 2 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0' || + str[iin + 2] == '\0') + break; + ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) | + ((REV32(str[iin + 1]) & 0x1f) << 1) | + ((REV32(str[iin + 2]) & 0x10) >> 4); + iin += 2; /* 1,2 used up, iin=3 */ + iout++; + + if (iout >= *buflen || iin + 1 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0') + break; + ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) | + ((REV32(str[iin + 1]) & 0x1e) >> 1); + iin++; /* 3 used up, iin=4 */ + iout++; + + if (iout >= *buflen || iin + 2 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0' || + str[iin + 2] == '\0') + break; + ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) | + ((REV32(str[iin + 1]) & 0x1f) << 2) | + ((REV32(str[iin + 2]) & 0x18) >> 3); + iin += 2; /* 4,5 used up, iin=6 */ + iout++; - q = *buf; - for (p = str; *p && strchr(cb32, *p); p += 8) { - len = decode_token(p, (char *) q); - q += len; - - if (len < 5) + if (iout >= *buflen || iin + 1 >= slen || + str[iin] == '\0' || str[iin + 1] == '\0') break; + ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) | + ((REV32(str[iin + 1]) & 0x1f)); + iin += 2; /* 6,7 used up, iin=8 */ + iout++; } - *q = '\0'; - - return q - (unsigned char *) *buf; -} + ubuf[iout] = '\0'; + + return iout; +}