]> git.cryptolib.org Git - avr-crypto-lib.git/blob - base64_dec.c
+ base64 en- and decoding
[avr-crypto-lib.git] / 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 "test_src/cli.h"
33
34 #define USE_GCC_EXTENSION
35
36 #if 1
37
38 #ifdef USE_GCC_EXTENSION
39
40 static
41 int ascii2bit6(char a){
42         switch(a){
43                 case 'A'...'Z':
44                         return a-'A';
45                 case 'a'...'z':
46                         return a-'a'+26;
47                 case '0'...'9':
48                         return a-'0'+52;
49                 case '+':
50                 case '-':
51                         return 62;
52                 case '/':
53                 case '_':
54                         return 63;
55                 default:
56                         return -1;
57         }
58 }
59
60 #else
61
62 static
63 uint8_t ascii2bit6(char a){
64         int r;
65         switch(a>>4){
66                 case 0x5:
67                 case 0x4: 
68                         r=a-'A';
69                         if(r<0 || r>25){
70                                 return -1;
71                         } else {
72                                 return r;
73                         }
74                 case 0x7:
75                 case 0x6: 
76                         r=a-'a';
77                         if(r<0 || r>25){
78                                 return -1;
79                         } else {
80                                 return r+26;
81                         }
82                         break;
83                 case 0x3:
84                         if(a>'9')
85                                 return -1;
86                         return a-'0'+52;
87                 default:
88                         break;  
89         }
90         switch (a){
91                 case '+':
92                 case '-':
93                         return 62;
94                 case '/':
95                 case '_':
96                         return 63;
97                 default:
98                         return 0xff;
99         }
100 }
101
102 #endif
103
104 #else
105
106 static 
107 uint8_t ascii2bit6(uint8_t a){
108         if(a>='A' && a<='Z'){
109                 return a-'A';
110         } else {
111                 if(a>='a' && a<= 'z'){
112                         return a-'a'+26;
113                 } else {
114                         if(a>='0' && a<='9'){
115                                 return a-'0'+52;
116                         } else {
117                                 if(a=='+' || a=='-'){
118                                         return 62;
119                                 } else {
120                                         if(a=='/' || a=='_'){
121                                                 return 63;
122                                         } else {
123                                                 return 0xff;
124                                         }
125                                 }
126                         }
127                 }
128         }
129 }
130
131 #endif
132
133 int base64_binlength(char* str, uint8_t strict){
134         int l=0;
135         uint8_t term=0;
136         for(;;){
137                 if(*str=='\0')
138                         break;
139                 if(*str=='\n' || *str=='\r'){
140                         str++;
141                         continue;
142                 }
143                 if(*str=='='){
144                         term++;
145                         str++;
146                         if(term==2){
147                                 break;
148                         }
149                         continue;
150                 }
151                 if(term)
152                         return -1;
153                 if(ascii2bit6(*str)==-1){
154                         if(strict)
155                                 return -1;
156                 } else {
157                         l++;
158                 }
159                 str++;
160         }
161         switch(term){
162                 case 0:
163                         if(l%4!=0)
164                                 return -1;
165                         return l/4*3;
166                 case 1:
167                         if(l%4!=3)
168                                 return -1;
169                         return (l+1)/4*3-1;
170                 case 2:
171                         if(l%4!=2)
172                                 return -1;
173                         return (l+2)/4*3-2;
174                 default:
175                         return -1;
176         }
177 }
178
179 /*
180   |543210543210543210543210|
181   |765432107654321076543210|
182
183         .      .      .     .
184   |54321054|32105432|10543210|
185   |76543210|76543210|76543210|
186
187 */
188
189 int base64dec(void* dest, char* b64str, uint8_t strict){
190         uint8_t buffer[4];
191         uint8_t idx=0;
192         uint8_t term=0;
193         for(;;){
194 //              cli_putstr_P(PSTR("\r\n  DBG: got 0x"));
195 //              cli_hexdump(b64str, 1);
196                 buffer[idx]= ascii2bit6(*b64str);
197 //              cli_putstr_P(PSTR(" --> 0x"));
198 //              cli_hexdump(buffer+idx, 1);
199                 
200                 if(buffer[idx]==0xFF){
201                         if(*b64str=='='){
202                                 term++;
203                                 b64str++;
204                                 if(term==2)
205                                         goto finalize; /* definitly the end */
206                         }else{
207                                 if(*b64str == '\0'){
208                                         goto finalize; /* definitly the end */
209                                 }else{
210                                         if(*b64str == '\r' || *b64str == '\n' || !(strict)){
211                                                 b64str++; /* charcters that we simply ignore */
212                                         }else{
213                                                 return -1;
214                                         }
215                                 }
216                         }
217                 }else{
218                         if(term)
219                                 return -1; /* this happens if we get a '=' in the stream */
220                         idx++;
221                         b64str++;
222                 }
223                 if(idx==4){
224                         ((uint8_t*)dest)[0] = buffer[0]<<2 | buffer[1]>>4;
225                         ((uint8_t*)dest)[1] = buffer[1]<<4 | buffer[2]>>2;
226                         ((uint8_t*)dest)[2] = buffer[2]<<6 | buffer[3];
227                         dest = (uint8_t*)dest +3;
228                         idx=0;
229                 }
230         }
231   finalize:     
232         /* the final touch */
233         if(idx==0)
234                 return 0;
235         if(term==1){
236                 ((uint8_t*)dest)[0] = buffer[0]<<2 | buffer[1]>>4;
237                 ((uint8_t*)dest)[1] = buffer[1]<<4 | buffer[2]>>2;                      
238                 return 0;
239         }
240         if(term==2){
241                 ((uint8_t*)dest)[0] = buffer[0]<<2 | buffer[1]>>4;
242                 return 0;
243         }
244         return -1;
245 }