summaryrefslogtreecommitdiffstats
path: root/src/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/base64.c')
-rw-r--r--src/base64.c297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..fa06a7a
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,297 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004, 2015 */
+/* License: GPL */
+
+/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+
+#include "exim.h"
+#ifdef WITH_CONTENT_SCAN /* file-IO specific decode function */
+# include "mime.h"
+
+/* BASE64 decoder matrix */
+static unsigned char mime_b64[256]={
+/* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63,
+/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128,
+/* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128,
+/* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128,
+/* 128 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 144 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 160 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 176 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 192 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 208 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 224 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+/* 240 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
+};
+
+/* decode base64 MIME part */
+ssize_t
+mime_decode_base64(FILE * in, FILE * out, uschar * boundary)
+{
+uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH];
+uschar *opos;
+ssize_t len, size = 0;
+int bytestate = 0;
+
+opos = obuf;
+
+while (Ufgets(ibuf, MIME_MAX_LINE_LENGTH, in) != NULL)
+ {
+ if (boundary != NULL
+ && Ustrncmp(ibuf, "--", 2) == 0
+ && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0
+ )
+ break;
+
+ for (uschar * ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos; ++ipos)
+ if (*ipos == '=') /* skip padding */
+ ++bytestate;
+
+ else if (mime_b64[*ipos] == 128) /* skip bad characters */
+ mime_set_anomaly(MIME_ANOMALY_BROKEN_BASE64);
+
+ /* simple state-machine */
+ else switch((bytestate++) & 3)
+ {
+ case 0:
+ *opos = mime_b64[*ipos] << 2; break;
+ case 1:
+ *opos++ |= mime_b64[*ipos] >> 4;
+ *opos = mime_b64[*ipos] << 4; break;
+ case 2:
+ *opos++ |= mime_b64[*ipos] >> 2;
+ *opos = mime_b64[*ipos] << 6; break;
+ case 3:
+ *opos++ |= mime_b64[*ipos]; break;
+ }
+
+ /* something to write? */
+ len = opos - obuf;
+ if (len > 0)
+ {
+ if (fwrite(obuf, 1, len, out) != len) return -1; /* error */
+ size += len;
+ /* copy incomplete last byte to start of obuf, where we continue */
+ if ((bytestate & 3) != 0)
+ *obuf = *opos;
+ opos = obuf;
+ }
+ } /* while */
+
+/* write out last byte if it was incomplete */
+if (bytestate & 3)
+ {
+ if (fwrite(obuf, 1, 1, out) != 1) return -1;
+ ++size;
+ }
+
+return size;
+}
+
+#endif /*WITH_CONTENT_SCAN*/
+
+/*************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************
+ *************************************************/
+
+
+/*************************************************
+* Decode byte-string in base 64 *
+*************************************************/
+
+/* This function decodes a string in base 64 format as defined in RFC 2045
+(MIME) and required by the SMTP AUTH extension (RFC 2554). The decoding
+algorithm is written out in a straightforward way. Turning it into some kind of
+compact loop is messy and would probably run more slowly.
+
+Arguments:
+ code points to the coded string, zero-terminated
+ ptr where to put the pointer to the result, which is in
+ allocated store, and zero-terminated
+
+Returns: the number of bytes in the result,
+ or -1 if the input was malformed
+
+Whitespace in the input is ignored.
+A zero is added on to the end to make it easy in cases where the result is to
+be interpreted as text. This is not included in the count. */
+
+static uschar dec64table[] = {
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0-15 */
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 16-31 */
+ 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, /* 32-47 */
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, /* 48-63 */
+ 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64-79 */
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, /* 80-95 */
+ 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96-111 */
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255 /* 112-127*/
+};
+
+int
+b64decode(const uschar *code, uschar **ptr)
+{
+
+int x, y;
+uschar *result;
+
+ {
+ int l = Ustrlen(code);
+ *ptr = result = store_get(1 + l/4 * 3 + l%4, code);
+ }
+
+/* Each cycle of the loop handles a quantum of 4 input bytes. For the last
+quantum this may decode to 1, 2, or 3 output bytes. */
+
+while ((x = *code++) != 0)
+ {
+ if (isspace(x)) continue;
+ /* debug_printf("b64d: '%c'\n", x); */
+
+ if (x > 127 || (x = dec64table[x]) == 255) return -1;
+
+ while (isspace(y = *code++)) ;
+ /* debug_printf("b64d: '%c'\n", y); */
+ if (y > 127 || (y = dec64table[y]) == 255)
+ return -1;
+
+ *result++ = (x << 2) | (y >> 4);
+ /* debug_printf("b64d: -> %02x\n", result[-1]); */
+
+ while (isspace(x = *code++)) ;
+ /* debug_printf("b64d: '%c'\n", x); */
+ if (x == '=') /* endmarker, but there should be another */
+ {
+ while (isspace(x = *code++)) ;
+ /* debug_printf("b64d: '%c'\n", x); */
+ if (x != '=') return -1;
+ while (isspace(y = *code++)) ;
+ if (y != 0) return -1;
+ /* debug_printf("b64d: DONE\n"); */
+ break;
+ }
+ else
+ {
+ if (x > 127 || (x = dec64table[x]) == 255) return -1;
+ *result++ = (y << 4) | (x >> 2);
+ /* debug_printf("b64d: -> %02x\n", result[-1]); */
+
+ while (isspace(y = *code++)) ;
+ /* debug_printf("b64d: '%c'\n", y); */
+ if (y == '=')
+ {
+ while (isspace(y = *code++)) ;
+ if (y != 0) return -1;
+ /* debug_printf("b64d: DONE\n"); */
+ break;
+ }
+ else
+ {
+ if (y > 127 || (y = dec64table[y]) == 255) return -1;
+ *result++ = (x << 6) | y;
+ /* debug_printf("b64d: -> %02x\n", result[-1]); */
+ }
+ }
+ }
+
+*result = 0;
+return result - *ptr;
+}
+
+
+/*************************************************
+* Encode byte-string in base 64 *
+*************************************************/
+
+/* This function encodes a string of bytes, containing any values whatsoever,
+in base 64 as defined in RFC 2045 (MIME) and required by the SMTP AUTH
+extension (RFC 2554). The encoding algorithm is written out in a
+straightforward way. Turning it into some kind of compact loop is messy and
+would probably run more slowly.
+
+Arguments:
+ clear points to the clear text bytes
+ len the number of bytes to encode
+ proto_mem taint indicator
+
+Returns: a pointer to the zero-terminated base 64 string, which
+ is in working store
+*/
+
+static uschar *enc64table =
+ US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+uschar *
+b64encode_taint(const uschar * clear, int len, const void * proto_mem)
+{
+uschar * code = store_get(4*((len+2)/3) + 1, proto_mem);
+uschar * p = code;
+
+while (len-- >0)
+ {
+ int x, y;
+
+ x = *clear++;
+ *p++ = enc64table[(x >> 2) & 63];
+
+ if (len-- <= 0)
+ {
+ *p++ = enc64table[(x << 4) & 63];
+ *p++ = '=';
+ *p++ = '=';
+ break;
+ }
+
+ y = *clear++;
+ *p++ = enc64table[((x << 4) | ((y >> 4) & 15)) & 63];
+
+ if (len-- <= 0)
+ {
+ *p++ = enc64table[(y << 2) & 63];
+ *p++ = '=';
+ break;
+ }
+
+ x = *clear++;
+ *p++ = enc64table[((y << 2) | ((x >> 6) & 3)) & 63];
+
+ *p++ = enc64table[x & 63];
+ }
+
+*p = 0;
+
+return code;
+}
+
+uschar *
+b64encode(const uschar * clear, int len)
+{
+return b64encode_taint(clear, len, clear);
+}
+
+
+/* End of base64.c */
+/* vi: sw ai sw=2
+*/