[svn-upgrade] Integrating new upstream version, iodine (0.5.1)
[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
31 static int base32_decode(void *, size_t *, const char *, size_t);
32 static int base32_encode(char *, size_t *, const void *, size_t);
33 static int base32_handles_dots();
34 static int base32_blksize_raw();
35 static int base32_blksize_enc();
36
37 static struct encoder base32_encoder =
38 {
39         "Base32",
40         base32_encode,
41         base32_decode,
42         base32_handles_dots,
43         base32_handles_dots,
44         base32_blksize_raw,
45         base32_blksize_enc
46 };
47
48 struct encoder
49 *get_base32_encoder()
50 {
51         return &base32_encoder;
52 }
53
54 static int 
55 base32_handles_dots()
56 {
57         return 0;
58 }
59
60 static int 
61 base32_blksize_raw()
62 {
63         return BLKSIZE_RAW;
64 }
65
66 static int 
67 base32_blksize_enc()
68 {
69         return BLKSIZE_ENC;
70 }
71
72 static void
73 base32_reverse_init()
74 {
75         int i;
76         unsigned char c;
77         static int reverse_init = 0;
78
79         if (!reverse_init) {
80                 for (i = 0; i < 32; i++) {
81                         c = cb32[i];
82                         rev32[(int) c] = i;
83                 }
84                 reverse_init = 1;
85         }
86 }
87
88 int
89 b32_5to8(int in)
90 {
91         return cb32[in & 31];
92 }
93
94 int
95 b32_8to5(int in)
96 {
97         base32_reverse_init();
98         return rev32[in];
99 }
100
101 static int 
102 base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
103 {
104         size_t newsize;
105         size_t maxsize;
106         unsigned char *p;
107         unsigned char *q;
108         int i;
109
110         memset(buf, 0, *buflen);
111
112         /* how many chars can we encode within the buf */
113         maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
114         /* how big will the encoded data be */
115         newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
116         if (size % BLKSIZE_RAW) {
117                 newsize += BLKSIZE_ENC;
118         }
119         /* if the buffer is too small, eat some of the data */
120         if (*buflen < newsize) {
121                 size = maxsize;
122         }
123
124         p = (unsigned char *) buf;
125         q = (unsigned char *)data;
126
127         for(i=0;i<size;i+=BLKSIZE_RAW) {
128                 p[0] = cb32[((q[0] & 0xf8) >> 3)];
129                 p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
130                 p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
131                 p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
132                 p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
133                 p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
134                 p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
135                 p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
136                 
137                 q += BLKSIZE_RAW;
138                 p += BLKSIZE_ENC;
139         }       
140         *p = 0;
141
142         /* store number of bytes from data that was used */
143         *buflen = size;
144
145         return strlen(buf);
146 }
147
148 #define DECODE_ERROR 0xffffffff
149 #define REV32(x) rev32[(int) (x)]
150
151 static int
152 decode_token(const unsigned char *t, unsigned char *data, size_t len) 
153 {
154         if (len < 2)
155                 return 0;
156
157         data[0] = ((REV32(t[0]) & 0x1f) << 3) | 
158                           ((REV32(t[1]) & 0x1c) >> 2);
159         
160         if (len < 4)
161                 return 1;
162
163         data[1] = ((REV32(t[1]) & 0x03) << 6) | 
164                           ((REV32(t[2]) & 0x1f) << 1) | 
165                           ((REV32(t[3]) & 0x10) >> 4);
166
167         if (len < 5)
168                 return 2;
169
170         data[2] = ((REV32(t[3]) & 0x0f) << 4) |
171                           ((REV32(t[4]) & 0x1e) >> 1);
172
173         if (len < 7)
174                 return 3;
175
176         data[3] = ((REV32(t[4]) & 0x01) << 7) |
177                           ((REV32(t[5]) & 0x1f) << 2) |
178                           ((REV32(t[6]) & 0x18) >> 3);
179
180         if (len < 8)
181                 return 4;
182
183         data[4] = ((REV32(t[6]) & 0x07) << 5) |
184                           ((REV32(t[7]) & 0x1f));
185
186         return 5;
187 }
188
189 static int
190 base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
191 {
192         unsigned char *q;
193         size_t newsize;
194         size_t maxsize;
195         const char *p;
196         int len;
197
198         base32_reverse_init();
199         
200         /* chars needed to decode slen */
201         newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
202         /* encoded chars that fit in buf */
203         maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
204         /* if the buffer is too small, eat some of the data */
205         if (*buflen < newsize) {
206                 slen = maxsize;
207         }
208
209         q = buf;
210         for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
211                 len = decode_token((unsigned char *) p, (unsigned char *) q, slen);     
212                 q += len;
213                 slen -= BLKSIZE_ENC;
214                 
215                 if (len < BLKSIZE_RAW)
216                         break;
217         }
218         *q = '\0';
219         
220         return q - (unsigned char *) buf;
221 }
222