summaryrefslogtreecommitdiffstats
path: root/src/lib/base64.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/base64.h')
-rw-r--r--src/lib/base64.h403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/lib/base64.h b/src/lib/base64.h
new file mode 100644
index 0000000..ec6ac17
--- /dev/null
+++ b/src/lib/base64.h
@@ -0,0 +1,403 @@
+#ifndef BASE64_H
+#define BASE64_H
+
+/*
+ * Common Base64
+ */
+
+/* max. buffer size required for base64_encode() */
+#define MAX_BASE64_ENCODED_SIZE(size) \
+ ((((size) + 2) / 3) * 4)
+/* max. buffer size required for base64_decode() */
+#define MAX_BASE64_DECODED_SIZE(size) \
+ (((size) + 3) / 4 * 3)
+
+struct base64_scheme {
+ const char encmap[64];
+ const unsigned char decmap[256];
+};
+
+/*
+ * Low-level Base64 encoder
+ */
+
+enum base64_encode_flags {
+ /* Use CRLF instead of the default LF as line ending. */
+ BASE64_ENCODE_FLAG_CRLF = BIT(0),
+ /* Encode no padding at the end of the data. */
+ BASE64_ENCODE_FLAG_NO_PADDING = BIT(1),
+};
+
+struct base64_encoder {
+ const struct base64_scheme *b64;
+ enum base64_encode_flags flags;
+ size_t max_line_len;
+
+ /* state */
+ unsigned int sub_pos;
+ unsigned char buf;
+ size_t cur_line_len;
+
+ unsigned char w_buf[10];
+ unsigned int w_buf_len;
+
+ bool pending_lf:1;
+ bool finishing:1;
+ bool finished:1;
+};
+
+/* Returns TRUE when base64_encode_finish() was called on this encoder. */
+static inline bool
+base64_encode_is_finished(struct base64_encoder *enc)
+{
+ return enc->finished;
+}
+
+/* Initialize the Base64 encoder. The b64 parameter is the definition of the
+ particular Base64 encoding scheme that is used.
+ */
+static inline void
+base64_encode_init(struct base64_encoder *enc,
+ const struct base64_scheme *b64,
+ enum base64_encode_flags flags,
+ size_t max_line_len)
+{
+ i_zero(enc);
+ enc->b64 = b64;
+ enc->flags = flags;
+ enc->max_line_len = (max_line_len == 0 ? SIZE_MAX : max_line_len);
+}
+
+/* Reset the Base64 encoder to its initial state. */
+static inline void
+base64_encode_reset(struct base64_encoder *enc)
+{
+ const struct base64_scheme *b64 = enc->b64;
+ enum base64_encode_flags flags = enc->flags;
+ size_t max_line_len = enc->max_line_len;
+
+ base64_encode_init(enc, b64, flags, max_line_len);
+}
+
+/* Translate the size of the full encoder input to the size of the encoder
+ output.
+ */
+uoff_t base64_get_full_encoded_size(struct base64_encoder *enc,
+ uoff_t src_size);
+/* Translate the size of the next input to the size of the output once encoded.
+ This yields the amount of data appended to the dest buffer by
+ base64_encode_more() with the indicated src_size. */
+size_t base64_encode_get_size(struct base64_encoder *enc, size_t src_size);
+
+/* Translate the space in the destination buffer to the number of bytes that can
+ be encoded at most to complete the full base64 encoding, including padding
+ and newlines if configured. */
+size_t base64_encode_get_full_space(struct base64_encoder *enc,
+ size_t dst_space);
+
+/* Translates binary data into some form of Base64. The src must not point to
+ dest buffer. Returns TRUE when all the provided data is encoded. Returns
+ FALSE when the space in the provided buffer is insufficient. The return value
+ may be ignored. If src_pos_r is non-NULL, it's updated to first
+ non-translated character in src.
+ */
+bool ATTR_NOWARN_UNUSED_RESULT
+base64_encode_more(struct base64_encoder *enc, const void *src, size_t src_size,
+ size_t *src_pos_r, buffer_t *dest) ATTR_NULL(4);
+
+/* Finishes Base64 encoding. Returns TRUE when all the provided data is encoded.
+ Returns FALSE when the space in the provided buffer is insufficient. The
+ return value may be ignored.
+ */
+bool ATTR_NOWARN_UNUSED_RESULT
+base64_encode_finish(struct base64_encoder *enc, buffer_t *dest) ATTR_NULL(2);
+
+/*
+ * Low-level Base64 decoder
+ */
+
+enum base64_decode_flags {
+ /* Decode input until a boundary is reached. This boundary is a
+ non-Base64 input sequence that would normally trigger a decode error;
+ e.g., Base64 data followed by a ':'. With this flag, it is possible
+ to decode such a Base64 prefix. The base64_decode_finish() function
+ will still check that the Base64 data ends properly (padding). */
+ BASE64_DECODE_FLAG_EXPECT_BOUNDARY = BIT(0),
+ /* Prohibit whitespace in the input. */
+ BASE64_DECODE_FLAG_NO_WHITESPACE = BIT(1),
+ /* Require absence of padding at the end of the input. */
+ BASE64_DECODE_FLAG_NO_PADDING = BIT(2),
+ /* Ignore padding at the end of the input. This flag is ignored when
+ BASE64_DECODE_FLAG_NO_PADDING is also set. If both of these flags are
+ absent, padding is required (the default). */
+ BASE64_DECODE_FLAG_IGNORE_PADDING = BIT(3),
+};
+
+struct base64_decoder {
+ const struct base64_scheme *b64;
+ enum base64_decode_flags flags;
+
+ /* state */
+ unsigned int sub_pos;
+ unsigned char buf;
+
+ bool seen_padding:1;
+ bool seen_end:1;
+ bool seen_boundary:1;
+ bool finished:1;
+ bool failed:1;
+};
+
+/* Returns TRUE when base64_decode_finish() was called on this decoder. */
+static inline bool
+base64_decode_is_finished(struct base64_decoder *dec)
+{
+ return dec->finished;
+}
+
+/* Initialize the Base64 decoder. The b64 parameter is the definition of the
+ particular Base64 encoding scheme that is expected.
+ */
+static inline void
+base64_decode_init(struct base64_decoder *dec,
+ const struct base64_scheme *b64,
+ enum base64_decode_flags flags)
+{
+ i_zero(dec);
+ dec->b64 = b64;
+ dec->flags = flags;
+}
+
+/* Reset the Base64 decoder to its initial state. */
+static inline void
+base64_decode_reset(struct base64_decoder *dec)
+{
+ const struct base64_scheme *b64 = dec->b64;
+ enum base64_decode_flags flags = dec->flags;
+
+ base64_decode_init(dec, b64, flags);
+}
+
+/* Translates some form 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.
+
+ By default, any CR, LF characters are ignored, as well as any whitespace.
+ This can be overridden using the BASE64_DECODE_FLAG_NO_WHITESPACE flag.
+
+ If src_pos is non-NULL, it's updated to first non-translated character in
+ src.
+ */
+int base64_decode_more(struct base64_decoder *dec,
+ const void *src, size_t src_size, size_t *src_pos_r,
+ buffer_t *dest) ATTR_NULL(4);
+/* Finishes Base64 decoding. This function checks whether the encoded data ends
+ in the proper padding. Returns 0 if all ok, and -1 if data is invalid.
+ */
+int base64_decode_finish(struct base64_decoder *dec);
+
+/*
+ * 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.
+ */
+static inline void
+base64_scheme_encode(const struct base64_scheme *b64,
+ enum base64_encode_flags flags, size_t max_line_len,
+ const void *src, size_t src_size, buffer_t *dest)
+{
+ struct base64_encoder enc;
+
+ base64_encode_init(&enc, b64, flags, max_line_len);
+ base64_encode_more(&enc, src, src_size, NULL, dest);
+ base64_encode_finish(&enc, dest);
+}
+
+buffer_t *t_base64_scheme_encode(const struct base64_scheme *b64,
+ enum base64_encode_flags flags,
+ size_t max_line_len,
+ const void *src, size_t src_size);
+
+static inline buffer_t *
+t_base64_scheme_encode_str(const struct base64_scheme *b64,
+ enum base64_encode_flags flags, size_t max_line_len,
+ const char *src)
+{
+ return t_base64_scheme_encode(b64, flags, max_line_len,
+ src, strlen(src));
+}
+
+/* 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.
+
+ 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.
+ */
+int base64_scheme_decode(const struct base64_scheme *b64,
+ enum base64_decode_flags flags,
+ const void *src, size_t src_size, buffer_t *dest);
+
+/* Decode given data to a buffer allocated from data stack.
+
+ The b64 parameter is the definition of the particular Base 64 encoding scheme
+ that is expected. See below for specific functions.
+ */
+buffer_t *t_base64_scheme_decode(const struct base64_scheme *b64,
+ enum base64_decode_flags flags,
+ const void *src, size_t src_size);
+/* Decode given string to a buffer allocated from data stack.
+
+ The b64 parameter is the definition of the particular Base 64 encoding scheme
+ that is expected. See below for specific functions.
+ */
+static inline buffer_t *
+t_base64_scheme_decode_str(const struct base64_scheme *b64,
+ enum base64_decode_flags flags, const char *str)
+{
+ return t_base64_scheme_decode(b64, flags, str, strlen(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, 0, 0, src, src_size, dest);
+}
+
+static inline buffer_t *
+t_base64_encode(enum base64_encode_flags flags, size_t max_line_len,
+ const void *src, size_t src_size)
+{
+ return t_base64_scheme_encode(&base64_scheme, flags, max_line_len,
+ src, src_size);
+}
+
+static inline buffer_t *
+t_base64_encode_str(enum base64_encode_flags flags, size_t max_line_len,
+ const char *src)
+{
+ return t_base64_scheme_encode(&base64_scheme, flags, max_line_len,
+ src, strlen(src));
+}
+
+/* Translates base64 data into binary and appends it to dest buffer. See
+ base64_scheme_decode().
+
+ The src_pos_r parameter is deprecated and MUST be NULL.
+ */
+static inline int
+base64_decode(const void *src, size_t src_size, size_t *src_pos_r ATTR_UNUSED,
+ buffer_t *dest) ATTR_NULL(3)
+{
+ // NOTE: src_pos_r is deprecated here; to be removed in v2.4 */
+ i_assert(src_pos_r == NULL);
+
+ return base64_scheme_decode(&base64_scheme, 0, src, src_size, dest);
+}
+
+/* Decode given data to a buffer allocated from data stack. */
+static inline buffer_t *
+t_base64_decode(enum base64_decode_flags flags,
+ const void *src, size_t src_size)
+{
+ return t_base64_scheme_decode(&base64_scheme, flags, src, src_size);
+}
+
+/* Decode given string to a buffer allocated from data stack. */
+static inline buffer_t *t_base64_decode_str(const char *str)
+{
+ return t_base64_scheme_decode_str(&base64_scheme, 0, str);
+}
+
+/* Returns TRUE if c is a valid base64 encoding character (excluding '=') */
+static inline bool base64_is_valid_char(char c)
+{
+ return base64_scheme_is_valid_char(&base64_scheme, c);
+}
+
+/*
+ * "base64url" encoding scheme (RFC 4648, Section 5)
+ */
+
+extern struct base64_scheme base64url_scheme;
+
+/* Translates binary data into base64url. See base64_scheme_encode(). */
+static inline void
+base64url_encode(enum base64_encode_flags flags, size_t max_line_len,
+ const void *src, size_t src_size, buffer_t *dest)
+{
+ base64_scheme_encode(&base64url_scheme, flags, max_line_len,
+ src, src_size, dest);
+}
+
+static inline buffer_t *
+t_base64url_encode(enum base64_encode_flags flags, size_t max_line_len,
+ const void *src, size_t src_size)
+{
+ return t_base64_scheme_encode(&base64url_scheme, flags, max_line_len,
+ src, src_size);
+}
+
+static inline buffer_t *
+t_base64url_encode_str(enum base64_encode_flags flags, size_t max_line_len,
+ const char *src)
+{
+ return t_base64_scheme_encode(&base64url_scheme, flags, max_line_len,
+ src, strlen(src));
+}
+
+/* Translates base64url data into binary and appends it to dest buffer. See
+ base64_scheme_decode(). */
+static inline int
+base64url_decode(enum base64_decode_flags flags,
+ const void *src, size_t src_size, buffer_t *dest)
+{
+ return base64_scheme_decode(&base64url_scheme, flags,
+ src, src_size, dest);
+}
+
+/* Decode given data to a buffer allocated from data stack. */
+static inline buffer_t *
+t_base64url_decode(enum base64_decode_flags flags,
+ const void *src, size_t src_size)
+{
+ return t_base64_scheme_decode(&base64url_scheme, flags, src, src_size);
+}
+
+/* Decode given string to a buffer allocated from data stack. */
+static inline buffer_t *
+t_base64url_decode_str(enum base64_decode_flags flags, const char *str)
+{
+ return t_base64_scheme_decode_str(&base64url_scheme, flags, str);
+}
+
+/* Returns TRUE if c is a valid base64url encoding character (excluding '=') */
+static inline bool base64url_is_valid_char(char c)
+{
+ return base64_scheme_is_valid_char(&base64url_scheme, c);
+}
+
+#endif