X-Git-Url: https://git.toastfreeware.priv.at/debian/iodine.git/blobdiff_plain/cf812f1d2258d434d6c75362a1f9e66170f0aabf..81f2f4b5b93cecc84dcf6f3c80723baefc0a07aa:/src/base32.c diff --git a/src/base32.c b/src/base32.c index 5ee0664..d971ce2 100644 --- a/src/base32.c +++ b/src/base32.c @@ -1,5 +1,7 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * 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 @@ -24,12 +26,15 @@ #define BLKSIZE_RAW 5 #define BLKSIZE_ENC 8 -static const char cb32[] = +static const char cb32[] = "abcdefghijklmnopqrstuvwxyz012345"; -static unsigned char rev32[128]; +static const char cb32_ucase[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; +static unsigned char rev32[256]; +static int reverse_init = 0; -static int base32_decode(void *, size_t *, const char *, size_t); 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(); @@ -51,35 +56,37 @@ struct encoder return &base32_encoder; } -static int +static int base32_handles_dots() { return 0; } -static int +static int base32_blksize_raw() { return BLKSIZE_RAW; } -static int +static int base32_blksize_enc() { return BLKSIZE_ENC; } -static void +inline static void base32_reverse_init() { int i; unsigned char c; - static int reverse_init = 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; } reverse_init = 1; } @@ -98,125 +105,167 @@ b32_8to5(int in) return rev32[in]; } -static int +static int 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 + */ { - size_t newsize; - size_t maxsize; - unsigned char *p; - unsigned char *q; - int i; - - memset(buf, 0, *buflen); + 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 */ - /* how many chars can we encode within the buf */ - maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC); - /* how big will the encoded data be */ - newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW); - if (size % BLKSIZE_RAW) { - newsize += BLKSIZE_ENC; - } - /* if the buffer is too small, eat some of the data */ - if (*buflen < newsize) { - size = maxsize; - } - - p = (unsigned char *) buf; - q = (unsigned 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] & 0x7c) >> 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 += BLKSIZE_RAW; - p += BLKSIZE_ENC; - } - *p = 0; - - /* store number of bytes from data that was used */ - *buflen = size; - - return strlen(buf); -} + /* Note: Don't bother to optimize manually. GCC optimizes + better(!) when using simplistic array indexing. */ -#define DECODE_ERROR 0xffffffff -#define REV32(x) rev32[(int) (x)] + while (1) { + if (iout >= *buflen || iin >= size) + break; + buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)]; + iout++; -static int -decode_token(const unsigned char *t, unsigned char *data, size_t len) -{ - 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] = ((REV32(t[0]) & 0x1f) << 3) | - ((REV32(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] = ((REV32(t[1]) & 0x03) << 6) | - ((REV32(t[2]) & 0x1f) << 1) | - ((REV32(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] = ((REV32(t[3]) & 0x0f) << 4) | - ((REV32(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] = ((REV32(t[4]) & 0x01) << 7) | - ((REV32(t[5]) & 0x1f) << 2) | - ((REV32(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] = ((REV32(t[6]) & 0x07) << 5) | - ((REV32(t[7]) & 0x1f)); + /* store number of bytes from data that was used */ + *buflen = iin; - return 5; + return iout; } +#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; - size_t maxsize; - const char *p; - int len; + unsigned char *ubuf = (unsigned char *) buf; + int iout = 0; /* to-be-filled output byte */ + int iin = 0; /* next input char to use in decoding */ - base32_reverse_init(); - - /* chars needed to decode slen */ - newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1; - /* encoded chars that fit in buf */ - maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1; - /* if the buffer is too small, eat some of the data */ - if (*buflen < newsize) { - slen = maxsize; - } + base32_reverse_init (); + + /* Note: Don't bother to optimize manually. GCC optimizes + better(!) when using simplistic array indexing. */ - q = buf; - for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) { - len = decode_token((unsigned char *) p, (unsigned char *) q, slen); - q += len; - slen -= BLKSIZE_ENC; - - if (len < BLKSIZE_RAW) + 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++; + + 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; +}