]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/base64.c
63bb9bf09832cf4eb022c252218b164566b076fa
[thirdparty/squid.git] / lib / base64.c
1 /*
2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /*
10 * Copied from Nettle 3.4 under GPLv2, with adjustments
11 */
12
13 #include "squid.h"
14 #include "base64.h"
15
16 #if !HAVE_NETTLE_BASE64_H || !HAVE_NETTLE34_BASE64
17
18 /* base64-encode.c
19
20 Copyright (C) 2002 Niels Möller
21
22 This file is part of GNU Nettle.
23
24 GNU Nettle is free software: you can redistribute it and/or
25 modify it under the terms of either:
26
27 * the GNU Lesser General Public License as published by the Free
28 Software Foundation; either version 3 of the License, or (at your
29 option) any later version.
30
31 or
32
33 * the GNU General Public License as published by the Free
34 Software Foundation; either version 2 of the License, or (at your
35 option) any later version.
36
37 or both in parallel, as here.
38
39 GNU Nettle is distributed in the hope that it will be useful,
40 but WITHOUT ANY WARRANTY; without even the implied warranty of
41 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42 General Public License for more details.
43
44 You should have received copies of the GNU General Public License and
45 the GNU Lesser General Public License along with this program. If
46 not, see http://www.gnu.org/licenses/.
47 */
48
49 #define TABLE_INVALID -1
50 #define TABLE_SPACE -2
51 #define TABLE_END -3
52
53 void
54 base64_decode_init(struct base64_decode_ctx *ctx)
55 {
56 static const signed char base64_decode_table[0x100] =
57 {
58 /* White space is HT, VT, FF, CR, LF and SPC */
59 -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1,
60 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
62 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1,
63 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
64 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
65 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
66 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
67 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
68 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
69 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
70 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75 };
76
77 ctx->word = ctx->bits = ctx->padding = 0;
78 ctx->table = base64_decode_table;
79 }
80
81 int
82 base64_decode_single(struct base64_decode_ctx *ctx,
83 uint8_t *dst,
84 char src)
85 {
86 int data = ctx->table[(uint8_t) src];
87
88 switch(data)
89 {
90 default:
91 assert(data >= 0 && data < 0x40);
92
93 if (ctx->padding)
94 return -1;
95
96 ctx->word = ctx->word << 6 | data;
97 ctx->bits += 6;
98
99 if (ctx->bits >= 8)
100 {
101 ctx->bits -= 8;
102 dst[0] = ctx->word >> ctx->bits;
103 return 1;
104 }
105 else return 0;
106
107 case TABLE_INVALID:
108 return -1;
109
110 case TABLE_SPACE:
111 return 0;
112
113 case TABLE_END:
114 /* There can be at most two padding characters. */
115 if (!ctx->bits || ctx->padding > 2)
116 return -1;
117
118 if (ctx->word & ( (1<<ctx->bits) - 1))
119 /* We shouldn't have any leftover bits */
120 return -1;
121
122 ctx->padding++;
123 ctx->bits -= 2;
124 return 0;
125 }
126 }
127
128 int
129 base64_decode_update(struct base64_decode_ctx *ctx,
130 size_t *dst_length,
131 uint8_t *dst,
132 size_t src_length,
133 const char *src)
134 {
135 size_t done;
136 size_t i;
137
138 for (i = 0, done = 0; i<src_length; i++)
139 switch(base64_decode_single(ctx, dst + done, src[i]))
140 {
141 case -1:
142 return 0;
143 case 1:
144 done++;
145 /* Fall through */
146 case 0:
147 break;
148 default:
149 abort();
150 }
151
152 assert(done <= BASE64_DECODE_LENGTH(src_length));
153
154 *dst_length = done;
155 return 1;
156 }
157
158 int
159 base64_decode_final(struct base64_decode_ctx *ctx)
160 {
161 return ctx->bits == 0;
162 }
163
164 /* base64-encode.c */
165
166 #define ENCODE(alphabet,x) ((alphabet)[0x3F & (x)])
167
168 static void
169 encode_raw(const char *alphabet,
170 char *dst, size_t length, const uint8_t *src)
171 {
172 const uint8_t *in = src + length;
173 char *out = dst + BASE64_ENCODE_RAW_LENGTH(length);
174
175 unsigned left_over = length % 3;
176
177 if (left_over)
178 {
179 in -= left_over;
180 *--out = '=';
181 switch(left_over)
182 {
183 case 1:
184 *--out = '=';
185 *--out = ENCODE(alphabet, (in[0] << 4));
186 break;
187
188 case 2:
189 *--out = ENCODE(alphabet, (in[1] << 2));
190 *--out = ENCODE(alphabet, ((in[0] << 4) | (in[1] >> 4)));
191 break;
192
193 default:
194 abort();
195 }
196 *--out = ENCODE(alphabet, (in[0] >> 2));
197 }
198
199 while (in > src)
200 {
201 in -= 3;
202 *--out = ENCODE(alphabet, (in[2]));
203 *--out = ENCODE(alphabet, ((in[1] << 2) | (in[2] >> 6)));
204 *--out = ENCODE(alphabet, ((in[0] << 4) | (in[1] >> 4)));
205 *--out = ENCODE(alphabet, (in[0] >> 2));
206 }
207 assert(in == src);
208 assert(out == dst);
209 }
210
211 static const char base64_encode_table[64] =
212 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
213 "abcdefghijklmnopqrstuvwxyz"
214 "0123456789+/";
215
216 void
217 base64_encode_raw(char *dst, size_t length, const uint8_t *src)
218 {
219 encode_raw(base64_encode_table, dst, length, src);
220 }
221
222 void
223 base64_encode_group(char *dst, uint32_t group)
224 {
225 *dst++ = ENCODE(base64_encode_table, (group >> 18));
226 *dst++ = ENCODE(base64_encode_table, (group >> 12));
227 *dst++ = ENCODE(base64_encode_table, (group >> 6));
228 *dst++ = ENCODE(base64_encode_table, group);
229 }
230
231 void
232 base64_encode_init(struct base64_encode_ctx *ctx)
233 {
234 ctx->word = ctx->bits = 0;
235 ctx->alphabet = base64_encode_table;
236 }
237
238 /* Encodes a single byte. */
239 size_t
240 base64_encode_single(struct base64_encode_ctx *ctx,
241 char *dst,
242 uint8_t src)
243 {
244 unsigned done = 0;
245 unsigned word = ctx->word << 8 | src;
246 unsigned bits = ctx->bits + 8;
247
248 while (bits >= 6)
249 {
250 bits -= 6;
251 dst[done++] = ENCODE(ctx->alphabet, (word >> bits));
252 }
253
254 ctx->bits = bits;
255 ctx->word = word;
256
257 assert(done <= 2);
258
259 return done;
260 }
261
262 /* Returns the number of output characters. DST should point to an
263 * area of size at least BASE64_ENCODE_LENGTH(length). */
264 size_t
265 base64_encode_update(struct base64_encode_ctx *ctx,
266 char *dst,
267 size_t length,
268 const uint8_t *src)
269 {
270 size_t done = 0;
271 size_t left = length;
272 unsigned left_over;
273 size_t bulk;
274
275 while (ctx->bits && left)
276 {
277 left--;
278 done += base64_encode_single(ctx, dst + done, *src++);
279 }
280
281 left_over = left % 3;
282 bulk = left - left_over;
283
284 if (bulk)
285 {
286 assert(!(bulk % 3));
287
288 encode_raw(ctx->alphabet, dst + done, bulk, src);
289 done += BASE64_ENCODE_RAW_LENGTH(bulk);
290 src += bulk;
291 left = left_over;
292 }
293
294 while (left)
295 {
296 left--;
297 done += base64_encode_single(ctx, dst + done, *src++);
298 }
299
300 assert(done <= BASE64_ENCODE_LENGTH(length));
301
302 return done;
303 }
304
305 /* DST should point to an area of size at least
306 * BASE64_ENCODE_FINAL_SIZE */
307 size_t
308 base64_encode_final(struct base64_encode_ctx *ctx,
309 char *dst)
310 {
311 unsigned done = 0;
312 unsigned bits = ctx->bits;
313
314 if (bits)
315 {
316 dst[done++] = ENCODE(ctx->alphabet, (ctx->word << (6 - ctx->bits)));
317 for (; bits < 6; bits += 2)
318 dst[done++] = '=';
319
320 ctx->bits = 0;
321 }
322
323 assert(done <= BASE64_ENCODE_FINAL_LENGTH);
324 return done;
325 }
326
327 #endif /* !HAVE_NETTLE_BASE64_H || !HAVE_NETTLE34_BASE64 */
328