OSDN Git Service

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