]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added support for base32 encode/decode.
authorStephan Bosch <stephan@rename-it.nl>
Sat, 15 Nov 2014 00:39:04 +0000 (02:39 +0200)
committerStephan Bosch <stephan@rename-it.nl>
Sat, 15 Nov 2014 00:39:04 +0000 (02:39 +0200)
src/lib/Makefile.am
src/lib/base32.c [new file with mode: 0644]
src/lib/base32.h [new file with mode: 0644]
src/lib/test-base32.c [new file with mode: 0644]
src/lib/test-lib.c
src/lib/test-lib.h

index ae2f8e09892cea3fa7746af937ce722a4590e3e6..4aec0eae25f4cd524136c21fb10b3fdd552e15e8 100644 (file)
@@ -16,6 +16,7 @@ liblib_la_SOURCES = \
        aqueue.c \
        askpass.c \
        backtrace-string.c \
+       base32.c \
        base64.c \
        bits.c \
        bsearch-insert-pos.c \
@@ -149,6 +150,7 @@ headers = \
        array-decl.h \
        askpass.h \
        backtrace-string.h \
+       base32.h \
        base64.h \
        bits.h \
        bsearch-insert-pos.h \
@@ -278,6 +280,7 @@ test_lib_SOURCES = \
        test-lib.c \
        test-array.c \
        test-aqueue.c \
+       test-base32.c \
        test-base64.c \
        test-bits.c \
        test-bsearch-insert-pos.c \
