]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: base64 - Make code suitable for encoding/decoding different Base64 variants.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Wed, 13 Feb 2019 18:00:11 +0000 (19:00 +0100)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 10 Sep 2019 07:02:24 +0000 (10:02 +0300)
src/lib/base64.c
src/lib/base64.h

index a60a6af7ead774cc96e4b77cc35fb4fae2565bd0..0b5f004c87e703b2e58688b335154ee56f5fb130 100644 (file)
@@ -5,14 +5,14 @@
 #include "buffer.h"
 
 /*
- * "base64" encoding (RFC 4648, Section 4)
+ * Common Base 64
  */
 
-static const char b64enc[];
-static const unsigned char b64dec[256];
-
-void base64_encode(const void *src, size_t src_size, buffer_t *dest)
+void base64_scheme_encode(const struct base64_scheme *b64,
+                         const void *src, size_t src_size,
+                         buffer_t *dest)
 {
+       const char *b64enc = b64->encmap;
        const size_t res_size = MAX_BASE64_ENCODED_SIZE(src_size);
        unsigned char *start = buffer_append_space_unsafe(dest, res_size);
        unsigned char *ptr = start;
@@ -54,9 +54,11 @@ void base64_encode(const void *src, size_t src_size, buffer_t *dest)
 #define IS_EMPTY(c) \
        ((c) == '\n' || (c) == '\r' || (c) == ' ' || (c) == '\t')
 
-int base64_decode(const void *src, size_t src_size,
-                 size_t *src_pos_r, buffer_t *dest)
+int base64_scheme_decode(const struct base64_scheme *b64,
+                        const void *src, size_t src_size, size_t *src_pos_r,
+                        buffer_t *dest)
 {
+       const unsigned char *b64dec = b64->decmap;
        const unsigned char *src_c = src;
        size_t src_pos;
        unsigned char input[4], output[3];
@@ -122,64 +124,65 @@ int base64_decode(const void *src, size_t src_size,
        return ret;
 }
 
-buffer_t *t_base64_decode_str(const char *str)
+buffer_t *t_base64_scheme_decode_str(const struct base64_scheme *b64,
+                                    const char *str)
 {
        buffer_t *buf;
        size_t len = strlen(str);
 
        buf = t_buffer_create(MAX_BASE64_DECODED_SIZE(len));
-       (void)base64_decode(str, len, NULL, buf);
+       (void)base64_scheme_decode(b64, str, len, NULL, buf);
        return buf;
 }
 
-bool base64_is_valid_char(char c)
-{
-       return b64dec[(uint8_t)c] != 0xff;
-}
-
-static const char b64enc[64] = {
-       'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
-       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
-       'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
-       'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
-       'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
-       'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
-       'w', 'x', 'y', 'z', '0', '1', '2', '3',
-       '4', '5', '6', '7', '8', '9', '+', '/',
-};
+/*
+ * "base64" encoding scheme (RFC 4648, Section 4)
+ */
 
-static const unsigned char b64dec[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, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40-47 */
-       0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48-55 */
-       0x3c, 0x3d, 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, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96-103 */
-       0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104-111 */
-       0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112-119 */
-       0x31, 0x32, 0x33, 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,
+struct base64_scheme base64_scheme = {
+       .encmap = {
+               'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+               'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+               'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+               'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+               'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+               'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+               'w', 'x', 'y', 'z', '0', '1', '2', '3',
+               '4', '5', '6', '7', '8', '9', '+', '/',
+       },
+       .decmap = {
+               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, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40-47 */
+               0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48-55 */
+               0x3c, 0x3d, 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, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96-103 */
+               0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104-111 */
+               0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112-119 */
+               0x31, 0x32, 0x33, 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,
+       },
 };
index c52ec4fafe76aff1f2d263a8c38c72ea9e9e4ef6..664e652309d5d0ab8c8ff7d444a18b3fa3922bca 100644 (file)
 #define MAX_BASE64_DECODED_SIZE(size) \
        (((size) + 3) / 4 * 3)
 
+struct base64_scheme {
+       const char encmap[64];
+       const unsigned char decmap[256];
+};
+
 /*
- * "base64" encoding (RFC 4648, Section 4)
+ * Generic Base64 API
+ */
+
+/* Translates binary data into some variant of Base64. The src must not point to
+   dest buffer.
+
+   The b64 parameter is the definition of the particular Base 64 encoding scheme
+   that is used. See below for specific functions.
  */
+void base64_scheme_encode(const struct base64_scheme *b64,
+                         const void *src, size_t src_size,
+                         buffer_t *dest);
 
-/* Translates binary data into base64. The src must not point to dest buffer. */
-void base64_encode(const void *src, size_t src_size, buffer_t *dest);
+/* Translates some variant of Base64 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 Base64 data found, -1 if data is invalid.
 
-/* Translates base64 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 base64 data
-   found, -1 if data is invalid.
+   The b64 parameter is the definition of the particular Base 64 encoding scheme
+   that is expected. See below for specific functions.
 
    Any CR, LF characters are ignored, as well as whitespace at beginning or
    end of line.
@@ -29,13 +44,59 @@ void base64_encode(const void *src, size_t src_size, buffer_t *dest);
    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 base64_decode(const void *src, size_t src_size,
-                 size_t *src_pos_r, buffer_t *dest) ATTR_NULL(3);
+int base64_scheme_decode(const struct base64_scheme *b64,
+                        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.
+
+   The decmap is the mapping table used for the specific base64 encoding
+   variant. See below for specific functions.
+ */
+buffer_t *t_base64_scheme_decode_str(const struct base64_scheme *b64,
+                                    const char *str);
+
+/* Returns TRUE if c is a valid encoding character (excluding '=') for the
+   provided base64 mapping table */
+static inline bool
+base64_scheme_is_valid_char(const struct base64_scheme *b64, char c)
+{
+       return b64->decmap[(uint8_t)c] != 0xff;
+}
+
+/*
+ * "base64" encoding scheme (RFC 4648, Section 4)
+ */
+
+extern struct base64_scheme base64_scheme;
+
+/* Translates binary data into base64. See base64_scheme_encode(). */
+static inline void
+base64_encode(const void *src, size_t src_size, buffer_t *dest)
+{
+       base64_scheme_encode(&base64_scheme, src, src_size, dest);
+}
+
+/* Translates base64 data into binary and appends it to dest buffer. See
+   base64_scheme_decode(). */
+static inline int
+base64_decode(const void *src, size_t src_size, size_t *src_pos_r,
+             buffer_t *dest) ATTR_NULL(3)
+{
+       return base64_scheme_decode(&base64_scheme, src, src_size,
+                                   src_pos_r, dest);
+}
 
 /* Decode given string to a buffer allocated from data stack. */
-buffer_t *t_base64_decode_str(const char *str);
+static inline buffer_t *t_base64_decode_str(const char *str)
+{
+       return t_base64_scheme_decode_str(&base64_scheme, str);
+}
 
 /* Returns TRUE if c is a valid base64 encoding character (excluding '=') */
-bool base64_is_valid_char(char c);
+static inline bool base64_is_valid_char(char c)
+{
+       return base64_scheme_is_valid_char(&base64_scheme, c);
+}
 
 #endif