d500eaada102f7327fdf760e5c53cd6695f69b81
[src/app-framework-main.git] / src / wgtpkg-base64.c
1 /*
2  Copyright 2015, 2016, 2017 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "verbose.h"
24 #include "wgtpkg-base64.h"
25
26 static char tob64(char x)
27 {
28         if (x < 26)
29                 return (char)('A' + x);
30         if (x < 52)
31                 return (char)('a' + x - 26);
32         if (x < 62)
33                 return (char)('0' + x - 52);
34         return x == 62 ? '+' : '/';
35 }
36
37 char *base64encw(const char *buffer, size_t length, unsigned width)
38 {
39         size_t remain, in, out;
40         char *result;
41
42         if (width == 0 || (width & 3) != 0) {
43                 ERROR("bad width in base64enc");
44                 return NULL;
45         }
46         result = malloc(2 + 4 * ((length + 2) / 3) + (length / width));
47         if (result == NULL) {
48                 ERROR("malloc failed in base64enc");
49                 return NULL;
50         }
51         in = out = 0;
52         remain = length;
53         while (remain >= 3) {
54                 if (out % (width + 1) == width)
55                         result[out++] = '\n'; 
56                 result[out] = tob64((buffer[in] >> 2) & '\x3f');
57                 result[out+1] = tob64((char)(((buffer[in] << 4) & '\x30')
58                                         | ((buffer[in+1] >> 4) & '\x0f')));
59                 result[out+2] = tob64((char)(((buffer[in+1] << 2) & '\x3c')
60                                         | ((buffer[in+2] >> 6) & '\x03')));
61                 result[out+3] = tob64(buffer[in+2] & '\x3f');
62                 remain -= 3;
63                 in += 3;
64                 out += 4;
65         }
66         if (remain != 0) {
67                 if (out % (width + 1) == width)
68                         result[out++] = '\n'; 
69                 result[out] = tob64((buffer[in] >> 2) & '\x3f');
70                 if (remain == 1) {
71                         result[out+1] = tob64((buffer[in] << 4) & '\x30');
72                         result[out+2] = '=';
73                 } else {
74                         result[out+1] = tob64((char)(((buffer[in] << 4) & '\x30')
75                                                 | ((buffer[in+1] >> 4) & '\x0f')));
76                         result[out+2] = tob64((buffer[in+1] << 2) & '\x3c');
77                 }
78                 result[out+3] = '=';
79                 out += 4;
80         }
81         result[out] = 0;
82         return result;
83 }
84
85 char *base64enc(const char *buffer, size_t length)
86 {
87         return base64encw(buffer, length, 76);
88 }
89
90 static char fromb64(char x)
91 {
92         if ('A' <= x && x <= 'Z')
93                 return (char)(x - 'A');
94         if ('a' <= x && x <= 'z')
95                 return (char)(x - 'a' + 26);
96         if ('0' <= x && x <= '9')
97                 return (char)(x - '0' + 52);
98         if (x == '+')
99                 return (char)62;
100         if (x == '/')
101                 return (char)63;
102         if (x == '=')
103                 return '@';
104         return 'E';
105 }
106
107 ssize_t base64dec(const char *buffer, char **output)
108 {
109         size_t len, in;
110         ssize_t out;
111         char *result;
112         unsigned char x0, x1, x2, x3;
113
114         len = strlen(buffer);
115         result = malloc(3 * ((3 + len) / 4));
116         if (result == NULL) {
117                 ERROR("malloc failed in base64dec");
118                 return -1;
119         }
120         in = 0;
121         out = 0;
122         while (buffer[in] == '\r' || buffer[in] == '\n')
123                 in++;
124         while (buffer[in]) {
125                 if (in + 4 > len) {
126                         ERROR("unexpected input size in base64dec");
127                         free(result);
128                         return -1;
129                 }
130                 x0 = (unsigned char)fromb64(buffer[in]);
131                 x1 = (unsigned char)fromb64(buffer[in+1]);
132                 x2 = (unsigned char)fromb64(buffer[in+2]);
133                 x3 = (unsigned char)fromb64(buffer[in+3]);
134                 in += 4;
135                 if (x0 == 'E' || x1 == 'E' || x2 == 'E' || x3 == 'E') {
136                         ERROR("unexpected input character in base64dec");
137                         free(result);
138                         return -1;
139                 }
140                 if (x0 == '@' || x1 == '@' || (x2 == '@' && x3 != '@')) {
141                         ERROR("unexpected termination character in base64dec");
142                         free(result);
143                         return -1;
144                 }
145                 result[out] = (char)((x0 << 2) | (x1 >> 4));
146                 result[out+1] = (char)((x1 << 4) | ((x2 >> 2) & 15));
147                 result[out+2] = (char)((x2 << 6) | (x3 & 63));
148                 while (buffer[in] == '\r' || buffer[in] == '\n')
149                         in++;
150                 if (x3 != '@')
151                         out += 3;
152                 else if (!buffer[in])
153                         out += 1 + (unsigned)(x2 != '@');
154                 else {
155                         ERROR("unexpected continuation in base64dec");
156                         free(result);
157                         return -1;
158                 }
159                 if (out < 0) {
160                         ERROR("output too big in base64dec");
161                         free(result);
162                         return -1;
163                 }
164         }
165         *output = result;
166         return out;
167 }
168
169 int base64eq(const char *buf1, const char *buf2)
170 {
171         for(;;) {
172                 while(*buf1 == '\n' || *buf1 == '\r')
173                         buf1++;
174                 while(*buf2 == '\n' || *buf2 == '\r')
175                         buf2++;
176                 if (*buf1 != *buf2)
177                         return 0;
178                 if (!*buf1)
179                         return 1;
180                 buf1++;
181                 buf2++;
182         }
183 }
184
185 #ifdef TESTBASE64
186 #include <fcntl.h>
187 #include <string.h>
188
189 int main(int ac, char **av)
190 {
191         char buffer[32768];
192         int fd, l0, l1, l2;
193         char *p1, *p2;
194
195         while(*++av) {
196                 fd = open(*av, O_RDONLY);
197                 if (fd < 0) continue;
198                 l0 = read(fd, buffer, sizeof buffer);
199                 if (l0 <= 0) continue;
200                 close(fd);
201                 p1 = base64enc(buffer, l0);
202                 if (!p1) continue;
203                 l1 = strlen(p1);
204                 l2 = base64dec(p1, &p2);
205                 if (l2 <= 0) continue;
206 printf("[[[%.*s]]]\n",l2,p2);
207                 if (l0 != l2) printf("length mismatch\n");
208                 else if (memcmp(buffer, p2, l0)) printf("content mismatch\n");
209                 free(p1);
210                 free(p2);
211         }
212         return 0;
213 }
214
215 #endif