Merge branch 'bug18280_029_03_nm_squashed'

This commit is contained in:
Nick Mathewson 2016-06-17 13:53:57 -04:00
commit 48b25e6811
3 changed files with 119 additions and 12 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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
};