From 92496d02007139d676a9ca4a35f288b368658be4 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Wed, 20 May 2015 11:49:51 +0100 Subject: [PATCH] Add base64 encoding routine. --- src/libutil/util.c | 166 +++++++++++++++++++++++++++++++++++++++++++++ src/libutil/util.h | 10 +++ 2 files changed, 176 insertions(+) diff --git a/src/libutil/util.c b/src/libutil/util.c index 15f73bf09..8aac96a90 100644 --- a/src/libutil/util.c +++ b/src/libutil/util.c @@ -2315,6 +2315,172 @@ rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen) return res; } +gchar * +rspamd_encode_base64 (const guchar *in, gsize inlen, gint str_len, gsize *outlen) +{ + gsize allocated_len = (inlen / 3) * 4 + 4; + gchar *out, *o; + guint64 n; + guint32 t1, t2, t3; + gint cols, shift; + guint i = 0; + static const char b64_enc[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + if (str_len > 0) { + allocated_len += (allocated_len / str_len + 1) * 2 + 1; + } + + out = g_malloc (allocated_len); + o = out; + cols = 0; + + while (inlen > 6) { + n = *(guint64 *)in; + n = GUINT64_TO_BE (n); + + if (str_len <= 0 || cols <= str_len - 8) { + *o++ = b64_enc[(n >> 58) & 0x3F]; + *o++ = b64_enc[(n >> 52) & 0x3F]; + *o++ = b64_enc[(n >> 46) & 0x3F]; + *o++ = b64_enc[(n >> 40) & 0x3F]; + *o++ = b64_enc[(n >> 34) & 0x3F]; + *o++ = b64_enc[(n >> 28) & 0x3F]; + *o++ = b64_enc[(n >> 22) & 0x3F]; + *o++ = b64_enc[(n >> 16) & 0x3F]; + cols += 8; + } + else { + cols = str_len - cols; + shift = 58; + while (cols) { + *o++ = b64_enc[(n >> shift) & 0x3F]; + shift -= 6; + cols --; + } + + *o++ = '\r'; + *o++ = '\n'; + + /* Remaining bytes */ + while (shift >= 16) { + *o++ = b64_enc[(n >> shift) & 0x3F]; + shift -= 6; + cols ++; + } + } + + in += 6; + inlen -= 6; + } + + if (str_len > 0 && cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + /* Trailing bytes */ + if (inlen > 2) { + for (i = 0; i < inlen - 2; i += 3) { + t1 = in[i]; t2 = in[i+1]; t3 = in[i+2]; + *o++ = b64_enc[t1]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = b64_enc[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = b64_enc[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = b64_enc[t3]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + } + } + + /* Padding + remaining data (0 - 2 bytes) */ + switch (inlen - i) { + case 0: + break; + case 1: + t1 = in[i]; + *o++ = b64_enc[t1]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = b64_enc[(t1 & 0x03) << 4]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = '='; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = '='; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + break; + default: /* case 2 */ + t1 = in[i]; t2 = in[i+1]; + *o++ = b64_enc[t1]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = b64_enc[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = b64_enc[(t2 & 0x0F) << 2]; + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + *o++ = '='; + } + + if (str_len > 0 && ++cols >= str_len) { + *o++ = '\r'; + *o++ = '\n'; + cols = 0; + } + + *o = '\0'; + + if (outlen != NULL) { + *outlen = o - out; + } + + return out; +} + gdouble rspamd_get_ticks (void) { diff --git a/src/libutil/util.h b/src/libutil/util.h index af2e00065..c4170881c 100644 --- a/src/libutil/util.h +++ b/src/libutil/util.h @@ -428,6 +428,16 @@ gchar * rspamd_encode_base32 (const guchar *in, gsize inlen); */ guchar* rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen); +/** + * Encode string using base64 encoding + * @param in input + * @param inlen input length + * @param str_len maximum string length (if <= 0 then no lines are split) + * @return freshly allocated base64 encoded value or NULL if input is invalid + */ +gchar * rspamd_encode_base64 (const guchar *in, gsize inlen, gint str_len, + gsize *outlen); + /** * Portably return the current clock ticks as seconds * @return -- 2.39.5