]> www.average.org Git - pam_pcsc_cr.git/blob - base64.c
Initialize pad memory to pacify stack protectors
[pam_pcsc_cr.git] / base64.c
1 /*
2 cencoder.c - c source to a base64 encoding algorithm implementation
3
4 This is part of the libb64 project, and has been placed in the public domain.
5 For details, see http://sourceforge.net/projects/libb64
6 */
7
8 /*
9   Modified by Eugene Crosser to fit pam_pcsc_cr project, 2013
10 */
11
12 #include <string.h>
13 #include <base64.h>
14 /*
15 cencode.h - c header for a base64 encoding algorithm
16
17 This is part of the libb64 project, and has been placed in the public domain.
18 For details, see http://sourceforge.net/projects/libb64
19 */
20
21 /*
22   Modified by Eugene Crosser to fit pam_pcsc_cr project, 2013
23 */
24
25 typedef enum
26 {
27         step_A, step_B, step_C
28 } base64_encodestep;
29
30 typedef struct
31 {
32         base64_encodestep step;
33         char result;
34         int stepcount;
35 } base64_encodestate;
36
37 /*
38 cdecode.h - c header for a base64 decoding algorithm
39
40 This is part of the libb64 project, and has been placed in the public domain.
41 For details, see http://sourceforge.net/projects/libb64
42 */
43
44 typedef enum
45 {
46         step_a, step_b, step_c, step_d
47 } base64_decodestep;
48
49 typedef struct
50 {
51         base64_decodestep step;
52         char plainchar;
53 } base64_decodestate;
54
55 static void base64_init_encodestate(base64_encodestate* state_in)
56 {
57         state_in->step = step_A;
58         state_in->result = 0;
59         state_in->stepcount = 0;
60 }
61
62 static char base64_encode_value(char value_in)
63 {
64         static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
65         if (value_in > 63) return '=';
66         return encoding[(int)value_in];
67 }
68
69 static int base64_encode_block(const unsigned char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
70 {
71         const unsigned char* plainchar = plaintext_in;
72         const unsigned char* const plaintextend = plaintext_in + length_in;
73         char* codechar = code_out;
74         char result;
75         char fragment;
76         
77         result = state_in->result;
78         
79         switch (state_in->step)
80         {
81                 while (1)
82                 {
83         case step_A:
84                         if (plainchar == plaintextend)
85                         {
86                                 state_in->result = result;
87                                 state_in->step = step_A;
88                                 return codechar - code_out;
89                         }
90                         fragment = *plainchar++;
91                         result = (fragment & 0x0fc) >> 2;
92                         *codechar++ = base64_encode_value(result);
93                         result = (fragment & 0x003) << 4;
94         case step_B:
95                         if (plainchar == plaintextend)
96                         {
97                                 state_in->result = result;
98                                 state_in->step = step_B;
99                                 return codechar - code_out;
100                         }
101                         fragment = *plainchar++;
102                         result |= (fragment & 0x0f0) >> 4;
103                         *codechar++ = base64_encode_value(result);
104                         result = (fragment & 0x00f) << 2;
105         case step_C:
106                         if (plainchar == plaintextend)
107                         {
108                                 state_in->result = result;
109                                 state_in->step = step_C;
110                                 return codechar - code_out;
111                         }
112                         fragment = *plainchar++;
113                         result |= (fragment & 0x0c0) >> 6;
114                         *codechar++ = base64_encode_value(result);
115                         result  = (fragment & 0x03f) >> 0;
116                         *codechar++ = base64_encode_value(result);
117                         
118                         ++(state_in->stepcount);
119                 }
120         }
121         /* control should not reach here */
122         return codechar - code_out;
123 }
124
125 static int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
126 {
127         char* codechar = code_out;
128         
129         switch (state_in->step)
130         {
131         case step_B:
132                 *codechar++ = base64_encode_value(state_in->result);
133                 *codechar++ = '=';
134                 *codechar++ = '=';
135                 break;
136         case step_C:
137                 *codechar++ = base64_encode_value(state_in->result);
138                 *codechar++ = '=';
139                 break;
140         case step_A:
141                 break;
142         }
143         *codechar++ = '\n';
144         
145         return codechar - code_out;
146 }
147
148 /*
149 cdecoder.c - c source to a base64 decoding algorithm implementation
150
151 This is part of the libb64 project, and has been placed in the public domain.
152 For details, see http://sourceforge.net/projects/libb64
153 */
154
155 static int base64_decode_value(char value_in)
156 {
157         static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
158         static const char decoding_size = sizeof(decoding);
159         value_in -= 43;
160         if (value_in < 0 || value_in >= decoding_size) return -1;
161         return decoding[(int)value_in];
162 }
163
164 static void base64_init_decodestate(base64_decodestate* state_in)
165 {
166         state_in->step = step_a;
167         state_in->plainchar = 0;
168 }
169
170 static int base64_decode_block(const char* code_in, const int length_in, unsigned char* plaintext_out, base64_decodestate* state_in)
171 {
172         const char* codechar = code_in;
173         unsigned char* plainchar = plaintext_out;
174         char fragment;
175         
176         *plainchar = state_in->plainchar;
177         
178         switch (state_in->step)
179         {
180                 while (1)
181                 {
182         case step_a:
183                         do {
184                                 if (codechar == code_in+length_in)
185                                 {
186                                         state_in->step = step_a;
187                                         state_in->plainchar = *plainchar;
188                                         return plainchar - plaintext_out;
189                                 }
190                                 fragment = (char)base64_decode_value(*codechar++);
191                         } while (fragment < 0);
192                         *plainchar    = (fragment & 0x03f) << 2;
193         case step_b:
194                         do {
195                                 if (codechar == code_in+length_in)
196                                 {
197                                         state_in->step = step_b;
198                                         state_in->plainchar = *plainchar;
199                                         return plainchar - plaintext_out;
200                                 }
201                                 fragment = (char)base64_decode_value(*codechar++);
202                         } while (fragment < 0);
203                         *plainchar++ |= (fragment & 0x030) >> 4;
204                         *plainchar    = (fragment & 0x00f) << 4;
205         case step_c:
206                         do {
207                                 if (codechar == code_in+length_in)
208                                 {
209                                         state_in->step = step_c;
210                                         state_in->plainchar = *plainchar;
211                                         return plainchar - plaintext_out;
212                                 }
213                                 fragment = (char)base64_decode_value(*codechar++);
214                         } while (fragment < 0);
215                         *plainchar++ |= (fragment & 0x03c) >> 2;
216                         *plainchar    = (fragment & 0x003) << 6;
217         case step_d:
218                         do {
219                                 if (codechar == code_in+length_in)
220                                 {
221                                         state_in->step = step_d;
222                                         state_in->plainchar = *plainchar;
223                                         return plainchar - plaintext_out;
224                                 }
225                                 fragment = (char)base64_decode_value(*codechar++);
226                         } while (fragment < 0);
227                         *plainchar++   |= (fragment & 0x03f);
228                 }
229         }
230         /* control should not reach here */
231         return plainchar - plaintext_out;
232 }
233
234 int b64_encode(const unsigned char *src, const int ssize,
235                 char *const b64, int *const bsize)
236 {
237         base64_encodestate s;
238         int cnt1, cnt2;
239         char *c = b64;
240
241         if (*bsize < ((ssize-1)/3+1)*4+1) return 1;
242         base64_init_encodestate(&s);
243         cnt1 = base64_encode_block(src, ssize, c, &s);
244         c += cnt1;
245         cnt2 = base64_encode_blockend(c, &s);
246         c += cnt2;
247         *c = 0;
248         *bsize = cnt1 + cnt2;
249         return 0;
250 }
251
252 int b64_decode(const char *b64, unsigned char *const dst, int *const dsize)
253 {
254         base64_decodestate s;
255         int cnt;
256         int bsize = strlen(b64);
257
258         if (*dsize < (bsize*3/4)) return 1;
259         base64_init_decodestate(&s);
260         cnt = base64_decode_block(b64, bsize, dst, &s);
261         *dsize = cnt;
262         return 0;
263 }