OSDN Git Service

cleanup
[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 2012-01-05 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         LOG(LOG_ERR, "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  * Encode BYTE[] to Base64 string
106  * Return
107  *   count
108  *   -1    ERROR
109  */
110 int _encodeBase64(char *out, unsigned char * in, int len) {
111     int ptr1 = 0;
112     int ptr2 = 0;
113
114     /* */
115     static unsigned char transTable[64] = {
116          /* 41h - */
117          'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
118          /* - 5Ah */
119          'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
120          /* 61h - */
121          'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
122          /* - 7Ah */
123          'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
124          /* 30h - 39h, 2Bh, 2Fh */
125          '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
126          };
127
128     /* check */
129     if (out == NULL) {
130         LOG(LOG_ERR, "null input\n");
131         return -1;
132     }
133     if (len == 0) {
134         out[0] = 0;
135         return 0;
136     }
137     if (in == NULL) {
138         LOG(LOG_ERR, "null input");
139         return 0;
140     }
141
142     /* Trans */
143     while (1) {
144         if ( len >= 3 ) {
145             out[ptr2  ] = transTable[   in[ptr1  ] >>2];
146             out[ptr2+1] = transTable[ ((in[ptr1  ]&0x03) <<4 |
147                                        (in[ptr1+1]&0xF0) >> 4) ];
148             out[ptr2+2] = transTable[ ((in[ptr1+1]&0x0F) <<2 |
149                                        (in[ptr1+2]&0xC0) >> 6) ];
150             out[ptr2+3] = transTable[  (in[ptr1+2]&0x3F) ];
151             len -= 3;
152             ptr1 += 3;
153             ptr2 += 4;
154         } else if ( len == 2 ) {
155             out[ptr2  ] = transTable[   in[ptr1  ] >>2];
156             out[ptr2+1] = transTable[ ((in[ptr1  ]&0x03) <<4 |
157                                        (in[ptr1+1]&0xF0) >> 4) ];
158             out[ptr2+2] = transTable[  (in[ptr1+1]&0x0F) <<2 ];
159             out[ptr2+3] = '=';
160             ptr2 += 4;
161             break;
162         } else if ( len == 1 ) {
163             out[ptr2  ] = transTable[  in[ptr1  ] >>2];
164             out[ptr2+1] = transTable[ (in[ptr1  ]&0x03) <<4 ];
165             out[ptr2+2] = '=';
166             out[ptr2+3] = '=';
167             ptr2 += 4;
168             break;
169         } else {
170             break;
171         }
172     }
173
174     /* add \0 at the end of buffer */
175     out[ptr2] = 0;
176
177     return ptr2;
178 }
179 /**
180  * Encode BYTE[] to Base64 string
181  *
182  * @param  *in     buffer of input data
183  * @param  inlen   length
184  * @raram  *outlen size of output
185  * @return *out    Base64 string, malloc new buffer
186  */
187 char *encodeBase64(unsigned char * in, int inlen, int *outlen) {
188     char *out;
189     int len2;
190
191     /* check */
192     if (in == NULL) {
193         LOG(LOG_ERR, "null input\n");
194         return NULL;
195     }
196
197     *outlen = _sizeofBase64Encode(inlen);
198     out = (char *) xmalloc_assert(*outlen);
199     if (out == NULL) {
200         LOG(LOG_ERR, "no memory");
201         *outlen = 0;
202         return NULL;
203     }
204     memset(out, 0, *outlen);
205
206     len2 = _encodeBase64(out, in, inlen);
207     if (len2 > *outlen) {
208         LOG(LOG_ERR, "fatal error");
209         xfree(out);
210         *outlen = 0;
211         return NULL;
212     }
213
214     return out;
215 }
216
217 /**
218   * trans (do not check the bad input)
219   */
220 unsigned char _b64trans(unsigned char in) {
221     if (in == '+') return 62;
222     if (in == '/') return 63;
223     if (in >= 'a') return (in-'a' + 26);
224     if (in >= 'A') return (in-'A');
225     if (in >= '0') return (in-'0' + 52);
226     return 0xFF;
227 }
228
229 /**
230  * string length without space at the end
231  *
232  * 2011-11-30 Munetoh - fixed to skip the char in the middle of string
233  */
234 int _strippedlength(char * in, int len) {
235     int skip = 0;
236     int i;
237
238     /* check */
239     if (in == NULL) {
240         LOG(LOG_ERR, "null input\n");
241         return -1;
242     }
243
244     /* last char */
245     i = len - 1;
246
247     while (i > 0) {
248         if (in[i] == '\n') {
249             /* skip */
250             skip++;
251         } else if (in[i] == ' ') {
252             /* skip */
253             skip++;
254         }
255         i = i - 1;
256     }
257
258     return len - skip;
259 }
260
261
262
263 /**
264   * Decode Base64 string to BYTE[]
265   *
266   * caller must provide the buffer
267   *
268   * return size of BYTE[] array
269   */
270 int _decodeBase64(unsigned char *out, char * in, int len) {
271     int ptr1 = 0;  // in
272     int ptr2 = 0;  // out
273     int len2;
274     char * in2;
275     char inbuf[4];
276     int i, j;
277     int skip;
278
279     /* check */
280     if (out == NULL) {
281         LOG(LOG_ERR, "decodeBase64core - out is NULL\n");
282         return -1;
283     }
284     /* null input? */
285     if (in == NULL) {
286         LOG(LOG_ERR, "decodeBase64core - in is NULL\n");
287         return -1;
288     }
289     /* in[0] => out[0]=\0 */
290     if (len == 0) {
291         out[0] = 0;
292         return 0;
293     }
294
295     len2 = _strippedlength(in, len);
296     in2 = in;
297
298     /* Trans */
299     while (1) {
300         /* check remain buffer size >= 4 */
301         if (len2 < 4) {
302             LOG(LOG_ERR, "bad base64 data size");
303             goto error;
304         }
305         /* remove CR and Space and check bad string */
306         j = 0;
307         skip = 0;
308         for (i = ptr1; j < 4 ; i++) {
309             if (in2[i] == '\n') {
310                 /* skip */
311                 skip++;
312             } else if (in2[i] == ' ') {
313                 /* skip */
314                 skip++;
315             } else {
316                 if ((in2[i] == 0x2B) ||
317                    (in2[i] == 0x2F) ||
318                    (in2[i] == 0x3D) ||
319                    ((0x30 <= in2[i]) && (in2[i] <= 0x39)) ||
320                    ((0x41 <= in2[i]) && (in2[i] <= 0x5A)) ||
321                    ((0x61 <= in2[i]) && (in2[i] <= 0x7A))) {
322                     /* valid data */
323                     inbuf[j]=in2[i];
324                     j++;
325                 } else {
326                     /* BAD BASE64 String */
327                     LOG(LOG_ERR, "bad base64 data string, 0x%0x", in2[i]);
328                     goto error;
329                 }
330             }
331         }
332         /* BASE64 -> Plain */
333         if (len2 > 4) {
334             out[ptr2  ] =  (_b64trans(inbuf[0])       << 2) |
335                            (_b64trans(inbuf[1]) >> 4);
336             out[ptr2+1] = ((_b64trans(inbuf[1])&0x0F) << 4) |
337                            (_b64trans(inbuf[2]) >> 2);
338             out[ptr2+2] = ((_b64trans(inbuf[2])&0x03) << 6) |
339                             _b64trans(inbuf[3]);
340             len2 -= 4;  // skip chars has been removed in len2
341             ptr1 += 4 + skip;
342             ptr2 += 3;
343         } else if ( inbuf[1] == '=' ) {
344             out[ptr2  ] = _b64trans(inbuf[0])      << 2;
345             ptr2 += 1;
346             break;
347         } else if ( inbuf[2] == '=' ) {
348             out[ptr2  ] = (_b64trans(inbuf[0]) << 2) |
349                           (_b64trans(inbuf[1]) >> 4);
350             ptr2 += 1;
351             break;
352         } else if ( inbuf[3] == '=' ) {
353             out[ptr2  ] =  (_b64trans(inbuf[0])       << 2) |
354                            (_b64trans(inbuf[1]) >> 4);
355             out[ptr2+1] = ((_b64trans(inbuf[1])&0x0F) << 4) |
356                            (_b64trans(inbuf[2]) >> 2);
357             ptr2 += 2;
358             break;
359         } else {
360             out[ptr2  ] =  (_b64trans(inbuf[0])       << 2) |
361                            (_b64trans(inbuf[1]) >> 4);
362             out[ptr2+1] = ((_b64trans(inbuf[1])&0x0F) << 4) |
363                            (_b64trans(inbuf[2]) >> 2);
364             out[ptr2+2] = ((_b64trans(inbuf[2])&0x03) << 6) |
365                             _b64trans(inbuf[3]);
366             ptr2 += 3;
367             break;
368         }
369     }
370
371     /* Anyway, add \0 at the end of buffer */
372     out[ptr2] = 0;
373
374     return ptr2;
375
376   error:
377     return -1;
378 }
379
380
381 /**
382  * Decode Base64(with CRLF) string to BYTE[]
383  *
384  * @param  *in     buffer of base64 string
385  * @param  inlen   length
386  * @raram  *outlen size of BYTE[] array from base64 string, malloced size is bigger then this
387  * @return *out    malloc new buffer
388  */
389 unsigned char *decodeBase64(char * in, int inlen, int *outlen) {
390     unsigned char *out;
391     int len1;
392     int len2;
393
394     /* check */
395     if (in == NULL) {
396         LOG(LOG_ERR, "null input\n");
397         return NULL;
398     }
399
400     len1 = _sizeofBase64Decode(inlen);
401     out = (unsigned char *) xmalloc_assert(len1);
402     if (out == NULL) {
403         LOG(LOG_ERR, "no memory");
404         *outlen = 0;
405         return NULL;
406     }
407     memset(out, 0, len1);
408
409     len2 = _decodeBase64(out, in, inlen);
410     if (len2 < 0) {
411         LOG(LOG_ERR, "fatal error");
412         xfree(out);
413         *outlen = 0;
414         return NULL;
415     }
416
417     /* return actial data size created from base64 */
418     *outlen = len2;
419
420     return out;
421 }