DKIM: rename internal signing api
[exim.git] / src / src / base64.c
CommitLineData
f4d091fb
JH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
5/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004, 2015 */
6/* License: GPL */
7
80fea873 8/* Copyright (c) University of Cambridge 1995 - 2016 */
f4d091fb
JH
9/* See the file NOTICE for conditions of use and distribution. */
10
11
12#include "exim.h"
13#ifdef WITH_CONTENT_SCAN /* file-IO specific decode function */
14# include "mime.h"
15
16/* BASE64 decoder matrix */
17static unsigned char mime_b64[256]={
18/* 0 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
19/* 16 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
20/* 32 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 62, 128, 128, 128, 63,
21/* 48 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 128, 128, 128, 255, 128, 128,
22/* 64 */ 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
23/* 80 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128, 128, 128,
24/* 96 */ 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
25/* 112 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128, 128,
26/* 128 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
27/* 144 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
28/* 160 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
29/* 176 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
30/* 192 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
31/* 208 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
32/* 224 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
33/* 240 */ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
34};
35
36/* decode base64 MIME part */
37ssize_t
38mime_decode_base64(FILE * in, FILE * out, uschar * boundary)
39{
40uschar ibuf[MIME_MAX_LINE_LENGTH], obuf[MIME_MAX_LINE_LENGTH];
41uschar *ipos, *opos;
42ssize_t len, size = 0;
43int bytestate = 0;
44
45opos = obuf;
46
47while (Ufgets(ibuf, MIME_MAX_LINE_LENGTH, in) != NULL)
48 {
49 if (boundary != NULL
50 && Ustrncmp(ibuf, "--", 2) == 0
51 && Ustrncmp((ibuf+2), boundary, Ustrlen(boundary)) == 0
52 )
53 break;
54
55 for (ipos = ibuf ; *ipos != '\r' && *ipos != '\n' && *ipos != 0; ++ipos)
56 if (*ipos == '=') /* skip padding */
57 ++bytestate;
58
59 else if (mime_b64[*ipos] == 128) /* skip bad characters */
60 mime_set_anomaly(MIME_ANOMALY_BROKEN_BASE64);
61
62 /* simple state-machine */
63 else switch((bytestate++) & 3)
64 {
65 case 0:
66 *opos = mime_b64[*ipos] << 2; break;
67 case 1:
68 *opos++ |= mime_b64[*ipos] >> 4;
69 *opos = mime_b64[*ipos] << 4; break;
70 case 2:
71 *opos++ |= mime_b64[*ipos] >> 2;
72 *opos = mime_b64[*ipos] << 6; break;
73 case 3:
74 *opos++ |= mime_b64[*ipos]; break;
75 }
76
77 /* something to write? */
78 len = opos - obuf;
79 if (len > 0)
80 {
81 if (fwrite(obuf, 1, len, out) != len) return -1; /* error */
82 size += len;
83 /* copy incomplete last byte to start of obuf, where we continue */
84 if ((bytestate & 3) != 0)
85 *obuf = *opos;
86 opos = obuf;
87 }
88 } /* while */
89
90/* write out last byte if it was incomplete */
91if (bytestate & 3)
92 {
93 if (fwrite(obuf, 1, 1, out) != 1) return -1;
94 ++size;
95 }
96
97return size;
98}
99
100#endif /*WITH_CONTENT_SCAN*/
101
102/*************************************************
3c51463e
JH
103 *************************************************
104 *************************************************
105 *************************************************
106 *************************************************
107 *************************************************
108 *************************************************
109 *************************************************
110 *************************************************
111 *************************************************
112 *************************************************
113 *************************************************
114 *************************************************
115 *************************************************
116 *************************************************
117 *************************************************/
f4d091fb
JH
118
119
120/*************************************************
121* Decode byte-string in base 64 *
122*************************************************/
123
124/* This function decodes a string in base 64 format as defined in RFC 2045
125(MIME) and required by the SMTP AUTH extension (RFC 2554). The decoding
126algorithm is written out in a straightforward way. Turning it into some kind of
127compact loop is messy and would probably run more slowly.
128
129Arguments:
130 code points to the coded string, zero-terminated
131 ptr where to put the pointer to the result, which is in
df3def24 132 allocated store, and zero-terminated
f4d091fb
JH
133
134Returns: the number of bytes in the result,
135 or -1 if the input was malformed
136
69a70afa 137Whitespace in the input is ignored.
f4d091fb
JH
138A zero is added on to the end to make it easy in cases where the result is to
139be interpreted as text. This is not included in the count. */
140
141static uschar dec64table[] = {
142 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 0-15 */
143 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /* 16-31 */
144 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, /* 32-47 */
145 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,255,255,255, /* 48-63 */
146 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64-79 */
147 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, /* 80-95 */
148 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96-111 */
149 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255 /* 112-127*/
150};
151
152int
35cf75e9 153b64decode(const uschar *code, uschar **ptr)
f4d091fb
JH
154{
155int x, y;
156uschar *result = store_get(3*(Ustrlen(code)/4) + 1);
157
158*ptr = result;
159
160/* Each cycle of the loop handles a quantum of 4 input bytes. For the last
161quantum this may decode to 1, 2, or 3 output bytes. */
162
163while ((x = *code++) != 0)
164 {
69a70afa 165 if (isspace(x)) continue;
df3def24 166 /* debug_printf("b64d: '%c'\n", x); */
69a70afa 167
f4d091fb 168 if (x > 127 || (x = dec64table[x]) == 255) return -1;
69a70afa
JH
169
170 while (isspace(y = *code++)) ;
df3def24 171 /* debug_printf("b64d: '%c'\n", y); */
69a70afa 172 if (y == 0 || (y = dec64table[y]) == 255)
f4d091fb
JH
173 return -1;
174
175 *result++ = (x << 2) | (y >> 4);
df3def24 176 /* debug_printf("b64d: -> %02x\n", result[-1]); */
f4d091fb 177
69a70afa 178 while (isspace(x = *code++)) ;
df3def24
JH
179 /* debug_printf("b64d: '%c'\n", x); */
180 if (x == '=') /* endmarker, but there should be another */
f4d091fb 181 {
69a70afa 182 while (isspace(x = *code++)) ;
df3def24
JH
183 /* debug_printf("b64d: '%c'\n", x); */
184 if (x != '=') return -1;
185 while (isspace(y = *code++)) ;
186 if (y != 0) return -1;
187 /* debug_printf("b64d: DONE\n"); */
188 break;
f4d091fb
JH
189 }
190 else
191 {
192 if (x > 127 || (x = dec64table[x]) == 255) return -1;
193 *result++ = (y << 4) | (x >> 2);
df3def24 194 /* debug_printf("b64d: -> %02x\n", result[-1]); */
69a70afa
JH
195
196 while (isspace(y = *code++)) ;
df3def24 197 /* debug_printf("b64d: '%c'\n", y); */
69a70afa 198 if (y == '=')
f4d091fb 199 {
df3def24
JH
200 while (isspace(y = *code++)) ;
201 if (y != 0) return -1;
202 /* debug_printf("b64d: DONE\n"); */
203 break;
f4d091fb
JH
204 }
205 else
206 {
207 if (y > 127 || (y = dec64table[y]) == 255) return -1;
208 *result++ = (x << 6) | y;
df3def24 209 /* debug_printf("b64d: -> %02x\n", result[-1]); */
f4d091fb
JH
210 }
211 }
212 }
213
214*result = 0;
215return result - *ptr;
216}
217
218
f4d091fb
JH
219/*************************************************
220* Encode byte-string in base 64 *
221*************************************************/
222
223/* This function encodes a string of bytes, containing any values whatsoever,
224in base 64 as defined in RFC 2045 (MIME) and required by the SMTP AUTH
225extension (RFC 2554). The encoding algorithm is written out in a
226straightforward way. Turning it into some kind of compact loop is messy and
227would probably run more slowly.
228
229Arguments:
230 clear points to the clear text bytes
231 len the number of bytes to encode
232
233Returns: a pointer to the zero-terminated base 64 string, which
234 is in working store
235*/
236
237static uschar *enc64table =
238 US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
239
240uschar *
241b64encode(uschar *clear, int len)
242{
243uschar *code = store_get(4*((len+2)/3) + 1);
244uschar *p = code;
245
246while (len-- >0)
247 {
248 register int x, y;
249
250 x = *clear++;
251 *p++ = enc64table[(x >> 2) & 63];
252
253 if (len-- <= 0)
254 {
255 *p++ = enc64table[(x << 4) & 63];
256 *p++ = '=';
257 *p++ = '=';
258 break;
259 }
260
261 y = *clear++;
262 *p++ = enc64table[((x << 4) | ((y >> 4) & 15)) & 63];
263
264 if (len-- <= 0)
265 {
266 *p++ = enc64table[(y << 2) & 63];
267 *p++ = '=';
268 break;
269 }
270
271 x = *clear++;
272 *p++ = enc64table[((y << 2) | ((x >> 6) & 3)) & 63];
273
274 *p++ = enc64table[x & 63];
275 }
276
277*p = 0;
278
279return code;
280}
281
282
283/* End of base64.c */
284/* vi: sw ai sw=2
285*/