Added SILC Thread Queue API
[silc.git] / lib / silcutil / silcbase64.c
1 /*
2
3   silcbase64.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21
22 static unsigned char pem_enc[64] =
23 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
24
25 /* Encodes data into Base 64 encoding. Returns NULL terminated base 64 encoded
26    data string. */
27
28 char *silc_base64_encode(SilcStack stack, unsigned char *data, SilcUInt32 len)
29 {
30   int i, j;
31   SilcUInt32 bits, c, char_count;
32   char *pem;
33
34   char_count = 0;
35   bits = 0;
36   j = 0;
37
38   pem = silc_scalloc(stack, ((len * 8 + 5) / 6) + 5, sizeof(*pem));
39   if (!pem)
40     return NULL;
41
42   for (i = 0; i < len; i++) {
43     c = data[i];
44     bits += c;
45     char_count++;
46
47     if (char_count == 3) {
48       pem[j++] = pem_enc[bits  >> 18];
49       pem[j++] = pem_enc[(bits >> 12) & 0x3f];
50       pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
51       pem[j++] = pem_enc[bits & 0x3f];
52       bits = 0;
53       char_count = 0;
54     } else {
55       bits <<= 8;
56     }
57   }
58
59   if (char_count != 0) {
60     bits <<= 16 - (8 * char_count);
61     pem[j++] = pem_enc[bits >> 18];
62     pem[j++] = pem_enc[(bits >> 12) & 0x3f];
63
64     if (char_count == 1) {
65       pem[j++] = '=';
66       pem[j] = '=';
67     } else {
68       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
69       pem[j] = '=';
70     }
71   }
72
73   return pem;
74 }
75
76 /* Same as above but puts newline ('\n') every 72 characters. */
77
78 char *silc_base64_encode_file(SilcStack stack,
79                               unsigned char *data, SilcUInt32 data_len)
80 {
81   int i, j;
82   SilcUInt32 len, cols;
83   char *pem, *pem2;
84
85   pem = silc_base64_encode(stack, data, data_len);
86   len = strlen(pem);
87
88   pem2 = silc_scalloc(stack, len + (len / 72) + 1, sizeof(*pem2));
89
90   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
91     if (cols == 72) {
92       pem2[i] = '\n';
93       cols = 0;
94       len++;
95       continue;
96     }
97
98     pem2[i] = pem[j++];
99   }
100
101   silc_sfree(stack, pem);
102   return pem2;
103 }
104
105 /* Decodes Base 64 into data. Returns the decoded data. */
106
107 unsigned char *silc_base64_decode(SilcStack stack,
108                                   unsigned char *base64,
109                                   SilcUInt32 base64_len,
110                                   SilcUInt32 *ret_len)
111 {
112   int i, j;
113   SilcUInt32 len, c, char_count, bits;
114   unsigned char *data;
115   static char ialpha[256], decoder[256];
116
117   for (i = 64 - 1; i >= 0; i--) {
118     ialpha[pem_enc[i]] = 1;
119     decoder[pem_enc[i]] = i;
120   }
121
122   char_count = 0;
123   bits = 0;
124   j = 0;
125
126   if (!base64_len)
127     len = strlen(base64);
128   else
129     len = base64_len;
130
131   data = silc_scalloc(stack, ((len * 6) / 8), sizeof(*data));
132   if (!data)
133     return NULL;
134
135   for (i = 0; i < len; i++) {
136     c = base64[i];
137
138     if (c == '=')
139       break;
140
141     if (c > 127 || !ialpha[c])
142       continue;
143
144     bits += decoder[c];
145     char_count++;
146
147     if (char_count == 4) {
148       data[j++] = bits >> 16;
149       data[j++] = (bits >> 8) & 0xff;
150       data[j++] = bits & 0xff;
151       bits = 0;
152       char_count = 0;
153     } else {
154       bits <<= 6;
155     }
156   }
157
158   switch (char_count) {
159   case 1:
160     silc_sfree(stack, data);
161     silc_set_errno(SILC_ERR_BAD_ENCODING);
162     return NULL;
163     break;
164   case 2:
165     data[j++] = bits >> 10;
166     break;
167   case 3:
168     data[j++] = bits >> 16;
169     data[j++] = (bits >> 8) & 0xff;
170     break;
171   }
172
173   if (ret_len)
174     *ret_len = j;
175
176   return data;
177 }