Browse Source

Fix base32 API to take any source length in bytes

Fixes #18280

Signed-off-by: David Goulet <dgoulet@ev0ke.net>
David Goulet 8 years ago
parent
commit
4e4a7d2b0c
2 changed files with 25 additions and 12 deletions
  1. 24 12
      src/common/util_format.c
  2. 1 0
      src/common/util_format.h

+ 24 - 12
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);
 

+ 1 - 0
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);