diff --git a/src/lib/base32.c b/src/lib/base32.c
new file mode 100644 (file)
index 0000000..b683941
--- /dev/null
@@ -0,0 +1,326 @@
+/* Copyright (c) 2007-2014 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "base32.h"
+#include "buffer.h"
+
+static const char b32enc[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+
+static const char b32hexenc[] =
+       "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+
+static const unsigned char b32dec[256] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-7 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8-15 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16-23 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24-31 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32-39 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 40-47 */
+       0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 48-55 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56-63 */
+       0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64-71 */
+       0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, /* 72-79 */
+       0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80-87 */
+       0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88-95 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96-103 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 104-111 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112-119 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120-127 */
+
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128-255 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static const unsigned char b32hexdec[256] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-7 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8-15 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16-23 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24-31 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32-39 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 40-47 */
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 48-55 */
+       0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56-63 */
+       0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, /* 64-71 */
+       0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, /* 72-79 */
+       0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0xff, /* 80-87 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88-95 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96-103 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 104-111 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112-119 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120-127 */
+
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128-255 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void
+base32_encode_with_alphabet(const char *alph,
+       bool pad, const void *src, size_t src_size, buffer_t *dest)
+{
+       const unsigned char *src_c = src;
+       unsigned char tmp[8], endb;
+       size_t src_pos;
+
+       /* [5  3][2  5  1][4  4][1  5  2][3  5]
+          (5)(3  2)(5)(1  4)(4  1)(5)(2  3)(5)
+        */
+
+       /* encode main part */
+       for (src_pos = 0; src_pos + 4 < src_size; src_pos += 5) {
+               tmp[0] = alph[src_c[src_pos] >> 3];
+               tmp[1] = alph[((src_c[src_pos] & 0x07) << 2) |
+                               ((src_c[src_pos+1] >> 6) & 0x03)];
+               tmp[2] = alph[((src_c[src_pos+1] >> 1) & 0x1f)];
+               tmp[3] = alph[((src_c[src_pos+1] & 0x01) << 4) |
+                               (src_c[src_pos+2] >> 4)];
+               tmp[4] = alph[((src_c[src_pos+2] & 0x0f) << 1) |
+                               (src_c[src_pos+3] >> 7)];
+               tmp[5] = alph[((src_c[src_pos+3] >> 2) & 0x1f)];
+               tmp[6] = alph[((src_c[src_pos+3] & 0x03) << 3) |
+                               (src_c[src_pos+4] >> 5)];
+               tmp[7] = alph[src_c[src_pos+4] & 0x1f];
+               buffer_append(dest, tmp, 8);
+       }
+
+       /* encode last < 5 bytes if any */
+       if (src_pos < src_size) {       
+               tmp[0] = alph[src_c[src_pos] >> 3];
+               switch (src_size - src_pos) {
+               case 1:
+                       tmp[1] = alph[((src_c[src_pos] & 0x07) << 2)];
+                       endb = 2;
+                       break;
+               case 2:
+                       tmp[1] = alph[((src_c[src_pos] & 0x07) << 2) |
+                                       ((src_c[src_pos+1] >> 6) & 0x03)];
+                       tmp[2] = alph[((src_c[src_pos+1] >> 1) & 0x1f)];
+                       tmp[3] = alph[((src_c[src_pos+1] & 0x01) << 4)];
+                       endb = 4;
+                       break;
+               case 3:
+                       tmp[1] = alph[((src_c[src_pos] & 0x07) << 2) |
+                                       ((src_c[src_pos+1] >> 6) & 0x03)];
+                       tmp[2] = alph[((src_c[src_pos+1] >> 1) & 0x1f)];
+                       tmp[3] = alph[((src_c[src_pos+1] & 0x01) << 4) |
+                                       (src_c[src_pos+2] >> 4)];
+                       tmp[4] = alph[((src_c[src_pos+2] & 0x0f) << 1)];
+                       endb = 5;
+                       break;
+               case 4:
+                       tmp[1] = alph[((src_c[src_pos] & 0x07) << 2) |
+                                       ((src_c[src_pos+1] >> 6) & 0x03)];
+                       tmp[2] = alph[((src_c[src_pos+1] >> 1) & 0x1f)];
+                       tmp[3] = alph[((src_c[src_pos+1] & 0x01) << 4) |
+                                       (src_c[src_pos+2] >> 4)];
+                       tmp[4] = alph[((src_c[src_pos+2] & 0x0f) << 1) |
+                                       (src_c[src_pos+3] >> 7)];
+                       tmp[5] = alph[((src_c[src_pos+3] >> 2) & 0x1f)];
+                       tmp[6] = alph[((src_c[src_pos+3] & 0x03) << 3)];
+                       endb = 7;
+                       break;
+               default:
+                       i_unreached();
+               }
+
+               /* add padding if required */
+               if (pad) {
+                       memset(&tmp[endb], '=', sizeof(tmp)-endb);
+                       buffer_append(dest, tmp, 8);
+               } else {
+                       buffer_append(dest, tmp, endb);
+               }
+       }
+}
+
+void base32_encode(bool pad, const void *src, size_t src_size,
+       buffer_t *dest)
+{
+       base32_encode_with_alphabet(b32enc, pad, src, src_size, dest);
+}
+
+void base32hex_encode(bool pad, const void *src, size_t src_size,
+       buffer_t *dest)
+{
+       base32_encode_with_alphabet(b32hexenc, pad, src, src_size, dest);
+}
+
+#define IS_EMPTY(c) \
+       ((c) == '\n' || (c) == '\r' || (c) == ' ' || (c) == '\t')
+
+static int
+base32_decode_with_alphabet(const unsigned char *alph,
+                 const void *src, size_t src_size, size_t *src_pos_r,
+                 buffer_t *dest)
+{
+       const unsigned char *src_c = src;
+       size_t block_pos, src_pos;
+       unsigned char output[5], ipos, opos;
+       int ret = 1;
+
+       /* (5)(3  2)(5)(1  4)(4  1)(5)(2  3)(5)
+          [5  3][2  5  1][4  4][1  5  2][3  5]
+        */
+       ipos = opos = 0;
+       block_pos = 0;
+       for (src_pos = 0; src_pos < src_size; src_pos++) {
+               unsigned char input = alph[src_c[src_pos]];
+
+               if (input == 0xff) {
+                       if (unlikely(!IS_EMPTY(src_c[src_pos])))
+                               break;
+                       continue;
+               }
+
+               ipos++;
+               switch (ipos) {
+               case 1:
+                       output[0] = input << 3;
+                       opos = 0;
+                       break;
+               case 2:
+                       output[0] |= input >> 2;
+                       output[1] = (input & 0x03) << 6;
+                       opos = 1;
+                       break;
+               case 3: 
+                       output[1] |= input << 1;
+                       opos = 1;
+                       break;
+               case 4:
+                       output[1] |= input >> 4;
+                       output[2] = (input & 0x0f) << 4;
+                       opos = 2;
+                       break;
+               case 5:
+                       output[2] |= input >> 1;
+                       output[3] = (input & 0x01) << 7;
+                       opos = 3;
+                       break;
+               case 6:
+                       output[3] |= input << 2;
+                       opos = 3;
+                       break;
+               case 7:
+                       output[3] |= input >> 3;
+                       output[4] = ((input & 0x07) << 5);
+                       opos = 4;
+                       break;
+               case 8:
+                       output[4] |= input;
+                       buffer_append(dest, output, 5);
+                       ipos = 0;
+                       opos = 0;
+                       block_pos = src_pos;
+                       break;
+               default:
+                       i_unreached();
+               }
+       }
+
+       if (ipos > 0) {
+               for (; src_pos < src_size; src_pos++) {
+                       if (src_c[src_pos] != '=') {
+                               if (unlikely(!IS_EMPTY(src_c[src_pos]))) {
+                                       ret = -1;
+                                       break;
+                               }
+                               continue;
+                       }
+                       if (++ipos >= 8) {
+                               buffer_append(dest, output, opos);
+                               ipos = 0;
+                               ret = 0;
+                               src_pos++;
+                               break;
+                       }
+               }
+       }
+
+       if (src_pos_r != NULL) {
+               if (ipos == 0) {
+                       for (; src_pos < src_size; src_pos++) {
+                               if (!IS_EMPTY(src_c[src_pos]))
+                                       break;
+                       }
+
+                       *src_pos_r = src_pos;
+               } else {
+                       *src_pos_r = block_pos;
+               }
+       }
+       return ret;
+}
+
+int base32_decode(const void *src, size_t src_size,
+                 size_t *src_pos_r, buffer_t *dest)
+{
+       return base32_decode_with_alphabet
+               (b32dec, src, src_size, src_pos_r, dest);
+}
+int base32hex_decode(const void *src, size_t src_size,
+                 size_t *src_pos_r, buffer_t *dest)
+{
+       return base32_decode_with_alphabet
+               (b32hexdec, src, src_size, src_pos_r, dest);
+}
+
+buffer_t *t_base32_decode_str(const char *str)
+{
+       buffer_t *buf;
+       size_t len = strlen(str);
+
+       buf = buffer_create_dynamic(pool_datastack_create(),
+                                   MAX_BASE32_DECODED_SIZE(len));
+       (void)base32_decode(str, len, NULL, buf);
+       return buf;
+}
+
+buffer_t *t_base32hex_decode_str(const char *str)
+{
+       buffer_t *buf;
+       size_t len = strlen(str);
+
+       buf = buffer_create_dynamic(pool_datastack_create(),
+                                   MAX_BASE32_DECODED_SIZE(len));
+       (void)base32hex_decode(str, len, NULL, buf);
+       return buf;
+}
+
+bool base32_is_valid_char(char c)
+{
+       return b32dec[(uint8_t)c] != 0xff;
+}
+
+bool base32hex_is_valid_char(char c)
+{
+       return b32hexdec[(uint8_t)c] != 0xff;
+}
diff --git a/src/lib/base32.h b/src/lib/base32.h
new file mode 100644 (file)
index 0000000..6a7b52a
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BASE32_H
+#define BASE32_H
+
+/* Translates binary data into base32 (RFC 4648, Section 6). The src must not
+   point to dest buffer. The pad argument determines whether output is padded
+   with '='.
+ */
+void base32_encode(bool pad, const void *src, size_t src_size,
+       buffer_t *dest);
+
+/* Translates binary data into base32hex (RFC 4648, Section 7). The src must
+   not point to dest buffer. The pad argument determines whether output is
+   padded with '='.
+ */
+void base32hex_encode(bool pad, const void *src, size_t src_size,
+       buffer_t *dest);
+
+/* Translates base32/base32hex data into binary and appends it to dest buffer.
+   dest may point to same buffer as src. Returns 1 if all ok, 0 if end of
+   base32 data found, -1 if data is invalid.
+
+   Any whitespace characters are ignored.
+
+   This function may be called multiple times for parsing the same stream.
+   If src_pos is non-NULL, it's updated to first non-translated character in
+   src. */
+int base32_decode(const void *src, size_t src_size,
+                 size_t *src_pos_r, buffer_t *dest) ATTR_NULL(4);
+int base32hex_decode(const void *src, size_t src_size,
+                 size_t *src_pos_r, buffer_t *dest) ATTR_NULL(4);
+
+/* Decode given string to a buffer allocated from data stack. */
+buffer_t *t_base32_decode_str(const char *str);
+buffer_t *t_base32hex_decode_str(const char *str);
+
+/* Returns TRUE if c is a valid base32 encoding character (excluding '=') */
+bool base32_is_valid_char(char c);
+bool base32hex_is_valid_char(char c);
+
+/* max. buffer size required for base32_encode()/base32hex_encode() */
+#define MAX_BASE32_ENCODED_SIZE(size) \
+       ((size) / 5 * 8 + 8)
+/* max. buffer size required for base32_decode()/base32hex_decode() */
+#define MAX_BASE32_DECODED_SIZE(size) \
+       ((size) / 8 * 5 + 5)
+
+#endif
diff --git a/src/lib/test-base32.c b/src/lib/test-base32.c
new file mode 100644 (file)
index 0000000..dc0f86c
--- /dev/null
@@ -0,0 +1,190 @@
+/* Copyright (c) 2007-2014 Dovecot authors, see the included COPYING file */
+
+#include "test-lib.h"
+#include "str.h"
+#include "base32.h"
+
+#include <stdlib.h>
+
+static void test_base32_encode(void)
+{
+       static const char *input[] = {
+               "toedeledokie!!",
+               "bye bye world",
+               "hoeveel onzin kun je testen?????",
+               "c'est pas vrai! ",
+               "dit is het einde van deze test"
+       };
+       static const char *output[] = {
+               "ORXWKZDFNRSWI33LNFSSCII=",
+               "MJ4WKIDCPFSSA53POJWGI===",
+               "NBXWK5TFMVWCA33OPJUW4IDLOVXCA2TFEB2GK43UMVXD6PZ7H47Q====",
+               "MMTWK43UEBYGC4ZAOZZGC2JBEA======",
+               "MRUXIIDJOMQGQZLUEBSWS3TEMUQHMYLOEBSGK6TFEB2GK43U"
+       };
+       string_t *str;
+       unsigned int i;
+
+       test_begin("base32_encode() with padding");
+       str = t_str_new(256);
+       for (i = 0; i < N_ELEMENTS(input); i++) {
+               str_truncate(str, 0);
+               base32_encode(TRUE, input[i], strlen(input[i]), str);
+               test_assert(strcmp(output[i], str_c(str)) == 0);
+       }
+       test_end();
+
+       test_begin("base32_encode() no padding");
+       str = t_str_new(256);
+       for (i = 0; i < N_ELEMENTS(input); i++) {
+               const char *p = strchr(output[i], '=');
+               size_t len;
+
+               if (p == NULL)
+                       len = strlen(output[i]);
+               else
+                       len = (size_t)(p - output[i]);
+               str_truncate(str, 0);
+               base32_encode(FALSE, input[i], strlen(input[i]), str);
+               test_assert(strncmp(output[i], str_c(str), len) == 0);
+       }
+       test_end();
+}
+
+static void test_base32hex_encode(void)
+{
+       static const char *input[] = {
+               "toedeledokie!!",
+               "bye bye world",
+               "hoeveel onzin kun je testen?????",
+               "c'est pas vrai! ",
+               "dit is het einde van deze test"
+       };
+       static const char *output[] = {
+               "EHNMAP35DHIM8RRBD5II288=",
+               "C9SMA832F5II0TRFE9M68===",
+               "D1NMATJ5CLM20RREF9KMS83BELN20QJ541Q6ASRKCLN3UFPV7SVG====",
+               "CCJMASRK41O62SP0EPP62Q9140======",
+               "CHKN8839ECG6GPBK41IMIRJ4CKG7COBE41I6AUJ541Q6ASRK"
+       };
+       string_t *str;
+       unsigned int i;
+
+       test_begin("base32hex_encode() with padding");
+       str = t_str_new(256);
+       for (i = 0; i < N_ELEMENTS(input); i++) {
+               str_truncate(str, 0);
+               base32hex_encode(TRUE, input[i], strlen(input[i]), str);
+               test_assert(strcmp(output[i], str_c(str)) == 0);
+       }
+       test_end();
+
+       test_begin("base32hex_encode() no padding");
+       str = t_str_new(256);
+       for (i = 0; i < N_ELEMENTS(input); i++) {
+               const char *p = strchr(output[i], '=');
+               size_t len;
+
+               if (p == NULL)
+                       len = strlen(output[i]);
+               else
+                       len = (size_t)(p - output[i]);
+               str_truncate(str, 0);
+               base32hex_encode(FALSE, input[i], strlen(input[i]), str);
+               test_assert(strncmp(output[i], str_c(str), len) == 0);
+       }
+       test_end();
+
+}
+
+struct test_base32_decode_output {
+       const char *text;
+       int ret;
+       unsigned int src_pos;
+};
+
+static void test_base32_decode(void)
+{
+       static const char *input[] = {
+               "ORXWKZDFNRSWI33LNFSSCII=",
+               "MJ4WKIDCPFSSA53POJWGI===",
+               "NBXWK5TFMVWCA33OPJUW4IDLOVXCA2TFEB2GK43UMVXD6PZ7H47Q====",
+               "MMTWK43UEBYGC4ZAOZZGC2JBEA======",
+               "MRUXIIDJOMQGQZLUEBSWS3TEMUQHMYLOEBSGK6TFEB2GK43U"
+       };
+       static const struct test_base32_decode_output output[] = {
+               { "toedeledokie!!", 0, 24 },
+               { "bye bye world", 0, 24 },
+               { "hoeveel onzin kun je testen?????", 0, 56 },
+               { "c'est pas vrai! ", 0, 32 },
+               { "dit is het einde van deze test", 1, 48 },
+       };
+       string_t *str;
+       unsigned int i;
+       size_t src_pos;
+       int ret;
+
+       test_begin("base32_decode()");
+       str = t_str_new(256);
+       for (i = 0; i < N_ELEMENTS(input); i++) {
+               str_truncate(str, 0);
+
+               src_pos = 0;
+               ret = base32_decode(input[i], strlen(input[i]), &src_pos, str);
+
+               test_assert(output[i].ret == ret &&
+                           strcmp(output[i].text, str_c(str)) == 0 &&
+                           (src_pos == output[i].src_pos ||
+                            (output[i].src_pos == UINT_MAX &&
+                             src_pos == strlen(input[i]))));
+       }
+       test_end();
+}
+
+static void test_base32_random(void)
+{
+       string_t *str, *dest;
+       char buf[10];
+       unsigned int i, j, max;
+
+       str = t_str_new(256);
+       dest = t_str_new(256);
+
+       test_begin("padded base32 encode/decode with random input");
+       for (i = 0; i < 1000; i++) {
+               max = rand() % sizeof(buf);
+               for (j = 0; j < max; j++)
+                       buf[j] = rand();
+
+               str_truncate(str, 0);
+               str_truncate(dest, 0);
+               base32_encode(TRUE, buf, max, str);
+               test_assert(base32_decode(str_data(str), str_len(str), NULL, dest) >= 0);
+               test_assert(str_len(dest) == max &&
+                           memcmp(buf, str_data(dest), max) == 0);
+       }
+       test_end();
+
+       test_begin("padded base32hex encode/decode with random input");
+       for (i = 0; i < 1000; i++) {
+               max = rand() % sizeof(buf);
+               for (j = 0; j < max; j++)
+                       buf[j] = rand();
+
+               str_truncate(str, 0);
+               str_truncate(dest, 0);
+               base32hex_encode(TRUE, buf, max, str);
+               test_assert(base32hex_decode(str_data(str), str_len(str), NULL, dest) >= 0);
+               test_assert(str_len(dest) == max &&
+                           memcmp(buf, str_data(dest), max) == 0);
+       }
+       test_end();
+}
+
+void test_base32(void)
+{
+       test_base32_encode();
+       test_base32hex_encode();
+       test_base32_decode();
+       test_base32_random();
+}
index 8083e0f769f19093c3f50c9910d88edcc88c16b1..5c264eb9c1c686866fca13fd020882e73cc8b35b 100644 (file)
@@ -7,6 +7,7 @@ int main(void)
        static void (*test_functions[])(void) = {
                test_aqueue,
                test_array,
+               test_base32,
                test_base64,
                test_bits,
                test_bsearch_insert_pos,
index 8fd07c332e66558a7828b0412b49a0b51abf4191..fe19f6bca7f3c7416e3397114877498cc0a90b3d 100644 (file)
@@ -6,6 +6,7 @@
 
 void test_aqueue(void);
 void test_array(void);
+void test_base32(void);
 void test_base64(void);
 void test_bits(void);
 void test_bsearch_insert_pos(void);