aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2016-06-17 13:53:57 -0400
committerNick Mathewson <nickm@torproject.org>2016-06-17 13:53:57 -0400
commit48b25e6811bb822542ea898e30aebc75e185f29d (patch)
tree4dfd97599024d2df35f4f56471a40bf6e518c3d7 /src
parent94762e37b950f3ce1696c78dd4f7a89b6d05f1ac (diff)
parentf4f9a9be40877cbd3d4311ba696a07d316760095 (diff)
downloadtor-48b25e6811bb822542ea898e30aebc75e185f29d.tar.gz
tor-48b25e6811bb822542ea898e30aebc75e185f29d.zip
Merge branch 'bug18280_029_03_nm_squashed'
Diffstat (limited to 'src')
-rw-r--r--src/common/util_format.c36
-rw-r--r--src/common/util_format.h1
-rw-r--r--src/test/test_util_format.c94
3 files changed, 119 insertions, 12 deletions
diff --git a/src/common/util_format.c b/src/common/util_format.c
index 2dea187e40..f343a9d921 100644
--- a/src/common/util_format.c
+++ b/src/common/util_format.c
@@ -21,33 +21,46 @@
#include <string.h>
#include <stdlib.h>
-/** Implements base32 encoding as in RFC 4648. Limitation: Requires
- * that srclen*8 is a multiple of 5.
- */
+
+/* Return the base32 encoded size in bytes using the source length srclen.
+ * The NUL terminated byte is added as well since every base32 encoding
+ * requires enough space for it. */
+size_t
+base32_encoded_size(size_t srclen)
+{
+ size_t enclen;
+ enclen = CEIL_DIV(srclen*8, 5) + 1;
+ tor_assert(enclen < INT_MAX && enclen > srclen);
+ return enclen;
+}
+
+/** Implements base32 encoding as in RFC 4648. */
void
base32_encode(char *dest, size_t destlen, const char *src, size_t srclen)
{
unsigned int i, v, u;
- size_t nbits = srclen * 8, bit;
+ size_t nbits = srclen * 8;
+ size_t bit;
tor_assert(srclen < SIZE_T_CEILING/8);
- tor_assert((nbits%5) == 0); /* We need an even multiple of 5 bits. */
- tor_assert((nbits/5)+1 <= destlen); /* We need enough space. */
+ /* We need enough space for the encoded data and the extra NUL byte. */
+ tor_assert(base32_encoded_size(srclen) <= destlen);
tor_assert(destlen < SIZE_T_CEILING);
for (i=0,bit=0; bit < nbits; ++i, bit+=5) {
/* set v to the 16-bit value starting at src[bits/8], 0-padded. */
v = ((uint8_t)src[bit/8]) << 8;
- if (bit+5<nbits) v += (uint8_t)src[(bit/8)+1];
- /* set u to the 5-bit value at the bit'th bit of src. */
+ if (bit+5<nbits)
+ v += (uint8_t)src[(bit/8)+1];
+ /* set u to the 5-bit value at the bit'th bit of buf. */
u = (v >> (11-(bit%8))) & 0x1F;
dest[i] = BASE32_CHARS[u];
}
dest[i] = '\0';
}
-/** Implements base32 decoding as in RFC 4648. Limitation: Requires
- * that srclen*5 is a multiple of 8. Returns 0 if successful, -1 otherwise.
+/** Implements base32 decoding as in RFC 4648.
+ * Returns 0 if successful, -1 otherwise.
*/
int
base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
@@ -57,10 +70,9 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
unsigned int i;
size_t nbits, j, bit;
char *tmp;
- nbits = srclen * 5;
+ nbits = ((srclen * 5) / 8) * 8;
tor_assert(srclen < SIZE_T_CEILING / 5);
- tor_assert((nbits%8) == 0); /* We need an even multiple of 8 bits. */
tor_assert((nbits/8) <= destlen); /* We need enough space. */
tor_assert(destlen < SIZE_T_CEILING);
diff --git a/src/common/util_format.h b/src/common/util_format.h
index a748a4f3cf..20ac711d10 100644
--- a/src/common/util_format.h
+++ b/src/common/util_format.h
@@ -24,6 +24,7 @@ int base64_decode_nopad(uint8_t *dest, size_t destlen,
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen);
+size_t base32_encoded_size(size_t srclen);
int hex_decode_digit(char c);
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c
index a25054cd0a..c27b3a50eb 100644
--- a/src/test/test_util_format.c
+++ b/src/test/test_util_format.c
@@ -289,6 +289,96 @@ test_util_format_base16_decode(void *ignored)
tor_free(real_dst);
}
+static void
+test_util_format_base32_encode(void *arg)
+{
+ (void) arg;
+ size_t real_dstlen = 32;
+ char *dst = tor_malloc_zero(real_dstlen);
+
+ /* Basic use case that doesn't require a source length correction. */
+ {
+ /* Length of 10 bytes. */
+ const char *src = "blahbleh12";
+ size_t srclen = strlen(src);
+ /* Expected result encoded base32. This was created using python as
+ * such (and same goes for all test case.):
+ *
+ * b = bytes("blahbleh12", 'utf-8')
+ * base64.b32encode(b)
+ * (result in lower case)
+ */
+ const char *expected = "mjwgc2dcnrswqmjs";
+
+ base32_encode(dst, base32_encoded_size(srclen), src, srclen);
+ tt_mem_op(expected, OP_EQ, dst, strlen(expected));
+ /* Encode but to a larger size destination. */
+ memset(dst, 0, real_dstlen);
+ base32_encode(dst, real_dstlen, src, srclen);
+ tt_mem_op(expected, OP_EQ, dst, strlen(expected));
+ }
+
+
+ /* Non multiple of 5 for the source buffer length. */
+ {
+ /* Length of 8 bytes. */
+ const char *expected = "mjwgc2dcnrswq";
+ const char *src = "blahbleh";
+ size_t srclen = strlen(src);
+
+ memset(dst, 0, real_dstlen);
+ base32_encode(dst, base32_encoded_size(srclen), src, srclen);
+ tt_mem_op(expected, OP_EQ, dst, strlen(expected));
+ }
+
+ done:
+ tor_free(dst);
+}
+
+static void
+test_util_format_base32_decode(void *arg)
+{
+ (void) arg;
+ int ret;
+ size_t real_dstlen = 32;
+ char *dst = tor_malloc_zero(real_dstlen);
+
+ /* Basic use case. */
+ {
+ /* Length of 10 bytes. */
+ const char *expected = "blahbleh12";
+ /* Expected result encoded base32. */
+ const char *src = "mjwgc2dcnrswqmjs";
+
+ ret = base32_decode(dst, strlen(expected), src, strlen(src));
+ tt_int_op(ret, ==, 0);
+ tt_str_op(expected, OP_EQ, dst);
+ }
+
+ /* Non multiple of 5 for the source buffer length. */
+ {
+ /* Length of 8 bytes. */
+ const char *expected = "blahbleh";
+ const char *src = "mjwgc2dcnrswq";
+
+ ret = base32_decode(dst, strlen(expected), src, strlen(src));
+ tt_int_op(ret, ==, 0);
+ tt_mem_op(expected, OP_EQ, dst, strlen(expected));
+ }
+
+ /* Invalid values. */
+ {
+ /* Invalid character '#'. */
+ ret = base32_decode(dst, real_dstlen, "#abcde", 6);
+ tt_int_op(ret, ==, -1);
+ /* Make sure the destination buffer has been zeroed even on error. */
+ tt_int_op(tor_mem_is_zero(dst, real_dstlen), ==, 1);
+ }
+
+done:
+ tor_free(dst);
+}
+
struct testcase_t util_format_tests[] = {
{ "unaligned_accessors", test_util_format_unaligned_accessors, 0,
NULL, NULL },
@@ -297,6 +387,10 @@ struct testcase_t util_format_tests[] = {
NULL, NULL },
{ "base64_decode", test_util_format_base64_decode, 0, NULL, NULL },
{ "base16_decode", test_util_format_base16_decode, 0, NULL, NULL },
+ { "base32_encode", test_util_format_base32_encode, 0,
+ NULL, NULL },
+ { "base32_decode", test_util_format_base32_decode, 0,
+ NULL, NULL },
END_OF_TESTCASES
};