From: Stephan Bosch Date: Wed, 13 Feb 2019 18:00:11 +0000 (+0100) Subject: lib: base64 - Make code suitable for encoding/decoding different Base64 variants. X-Git-Tag: 2.3.8~138 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ca160577fce3d7cd70c8b02711dcad202e559846;p=thirdparty%2Fdovecot%2Fcore.git lib: base64 - Make code suitable for encoding/decoding different Base64 variants. --- diff --git a/src/lib/base64.c b/src/lib/base64.c index a60a6af7ea..0b5f004c87 100644 --- a/src/lib/base64.c +++ b/src/lib/base64.c @@ -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, + }, }; diff --git a/src/lib/base64.h b/src/lib/base64.h index c52ec4fafe..664e652309 100644 --- a/src/lib/base64.h +++ b/src/lib/base64.h @@ -12,16 +12,31 @@ #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