New upstream release.
[debian/iodine.git] / src / base32.c
1 /*
2  * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "encoding.h"
22 #include "base32.h"
23
24 #define BLKSIZE_RAW 5
25 #define BLKSIZE_ENC 8
26
27 static const char cb32[] = 
28         "abcdefghijklmnopqrstuvwxyz012345";
29 static unsigned char rev32[128];
30 static int reverse_init = 0;
31
32 static int base32_decode(void *, size_t *, const char *, size_t);
33 static int base32_encode(char *, size_t *, const void *, size_t);
34 static int base32_handles_dots();
35 static int base32_blksize_raw();
36 static int base32_blksize_enc();
37
38 static struct encoder base32_encoder =
39 {
40         "Base32",
41         base32_encode,
42         base32_decode,
43         base32_handles_dots,
44         base32_handles_dots,
45         base32_blksize_raw,
46         base32_blksize_enc
47 };
48
49 struct encoder
50 *get_base32_encoder()
51 {
52         return &base32_encoder;
53 }
54
55 static int 
56 base32_handles_dots()
57 {
58         return 0;
59 }
60
61 static int 
62 base32_blksize_raw()
63 {
64         return BLKSIZE_RAW;
65 }
66
67 static int 
68 base32_blksize_enc()
69 {
70         return BLKSIZE_ENC;
71 }
72
73 int
74 b32_5to8(int in)
75 {
76         return cb32[in & 31];
77 }
78
79 int
80 b32_8to5(int in)
81 {
82         int i;
83         int c;
84         if (!reverse_init) {
85                 for (i = 0; i < 32; i++) {
86                         c = cb32[i];
87                         rev32[(int) c] = i;
88                 }
89                 reverse_init = 1;
90         }
91         return rev32[in];
92 }
93
94 static int 
95 base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
96 {
97         size_t newsize;
98         size_t maxsize;
99         unsigned char *p;
100         unsigned char *q;
101         int i;
102
103         memset(buf, 0, *buflen);
104
105         /* how many chars can we encode within the buf */
106         maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
107         /* how big will the encoded data be */
108         newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
109         /* if the buffer is too small, eat some of the data */
110         if (*buflen < newsize) {
111                 size = maxsize;
112         }
113
114         p = (unsigned char *) buf;
115         q = (unsigned char *)data;
116
117         for(i=0;i<size;i+=BLKSIZE_RAW) {
118                 p[0] = cb32[((q[0] & 0xf8) >> 3)];
119                 p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
120                 p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
121                 p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
122                 p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
123                 p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
124                 p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
125                 p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
126                 
127                 q += BLKSIZE_RAW;
128                 p += BLKSIZE_ENC;
129         }       
130         *p = 0;
131
132         /* store number of bytes from data that was used */
133         *buflen = size;
134
135         return strlen(buf) - 1;
136 }
137
138 #define DECODE_ERROR 0xffffffff
139 #define REV32(x) rev32[(int) (x)]
140
141 static int
142 decode_token(const unsigned char *t, unsigned char *data, size_t len) 
143 {
144         if (len < 2)
145                 return 0;
146
147         data[0] = ((REV32(t[0]) & 0x1f) << 3) | 
148                           ((REV32(t[1]) & 0x1c) >> 2);
149         
150         if (len < 4)
151                 return 1;
152
153         data[1] = ((REV32(t[1]) & 0x03) << 6) | 
154                           ((REV32(t[2]) & 0x1f) << 1) | 
155                           ((REV32(t[3]) & 0x10) >> 4);
156
157         if (len < 5)
158                 return 2;
159
160         data[2] = ((REV32(t[3]) & 0x0f) << 4) |
161                           ((REV32(t[4]) & 0x1e) >> 1);
162
163         if (len < 7)
164                 return 3;
165
166         data[3] = ((REV32(t[4]) & 0x01) << 7) |
167                           ((REV32(t[5]) & 0x1f) << 2) |
168                           ((REV32(t[6]) & 0x18) >> 3);
169
170         if (len < 8)
171                 return 4;
172
173         data[4] = ((REV32(t[6]) & 0x07) << 5) |
174                           ((REV32(t[7]) & 0x1f));
175
176         return 5;
177 }
178
179 static int
180 base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
181 {
182         unsigned char *q;
183         size_t newsize;
184         size_t maxsize;
185         const char *p;
186         unsigned char c;
187         int len;
188         int i;
189
190         if (!reverse_init) {
191                 for (i = 0; i < 32; i++) {
192                         c = cb32[i];
193                         rev32[(int) c] = i;
194                 }
195                 reverse_init = 1;
196         }
197         
198         /* chars needed to decode slen */
199         newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
200         /* encoded chars that fit in buf */
201         maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
202         /* if the buffer is too small, eat some of the data */
203         if (*buflen < newsize) {
204                 slen = maxsize;
205         }
206
207         q = buf;
208         for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
209                 len = decode_token((unsigned char *) p, (unsigned char *) q, slen);     
210                 q += len;
211                 slen -= BLKSIZE_ENC;
212                 
213                 if (len < BLKSIZE_RAW)
214                         break;
215         }
216         *q = '\0';
217         
218         return q - (unsigned char *) buf;
219 }
220