Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "sdp_base64.h"
6 :
7 : /*
8 : * Local definitions for Base64 to Raw table entries.
9 : */
10 : #define INVALID_CHAR 0xFF /* Character not in supported Base64 set */
11 : #define WHITE_SPACE 0xFE /* Space, tab, newline, etc character */
12 : #define PADDING 0xFD /* The character '=' */
13 :
14 : #define PAD_CHAR '=' /* The character '=' */
15 :
16 : /* Maximum length of a base64 encoded line */
17 : #define MAX_BASE64_LINE_LENGTH 76
18 :
19 : /*
20 : * base64_result_table
21 : * String table for translating base64 error codes into human
22 : * understanable strings.
23 : */
24 : char *base64_result_table[BASE64_RESULT_MAX] =
25 : {
26 : "Base64 successful",
27 : "Base64 Buffer Overrun",
28 : "Base64 Bad Data",
29 : "Base64 Bad Padding",
30 : "Base64 Bad Block Size"
31 : };
32 :
33 : /*
34 : * base64_to_raw_table
35 : * Heart of the Base64 decoding algorithm. Lookup table to convert
36 : * the Base64 characters into their specified representative values.
37 : * Invalid characters are marked with 0xFF, white space characters
38 : * are marked with 0xFE, and the special pading character is marked
39 : * with 0xFD.
40 : */
41 : unsigned char base64_to_raw_table[128] =
42 : {
43 : 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, /* 0-9 */
44 : 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-19 */
45 : 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 20-29 */
46 : 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 30-39 */
47 : 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63, 52, 53, /* 40-49 */
48 : 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, /* 50-59 */
49 : 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, /* 60-69 */
50 : 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70-79 */
51 : 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80-89 */
52 : 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26, 27, 28, /* 90-99 */
53 : 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */
54 : 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */
55 : 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* 120-127 */
56 : };
57 :
58 : unsigned char raw_to_base64_table[64] =
59 : {
60 : 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0-9 */
61 : 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */
62 : 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */
63 : 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */
64 : 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */
65 : 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */
66 : '8', '9', '+', '/' /* 60-63 */
67 : };
68 :
69 : /*
70 : * base64_encode_size_bytes
71 : *
72 : * DESCRIPTION
73 : * Estimates the size of buffer required for holding the result of
74 : * encoding data of size raw_size_bytes.
75 : *
76 : * PARAMETERS
77 : * raw_size_bytes = Estimated size of the un-encoded data in bytes.
78 : *
79 : * RETURN VALUE
80 : * The size of destination buffer to use for encoding in bytes.
81 : */
82 0 : int base64_est_encode_size_bytes (int raw_size_bytes)
83 : {
84 : int length;
85 :
86 : /*
87 : * Find the number of bytes needed to represent the data
88 : * using a 4/3 expansion ratio. That result must be
89 : * rounded to the next higher multiple of four to account
90 : * for padding. Then add in a term to account for any '\n's
91 : * added.
92 : */
93 0 : length = ((((raw_size_bytes * 4 + 2)/ 3) + 3) & ~(0x3)) +
94 0 : raw_size_bytes / MAX_BASE64_LINE_LENGTH;
95 :
96 0 : return length;
97 : }
98 :
99 : /*
100 : * base64_decode_size_bytes
101 : *
102 : * DESCRIPTION
103 : * Estimates the size of buffer required for holding the result of
104 : * decoding data of size base64_size_bytes.
105 : *
106 : * PARAMETERS
107 : * base64_size_bytes = Estimated size of the Base64 data in bytes.
108 : *
109 : * RETURN VALUE
110 : * The size of destination buffer to use for decoding in bytes.
111 : */
112 0 : int base64_est_decode_size_bytes (int base64_size_bytes)
113 : {
114 : int length;
115 :
116 0 : length = (base64_size_bytes * 3 + 3) / 4;
117 0 : return length;
118 : }
119 :
120 : /*
121 : * base64_encode
122 : *
123 : * DESCRIPTION
124 : * Encode data pointed to by src into the buffer pointer to by dest
125 : * using the Base64 algorithm.
126 : *
127 : * NOTE: No trailing '\n' character will be added.
128 : *
129 : * NOTE: As per specification, '\n' will be placed every 76 chars.
130 : *
131 : * PARAMETERS
132 : * src = Pointer to the raw data to base64 encode.
133 : * src_bytes = The number of bytes in the src buffer to encode.
134 : * dest = Pointer to the destination buffer where the converted data
135 : * will reside when complete.
136 : * dest_bytes = Initially holds the size of the destination buffer
137 : * but at completion holds the number of bytes converted.
138 : *
139 : * RETURN VALUE
140 : * base64_success if the buffer was successfully converted, the
141 : * appropriate error code otherwise.
142 : *
143 : * The dest parameter holds the converted data.
144 : *
145 : * The dest_bytes parameter holds the actual number of bytes converted.
146 : */
147 0 : base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
148 : {
149 0 : int i, j=0;
150 0 : int line_count = 0;
151 : unsigned char index; /* index into base64 lookup table */
152 0 : int smax = src_bytes-2; /* only do full multiples of 3 */
153 0 : int dmax = *dest_bytes; /* destination maximum */
154 :
155 0 : *dest_bytes = 0;
156 :
157 : /* Do full groups. Base64 must be done in blocks of 3 src bytes */
158 0 : for (i=0; i<smax; i+=3) {
159 : /* Check to see if newline should be injected */
160 0 : if (line_count>=MAX_BASE64_LINE_LENGTH) {
161 0 : if (j<dmax){
162 0 : dest[j++] = '\n';
163 : } else {
164 0 : return BASE64_BUFFER_OVERRUN;
165 : }
166 0 : line_count = 0;
167 : }
168 :
169 0 : line_count += 4;
170 :
171 0 : if ((j+3) < dmax) {
172 :
173 : /* Find mapping of upper 6 bits */
174 0 : index = (src[i] >> 2) & 0x3F;
175 0 : dest[j++] = raw_to_base64_table[index];
176 :
177 : /* bottom 2 bits of first word, high 4 bits of second word */
178 0 : index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
179 0 : dest[j++] = raw_to_base64_table[index];
180 :
181 : /* bottom 4 bits of second word, high 2 bits of third word */
182 0 : index = ((src[i+1] << 2) & 0x3C) | ((src[i+2] >> 6) & 0x03);
183 0 : dest[j++] = raw_to_base64_table[index];
184 :
185 : /* bottom 6 bits of third word */
186 0 : index = src[i+2] & 0x3F;
187 0 : dest[j++] = raw_to_base64_table[index];
188 : } else {
189 0 : return BASE64_BUFFER_OVERRUN;
190 : }
191 : }
192 :
193 : /* Check to see if any more work must be done */
194 0 : if (i<src_bytes) {
195 :
196 : /* Check to see if a newline should be output */
197 0 : if (line_count>=MAX_BASE64_LINE_LENGTH) {
198 0 : if (j<dmax){
199 0 : dest[j++] = '\n';
200 : } else {
201 0 : return BASE64_BUFFER_OVERRUN;
202 : }
203 0 : line_count = 0;
204 : }
205 :
206 0 : line_count += 4;
207 :
208 : /* Must fill another quantum */
209 0 : if (j+4>dmax) {
210 : /* No room left in output buffer! */
211 0 : return BASE64_BUFFER_OVERRUN;
212 : }
213 :
214 : /* Find mapping of upper 6 bits */
215 0 : index = (src[i] >> 2) & 0x3F;
216 0 : dest[j++] = raw_to_base64_table[index];
217 :
218 : /* check for another stragler */
219 0 : if ((i+1)<src_bytes) {
220 : /* bottom 2 bits of first word, high 4 bits of second word */
221 0 : index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F);
222 0 : dest[j++] = raw_to_base64_table[index];
223 :
224 : /* bottom 4 bits of second word */
225 0 : index = (src[i+1] << 2) & 0x3C;
226 0 : dest[j++] = raw_to_base64_table[index];
227 0 : dest[j++] = PAD_CHAR;
228 : } else {
229 : /* bottom 2 bits of first word */
230 0 : index = (src[i] << 4) & 0x30;
231 0 : dest[j++] = raw_to_base64_table[index];
232 0 : dest[j++] = PAD_CHAR;
233 0 : dest[j++] = PAD_CHAR;
234 : }
235 : }
236 :
237 0 : *dest_bytes = j;
238 :
239 0 : return BASE64_SUCCESS;
240 : }
241 :
242 : /*
243 : * base64_decode
244 : *
245 : * DESCRIPTION
246 : * Decode data pointed to by src into the buffer pointer to by dest
247 : * using the Base64 algorithm.
248 : *
249 : * PARAMETERS
250 : * src = Pointer to the Base64 data to decode.
251 : * src_bytes = The number of bytes in the src buffer to decode.
252 : * dest = Pointer to the destination buffer where the converted data
253 : * will reside when complete.
254 : * dest_bytes = Initially holds the size of the destination buffer
255 : * but at completion holds the number of bytes converted.
256 : *
257 : * RETURN VALUE
258 : * base64_success if the buffer was successfully converted, the
259 : * appropriate error code otherwise.
260 : *
261 : * The dest parameter holds the converted data.
262 : *
263 : * The dest_bytes parameter holds the actual number of bytes converted.
264 : */
265 0 : base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes)
266 : {
267 0 : int i, j = 0;
268 0 : int sindex = 0; /* Current NON-whitespace source
269 : * index */
270 0 : int pad_count=0; /* Number of padding characters
271 : * encountered */
272 0 : int dest_size_bytes = *dest_bytes; /* Save size of destination buffer */
273 : unsigned char cindex; /* The current Base64 character to
274 : * process */
275 : unsigned char val; /* The value of the current Base64
276 : * character */
277 :
278 0 : *dest_bytes = 0;
279 :
280 0 : for (i=0; i<src_bytes; i++) {
281 0 : cindex = src[i];
282 :
283 0 : if ((cindex & 0x80) || /* only have 128 values, MSB must not be set! */
284 0 : ((val = base64_to_raw_table[cindex]) == INVALID_CHAR)) {
285 : /* Invalid base64 character */
286 0 : return BASE64_BAD_DATA;
287 : }
288 :
289 0 : if (val == WHITE_SPACE) {
290 : /* Ignore white space */
291 0 : continue;
292 : }
293 :
294 0 : if (val == PADDING) {
295 : /* we must be at the end-finish up */
296 0 : pad_count++;
297 0 : if (++i<src_bytes) {
298 : /* can have up to 2 pad chars */
299 0 : if (base64_to_raw_table[src[i]] != PADDING) {
300 0 : return BASE64_BAD_PADDING;
301 : }
302 :
303 0 : if (++i<src_bytes) {
304 : /* should not have any more padding! */
305 0 : return BASE64_BAD_PADDING;
306 : }
307 :
308 0 : pad_count++;
309 : }
310 :
311 : /* DONE! */
312 0 : break;
313 : }
314 :
315 : /* Determine which portion of the 3 bytes this data will fill */
316 0 : switch (sindex & 0x3) {
317 : case 0:
318 : /* Fill upper 6 bits */
319 0 : if (j<dest_size_bytes) {
320 0 : dest[j] = val << 2;
321 : } else {
322 0 : return BASE64_BUFFER_OVERRUN;
323 : }
324 0 : break;
325 : case 1:
326 : /* Fill Bottom 2 bits */
327 0 : dest[j++] |= val >> 4;
328 :
329 0 : if (j<dest_size_bytes) {
330 : /* Fill Top 4 bits */
331 0 : dest[j] = (val << 4) & 0xF0;
332 : } else {
333 : /*
334 : * Check to see if there is any more data present.
335 : * Next base64 character MUST be a pad character and
336 : * the rest of this data MUST be zero.
337 : *
338 : * If this is not the end of data then a buffer overrun
339 : * has occurred
340 : */
341 0 : if ((val & 0x0F) ||
342 0 : (i+1>=src_bytes) ||
343 0 : (base64_to_raw_table[src[i+1]] != PADDING)) {
344 0 : return BASE64_BUFFER_OVERRUN;
345 : }
346 : }
347 0 : break;
348 : case 2:
349 : /* Fill Bottom 4 bits */
350 0 : dest[j++] |= val >> 2;
351 :
352 0 : if (j<dest_size_bytes) {
353 : /* Fill Top 2 bits */
354 0 : dest[j] = (val << 6) & 0xC0;
355 : } else {
356 : /*
357 : * Check to see if there is any more data present.
358 : * Next base64 character MUST be a pad character and
359 : * the rest of this data MUST be zero.
360 : *
361 : * If this is not the end of data then a buffer overrun
362 : * has occurred
363 : */
364 0 : if ((val & 0x03) ||
365 0 : (i+1>=src_bytes) ||
366 0 : (base64_to_raw_table[src[i+1]] != PADDING)) {
367 0 : return BASE64_BUFFER_OVERRUN;
368 : }
369 : }
370 0 : break;
371 : case 3:
372 : /*
373 : * No need to check for overrun here since the
374 : * previous case was already checked. If another
375 : * group is present then case 0 will check again.
376 : */
377 :
378 : /* Fill Bottom 6 bits */
379 0 : dest[j++] |= val;
380 0 : break;
381 : }
382 0 : sindex++;
383 : }
384 :
385 : /* Check length for multiple of 3 bytes */
386 0 : if (((j + pad_count)% 3) != 0) {
387 0 : return BASE64_BAD_BLOCK_SIZE;
388 : }
389 :
390 : /* Save off the number of bytes converted */
391 0 : *dest_bytes = j;
392 :
393 0 : return BASE64_SUCCESS;
394 : }
|