OSDN Git Service

deleted ASSERTs and added many checks, also cleanup the codes
[openpts/openpts.git] / src / base64.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/base64.c
26  * \brief Base64 Encode/Decode
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-04-01
29  * cleanup 2011-12-31 SM
30  *
31  * http://en.wikipedia.org/wiki/Base64
32  *
33  * 2011-08-17 SM - encodebase64 & decodeBase64  - alloc output buffer
34  * 2011-08-21 SM - remove _removeCR() and malloc
35  * 2011-08-21 SM - check bad string in BASE64 msg.
36  *
37  */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include <openpts.h>
44
45 /**
46  * calc base64 size
47  *
48  * string(or binary data) => base64 string + 1
49  * Output is actual string size + 1 (for \0)
50  */
51 int _sizeofBase64Encode(int len) {
52     /* check */
53     if (len <  0) return 0;
54     if (len == 0) return 1;
55
56     return (len + 2 - ((len + 2) % 3)) * 4 / 3 + 1;
57 }
58
59 int getDecodedBase64Size(unsigned char *in, int inLen) {
60     int inCount;
61     int outCount;
62
63     /* check */
64     if (in == NULL) {
65         ERROR("null input");
66         return 0;
67     }
68
69     inCount = inLen / 4;
70     if (inCount > 0) {
71         --inCount;
72     }
73     outCount = inCount * 3;
74     inCount *= 4;
75
76     if ( in[inCount+1] == '=' ) {
77         outCount += 1;
78     } else if ( in[inCount+2] == '=' ) {
79         outCount += 1;
80     } else if ( in[inCount+3] == '=' ) {
81         outCount += 2;
82     } else {
83         outCount += 3;
84     }
85
86     return outCount;
87 }
88
89 /**
90  * calc original data size from base64 string size
91  *
92  * This is rough estimation.
93  * Output is actual string size (+1 or +2) + 1 (for \0)
94  *
95  */
96 int _sizeofBase64Decode(int len) {
97     /* check */
98     if (len <  0) return 0;
99     if (len == 0) return 1;
100
101     return (len / 4 * 3) + 1;
102 }
103
104
105 /**
106  * Encode BYTE[] to Base64 string
107  * Return
108  *   count
109  *   -1    ERROR
110  */
111 int _encodeBase64(char *out, unsigned char * in, int len) {
112     int ptr1 = 0;
113     int ptr2 = 0;
114
115     /* */
116     static unsigned char transTable[64] = {
117          /* 41h - */
118          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
119          /* - 5Ah */
120          'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
121          /* 61h - */
122          'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
123          /* - 7Ah */
124          'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
125          /* 30h - 39h, 2Bh, 2Fh */
126          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
127          };
128
129     /* check */
130     if (out == NULL) {
131         ERROR("null input\n");
132         return -1;
133     }
134     if (len == 0) {
135         out[0] = 0;
136         return 0;
137     }
138     if (in == NULL) {
139         ERROR("null input");
140         return 0;
141     }
142
143     /* Trans */
144
145     while (1) {
146         if ( len >= 3 ) {
147             out[ptr2  ] = transTable[   in[ptr1  ] >>2];
148             out[ptr2+1] = transTable[ ((in[ptr1  ]&0x03) <<4 |
149                                        (in[ptr1+1]&0xF0) >> 4) ];
150             out[ptr2+2] = transTable[ ((in[ptr1+1]&0x0F) <<2 |
151                                        (in[ptr1+2]&0xC0) >> 6) ];
152             out[ptr2+3] = transTable[  (in[ptr1+2]&0x3F) ];
153             len -= 3;
154             ptr1 += 3;
155             ptr2 += 4;
156         } else if ( len == 2 ) {
157             out[ptr2  ] = transTable[   in[ptr1  ] >>2];
158             out[ptr2+1] = transTable[ ((in[ptr1  ]&0x03) <<4 |
159                                        (in[ptr1+1]&0xF0) >> 4) ];
160             out[ptr2+2] = transTable[  (in[ptr1+1]&0x0F) <<2 ];
161             out[ptr2+3] = '=';
162             ptr2 += 4;
163             break;
164         } else if ( len == 1 ) {
165             out[ptr2  ] = transTable[  in[ptr1  ] >>2];
166             out[ptr2+1] = transTable[ (in[ptr1  ]&0x03) <<4 ];
167             out[ptr2+2] = '=';
168             out[ptr2+3] = '=';
169             ptr2 += 4;
170             break;
171         } else {
172             break;
173         }
174     }
175
176     /* add \0 at the end of buffer */
177     out[ptr2] = 0;
178
179     return ptr2;
180 }
181 /**
182  * Encode BYTE[] to Base64 string
183  *
184  * @param  *in     buffer of input data
185  * @param  inlen   length
186  * @raram  *outlen size of output
187  * @return *out    Base64 string, malloc new buffer
188  */
189 char *encodeBase64(unsigned char * in, int inlen, int *outlen) {
190     char *out;
191     int len2;
192
193     /* check */
194     if (in == NULL) {
195         ERROR("null input\n");
196         return NULL;
197     }
198
199     *outlen = _sizeofBase64Encode(inlen);
200     out = (char *) xmalloc_assert(*outlen);
201     if (out == NULL) {
202         ERROR("no memory");
203         *outlen = 0;
204         return NULL;
205     }
206     memset(out, 0, *outlen);
207
208     len2 = _encodeBase64(out, in, inlen);
209     if (len2 > *outlen) {
210         ERROR("fatal error");
211         xfree(out);
212         *outlen = 0;
213         return NULL;
214     }
215
216     return out;
217 }
218
219
220 /**
221   * trans (do not check the bad input)
222   */
223 unsigned char _b64trans(unsigned char in) {
224     if (in == '+') return 62;
225     if (in == '/') return 63;
226     if (in >= 'a') return (in-'a' + 26);
227     if (in >= 'A') return (in-'A');
228     if (in >= '0') return (in-'0' + 52);
229     return 0xFF;
230 }
231
232 /**
233  * string length without space at the end
234  *
235  * 2011-11-30 Munetoh - fixed to skip the char in the middle of string
236  */
237 int _strippedlength(char * in, int len) {
238     int skip = 0;
239     int i;
240
241     /* check */
242     if (in == NULL) {
243         ERROR("null input\n");
244         return -1;
245     }
246
247     /* last char */
248     i = len - 1;
249
250     while(i > 0) {
251         if (in[i] == '\n') {
252             /* skip */
253             skip++;
254         } else if (in[i] == ' ') {
255             /* skip */
256             skip++;
257         }
258         i = i - 1;
259     }
260
261     return len - skip;
262 }
263
264
265
266 /**
267   * Decode Base64 string to BYTE[]
268   *
269   * caller must provide the buffer
270   *
271   * return size of BYTE[] array
272   */
273 int _decodeBase64(unsigned char *out, char * in, int len) {
274     int ptr1 = 0;  // in
275     int ptr2 = 0;  // out
276     int len2;
277     char * in2;
278     char inbuf[4];
279     int i, j;
280     int skip;
281
282     /* check */
283     if (out == NULL) {
284         ERROR("decodeBase64core - out is NULL\n");
285         return -1;
286     }
287     /* null input? */
288     if (in == NULL) {
289         ERROR("decodeBase64core - in is NULL\n");
290         return -1;
291     }
292     /* in[0] => out[0]=\0 */
293     if (len == 0) {
294         out[0] = 0;
295         return 0;
296     }
297
298     len2 = _strippedlength(in, len);
299     in2 = in;
300
301     /* Trans */
302     while (1) {
303         /* check remain buffer size >= 4 */
304         if (len2 < 4) {
305             ERROR("bad base64 data size");
306             goto error;
307         }
308         /* remove CR and Space and check bad string */
309         j = 0;
310         skip = 0;
311         for (i = ptr1; j < 4 ; i++) {
312             if (in2[i] == '\n') {
313                 /* skip */
314                 skip++;
315             } else if (in2[i] == ' ') {
316                 /* skip */
317                 skip++;
318             } else {
319                 if ((in2[i] == 0x2B) ||
320                    (in2[i] == 0x2F) ||
321                    (in2[i] == 0x3D) ||
322                    ((0x30 <= in2[i]) && (in2[i] <= 0x39)) ||
323                    ((0x41 <= in2[i]) && (in2[i] <= 0x5A)) ||
324                    ((0x61 <= in2[i]) && (in2[i] <= 0x7A))) {
325                     /* valid data */
326                     inbuf[j]=in2[i];
327                     j++;
328                 } else {
329                     /* BAD BASE64 String */
330                     ERROR("bad base64 data string, 0x%0x", in2[i]);
331                     goto error;
332                 }
333             }
334         }
335         /* BASE64 -> Plain */
336         if (len2 > 4) {
337             out[ptr2  ] =  (_b64trans(inbuf[0])       << 2) |
338                            (_b64trans(inbuf[1]) >> 4);
339             out[ptr2+1] = ((_b64trans(inbuf[1])&0x0F) << 4) |
340                            (_b64trans(inbuf[2]) >> 2);
341             out[ptr2+2] = ((_b64trans(inbuf[2])&0x03) << 6) |
342                             _b64trans(inbuf[3]);
343             len2 -= 4; // skip chars has been removed in len2
344             ptr1 += 4 + skip;
345             ptr2 += 3;
346         } else if ( inbuf[1] == '=' ) {
347             out[ptr2  ] = _b64trans(inbuf[0])      << 2;
348             ptr2 += 1;
349             break;
350         } else if ( inbuf[2] == '=' ) {
351             out[ptr2  ] = (_b64trans(inbuf[0]) << 2) |
352                           (_b64trans(inbuf[1]) >> 4);
353             ptr2 += 1;
354             break;
355         } else if ( inbuf[3] == '=' ) {
356             out[ptr2  ] =  (_b64trans(inbuf[0])       << 2) |
357                            (_b64trans(inbuf[1]) >> 4);
358             out[ptr2+1] = ((_b64trans(inbuf[1])&0x0F) << 4) |
359                            (_b64trans(inbuf[2]) >> 2);
360             ptr2 += 2;
361             break;
362         } else {
363             out[ptr2  ] =  (_b64trans(inbuf[0])       << 2) |
364                            (_b64trans(inbuf[1]) >> 4);
365             out[ptr2+1] = ((_b64trans(inbuf[1])&0x0F) << 4) |
366                            (_b64trans(inbuf[2]) >> 2);
367             out[ptr2+2] = ((_b64trans(inbuf[2])&0x03) << 6) |
368                             _b64trans(inbuf[3]);
369             ptr2 += 3;
370             break;
371         }
372     }
373
374     /* Anyway, add \0 at the end of buffer */
375     out[ptr2] = 0;
376
377     return ptr2;
378
379   error:
380     return -1;
381 }
382
383
384 /**
385  * Decode Base64(with CRLF) string to BYTE[]
386  *
387  * @param  *in     buffer of base64 string
388  * @param  inlen   length
389  * @raram  *outlen size of BYTE[] array from base64 string, malloced size is bigger then this
390  * @return *out    malloc new buffer
391  */
392 unsigned char *decodeBase64(char * in, int inlen, int *outlen) {
393     unsigned char *out;
394     int len1;
395     int len2;
396
397     /* check */
398     if (in == NULL) {
399         ERROR("null input\n");
400         return NULL;
401     }
402
403     len1 = _sizeofBase64Decode(inlen);
404     out = (unsigned char *) xmalloc_assert(len1);
405     if (out == NULL) {
406         ERROR("no memory");
407         *outlen = 0;
408         return NULL;
409     }
410     memset(out, 0, len1);
411
412     len2 = _decodeBase64(out, in, inlen);
413     if (len2 < 0) {
414         ERROR("fatal error");
415         xfree(out);
416         *outlen = 0;
417         return NULL;
418     }
419
420     /* return actial data size created from base64 */
421     *outlen = len2;
422
423     return out;
424 }