]> git.cryptolib.org Git - avr-crypto-lib.git/blob - base64/base64_dec.c
2a6e94141868b8e86a3e94847fe6dd9825572bf3
[avr-crypto-lib.git] / base64 / base64_dec.c
1 /* base64_dec.c */
2 /*
3  *   This file is part of the AVR-Crypto-Lib.
4  *   Copyright (C) 2006, 2007, 2008  Daniel Otte (daniel.otte@rub.de)
5  *
6  *   This program is free software: you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation, either version 3 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 /**
22  * base64 decoder (RFC3548)
23  * Author: Daniel Otte
24  * License: GPLv3
25  * 
26  * 
27  */
28
29 #include <stdint.h>
30 #include "base64_dec.h"
31
32 #include "cli.h"
33
34 /*
35  #define USE_GCC_EXTENSION
36 */
37 #if 1
38
39 #ifdef USE_GCC_EXTENSION
40
41 static
42 int ascii2bit6(char a){
43         switch(a){
44                 case 'A'...'Z':
45                         return a-'A';
46                 case 'a'...'z':
47                         return a-'a'+26;
48                 case '0'...'9':
49                         return a-'0'+52;
50                 case '+':
51                 case '-':
52                         return 62;
53                 case '/':
54                 case '_':
55                         return 63;
56                 default:
57                         return -1;
58         }
59 }
60
61 #else
62
63 static
64 uint8_t ascii2bit6(char a){
65         int r;
66         switch(a>>4){
67                 case 0x5:
68                 case 0x4: 
69                         r=a-'A';
70                         if(r<0 || r>25){
71                                 return -1;
72                         } else {
73                                 return r;
74                         }
75                 case 0x7:
76                 case 0x6: 
77                         r=a-'a';
78                         if(r<0 || r>25){
79                                 return -1;
80                         } else {
81                                 return r+26;
82                         }
83                         break;
84                 case 0x3:
85                         if(a>'9')
86                                 return -1;
87                         return a-'0'+52;
88                 default:
89                         break;  
90         }
91         switch (a){
92                 case '+':
93                 case '-':
94                         return 62;
95                 case '/':
96                 case '_':
97                         return 63;
98                 default:
99                         return 0xff;
100         }
101 }
102
103 #endif
104
105 #else
106
107 static 
108 uint8_t ascii2bit6(uint8_t a){
109         if(a>='A' && a<='Z'){
110                 return a-'A';
111         } else {
112                 if(a>='a' && a<= 'z'){
113                         return a-'a'+26;
114                 } else {
115                         if(a>='0' && a<='9'){
116                                 return a-'0'+52;
117                         } else {
118                                 if(a=='+' || a=='-'){
119                                         return 62;
120                                 } else {
121                                         if(a=='/' || a=='_'){
122                                                 return 63;
123                                         } else {
124                                                 return 0xff;
125                                         }
126                                 }
127                         }
128                 }
129         }
130 }
131
132 #endif
133
134 int base64_binlength(char *str, uint8_t strict){
135         int l=0;
136         uint8_t term=0;
137         for(;;){
138                 if(*str=='\0')
139                         break;
140                 if(*str=='\n' || *str=='\r'){
141                         str++;
142                         continue;
143                 }
144                 if(*str=='='){
145                         term++;
146                         str++;
147                         if(term==2){
148                                 break;
149                         }
150                         continue;
151                 }
152                 if(term)
153                         return -1;
154                 if(ascii2bit6(*str)==-1){
155                         if(strict)
156                                 return -1;
157                 } else {
158                         l++;
159                 }
160                 str++;
161         }
162         switch(term){
163                 case 0:
164                         if(l%4!=0)
165                                 return -1;
166                         return l/4*3;
167                 case 1:
168                         if(l%4!=3)
169                                 return -1;
170                         return (l+1)/4*3-1;
171                 case 2:
172                         if(l%4!=2)
173                                 return -1;
174                         return (l+2)/4*3-2;
175                 default:
176                         return -1;
177         }
178 }
179
180 /*
181   |543210543210543210543210|
182   |765432107654321076543210|
183
184         .      .      .     .
185   |54321054|32105432|10543210|
186   |76543210|76543210|76543210|
187
188 */
189
190 int base64dec(void *dest, const char *b64str, uint8_t strict){
191         uint8_t buffer[4];
192         uint8_t idx=0;
193         uint8_t term=0;
194         for(;;){
195 //              cli_putstr_P(PSTR("\r\n  DBG: got 0x"));
196 //              cli_hexdump(b64str, 1);
197                 buffer[idx]= ascii2bit6(*b64str);
198 //              cli_putstr_P(PSTR(" --> 0x"));
199 //              cli_hexdump(buffer+idx, 1);
200                 
201                 if(buffer[idx]==0xFF){
202                         if(*b64str=='='){
203                                 term++;
204                                 b64str++;
205                                 if(term==2)
206                                         goto finalize; /* definitly the end */
207                         }else{
208                                 if(*b64str == '\0'){
209                                         goto finalize; /* definitly the end */
210                                 }else{
211                                         if(*b64str == '\r' || *b64str == '\n' || !(strict)){
212                                                 b64str++; /* charcters that we simply ignore */
213                                         }else{
214                                                 return -1;
215                                         }
216                                 }
217                         }
218                 }else{
219                         if(term)
220                                 return -1; /* this happens if we get a '=' in the stream */
221                         idx++;
222                         b64str++;
223                 }
224                 if(idx==4){
225                         ((uint8_t*)dest)[0] = buffer[0]<<2 | buffer[1]>>4;
226                         ((uint8_t*)dest)[1] = buffer[1]<<4 | buffer[2]>>2;
227                         ((uint8_t*)dest)[2] = buffer[2]<<6 | buffer[3];
228                         dest = (uint8_t*)dest +3;
229                         idx=0;
230                 }
231         }
232   finalize:     
233         /* the final touch */
234         if(idx==0)
235                 return 0;
236         if(term==1){
237                 ((uint8_t*)dest)[0] = buffer[0]<<2 | buffer[1]>>4;
238                 ((uint8_t*)dest)[1] = buffer[1]<<4 | buffer[2]>>2;                      
239                 return 0;
240         }
241         if(term==2){
242                 ((uint8_t*)dest)[0] = buffer[0]<<2 | buffer[1]>>4;
243                 return 0;
244         }
245         return -1;
246 }