]>
Commit | Line | Data |
---|---|---|
0545caaa | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
0545caaa AJ |
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 | ||
836c3244 | 9 | /* |
aadbbd7d | 10 | * Copied from Nettle 3.0 under GPLv2, with adjustments |
836c3244 | 11 | */ |
164f7660 | 12 | |
f7f3304a | 13 | #include "squid.h" |
25f98340 | 14 | #include "base64.h" |
0c05d982 | 15 | |
f9ef3ed8 | 16 | #if !HAVE_NETTLE_BASE64_H || !HAVE_NETTLE30_BASE64 |
aadbbd7d | 17 | |
0c05d982 | 18 | #if HAVE_STDLIB_H |
19 | #include <stdlib.h> | |
20 | #endif | |
21 | ||
aadbbd7d AJ |
22 | static const uint8_t encode_table[64] = |
23 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
24 | "abcdefghijklmnopqrstuvwxyz" | |
25 | "0123456789+/"; | |
0673c0ba | 26 | |
aadbbd7d | 27 | #define ENCODE(x) (encode_table[0x3F & (x)]) |
0c05d982 | 28 | |
aadbbd7d | 29 | static const signed char decode_table[0x100] = |
0c05d982 | 30 | { |
aadbbd7d AJ |
31 | /* White space is HT, VT, FF, CR, LF and SPC */ |
32 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, | |
33 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
34 | -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, | |
35 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, | |
36 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
37 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, | |
38 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | |
39 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, | |
40 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
41 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
42 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
43 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
44 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
45 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
46 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
47 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
48 | }; | |
0c05d982 | 49 | |
aadbbd7d AJ |
50 | #define TABLE_INVALID -1 |
51 | #define TABLE_SPACE -2 | |
52 | #define TABLE_END -3 | |
0c05d982 | 53 | |
aadbbd7d AJ |
54 | #define BASE64_VALUE_SZ 256 |
55 | int base64_value[BASE64_VALUE_SZ]; | |
0c05d982 | 56 | |
aadbbd7d AJ |
57 | void |
58 | base64_decode_init(struct base64_decode_ctx *ctx) | |
59 | { | |
60 | ctx->word = ctx->bits = ctx->padding = 0; | |
0c05d982 | 61 | } |
62 | ||
aadbbd7d AJ |
63 | static int |
64 | base64_decode_single(struct base64_decode_ctx *ctx, uint8_t *dst, uint8_t src) | |
0c05d982 | 65 | { |
aadbbd7d AJ |
66 | int data = decode_table[src]; |
67 | ||
68 | switch(data) { | |
69 | default: | |
70 | assert(data >= 0 && data < 0x40); | |
71 | ||
72 | if (ctx->padding) | |
73 | return -1; | |
74 | ||
75 | ctx->word = ctx->word << 6 | data; | |
76 | ctx->bits += 6; | |
77 | ||
78 | if (ctx->bits >= 8) { | |
79 | ctx->bits -= 8; | |
80 | dst[0] = ctx->word >> ctx->bits; | |
81 | return 1; | |
82 | } else | |
83 | return 0; | |
84 | ||
85 | case TABLE_INVALID: | |
86 | return -1; | |
87 | ||
88 | case TABLE_SPACE: | |
8bdd0cec AJ |
89 | return 0; |
90 | ||
aadbbd7d AJ |
91 | case TABLE_END: |
92 | /* There can be at most two padding characters. */ | |
93 | if (!ctx->bits || ctx->padding > 2) | |
94 | return -1; | |
8bdd0cec | 95 | |
aadbbd7d AJ |
96 | if (ctx->word & ( (1<<ctx->bits) - 1)) |
97 | /* We shouldn't have any leftover bits */ | |
98 | return -1; | |
99 | ||
100 | ctx->padding++; | |
101 | ctx->bits -= 2; | |
102 | return 0; | |
8bdd0cec | 103 | } |
8bdd0cec AJ |
104 | } |
105 | ||
106 | int | |
aadbbd7d AJ |
107 | base64_decode_update(struct base64_decode_ctx *ctx, |
108 | size_t *dst_length, | |
109 | uint8_t *dst, | |
110 | size_t src_length, | |
111 | const uint8_t *src) | |
8bdd0cec | 112 | { |
aadbbd7d AJ |
113 | size_t done; |
114 | size_t i; | |
115 | ||
116 | for (i = 0, done = 0; i < src_length; i++) { | |
117 | switch(base64_decode_single(ctx, dst + done, src[i])) { | |
118 | case -1: | |
119 | return 0; | |
120 | case 1: | |
121 | done++; | |
122 | /* Fall through */ | |
123 | case 0: | |
124 | break; | |
125 | default: | |
126 | abort(); | |
8bdd0cec | 127 | } |
0c05d982 | 128 | } |
aadbbd7d AJ |
129 | |
130 | assert(done <= BASE64_DECODE_LENGTH(src_length)); | |
131 | ||
132 | *dst_length = done; | |
133 | return 1; | |
8bdd0cec AJ |
134 | } |
135 | ||
136 | int | |
aadbbd7d | 137 | base64_decode_final(struct base64_decode_ctx *ctx) |
8bdd0cec | 138 | { |
aadbbd7d | 139 | return ctx->bits == 0; |
0c05d982 | 140 | } |
f86a22c5 | 141 | |
aadbbd7d AJ |
142 | static void |
143 | base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src) | |
f86a22c5 | 144 | { |
aadbbd7d AJ |
145 | const uint8_t *in = src + length; |
146 | uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length); | |
147 | ||
148 | unsigned left_over = length % 3; | |
149 | ||
150 | if (left_over) { | |
151 | in -= left_over; | |
152 | *--out = '='; | |
153 | switch(left_over) { | |
154 | case 1: | |
155 | *--out = '='; | |
156 | *--out = ENCODE(in[0] << 4); | |
157 | break; | |
158 | ||
159 | case 2: | |
160 | *--out = ENCODE( in[1] << 2); | |
161 | *--out = ENCODE((in[0] << 4) | (in[1] >> 4)); | |
162 | break; | |
163 | ||
164 | default: | |
165 | abort(); | |
166 | } | |
167 | *--out = ENCODE(in[0] >> 2); | |
168 | } | |
169 | ||
170 | while (in > src) { | |
171 | in -= 3; | |
172 | *--out = ENCODE( in[2]); | |
173 | *--out = ENCODE((in[1] << 2) | (in[2] >> 6)); | |
174 | *--out = ENCODE((in[0] << 4) | (in[1] >> 4)); | |
175 | *--out = ENCODE( in[0] >> 2); | |
176 | } | |
177 | assert(in == src); | |
178 | assert(out == dst); | |
8bdd0cec | 179 | } |
f86a22c5 | 180 | |
aadbbd7d AJ |
181 | void |
182 | base64_encode_init(struct base64_encode_ctx *ctx) | |
8bdd0cec | 183 | { |
aadbbd7d | 184 | ctx->word = ctx->bits = 0; |
8bdd0cec | 185 | } |
f86a22c5 | 186 | |
aadbbd7d AJ |
187 | /* Encodes a single byte. */ |
188 | size_t | |
189 | base64_encode_single(struct base64_encode_ctx *ctx, | |
190 | uint8_t *dst, | |
191 | uint8_t src) | |
8bdd0cec | 192 | { |
aadbbd7d AJ |
193 | unsigned done = 0; |
194 | unsigned word = ctx->word << 8 | src; | |
195 | unsigned bits = ctx->bits + 8; | |
8bdd0cec | 196 | |
aadbbd7d AJ |
197 | while (bits >= 6) { |
198 | bits -= 6; | |
199 | dst[done++] = ENCODE(word >> bits); | |
f86a22c5 | 200 | } |
aadbbd7d AJ |
201 | |
202 | ctx->bits = bits; | |
203 | ctx->word = word; | |
204 | ||
205 | assert(done <= 2); | |
206 | ||
207 | return done; | |
f86a22c5 | 208 | } |
94439e4e | 209 | |
aadbbd7d AJ |
210 | /* Returns the number of output characters. DST should point to an |
211 | * area of size at least BASE64_ENCODE_LENGTH(length). */ | |
212 | size_t | |
213 | base64_encode_update(struct base64_encode_ctx *ctx, | |
214 | uint8_t *dst, | |
215 | size_t length, | |
216 | const uint8_t *src) | |
94439e4e | 217 | { |
aadbbd7d AJ |
218 | size_t done = 0; |
219 | size_t left = length; | |
220 | unsigned left_over; | |
221 | size_t bulk; | |
94439e4e | 222 | |
aadbbd7d AJ |
223 | while (ctx->bits && left) { |
224 | left--; | |
225 | done += base64_encode_single(ctx, dst + done, *src++); | |
226 | } | |
94439e4e | 227 | |
aadbbd7d AJ |
228 | left_over = left % 3; |
229 | bulk = left - left_over; | |
230 | ||
231 | if (bulk) { | |
232 | assert(!(bulk % 3)); | |
233 | ||
234 | base64_encode_raw(dst + done, bulk, src); | |
235 | done += BASE64_ENCODE_RAW_LENGTH(bulk); | |
236 | src += bulk; | |
237 | left = left_over; | |
94439e4e | 238 | } |
aadbbd7d AJ |
239 | |
240 | while (left) { | |
241 | left--; | |
242 | done += base64_encode_single(ctx, dst + done, *src++); | |
94439e4e | 243 | } |
aadbbd7d AJ |
244 | |
245 | assert(done <= BASE64_ENCODE_LENGTH(length)); | |
246 | ||
247 | return done; | |
94439e4e | 248 | } |
f53969cc | 249 | |
aadbbd7d AJ |
250 | /* DST should point to an area of size at least |
251 | * BASE64_ENCODE_FINAL_SIZE */ | |
252 | size_t | |
253 | base64_encode_final(struct base64_encode_ctx *ctx, | |
254 | uint8_t *dst) | |
255 | { | |
256 | unsigned done = 0; | |
257 | unsigned bits = ctx->bits; | |
258 | ||
259 | if (bits) { | |
260 | dst[done++] = ENCODE(ctx->word << (6 - ctx->bits)); | |
261 | for (; bits < 6; bits += 2) | |
262 | dst[done++] = '='; | |
263 | ||
264 | ctx->bits = 0; | |
265 | } | |
266 | ||
267 | assert(done <= BASE64_ENCODE_FINAL_LENGTH); | |
268 | return done; | |
269 | } | |
270 | ||
f9ef3ed8 | 271 | #endif /* !HAVE_NETTLE_BASE64_H || !HAVE_NETTLE30_BASE64 */ |
aadbbd7d | 272 |