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