1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 /*
21 * XSEC
22 *
23 * XSCryptCryptoBase64 := Internal implementation of a base64
24 * encoder/decoder
25 *
26 * Author(s): Berin Lautenbach
27 *
28 * $Id: XSCryptCryptoBase64.cpp 1125514 2011-05-20 19:08:33Z scantor $
29 *
30 */
31
32 #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
33 #include <xsec/enc/XSECCryptoException.hpp>
34
35 // --------------------------------------------------------------------------------
36 // Lookup tables and macros
37 // --------------------------------------------------------------------------------
38
39 char Base64LookupTable[] = {
40 'A','B','C','D','E','F','G','H','I','J','K','L','M',
41 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
42 'a','b','c','d','e','f','g','h','i','j','k','l','m',
43 'n','o','p','q','r','s','t','u','v','w','x','y','z',
44 '0','1','2','3','4','5','6','7','8','9','+','/',
45 };
46
47 #define IS_UPPER(c) (c >= 'A' && c <= 'Z')
48 #define IS_LOWER(c) (c >= 'a' && c <= 'z')
49 #define IS_NUMBR(c) (c >= '0' && c <= '9')
50 #define IS_OTHER(c) (c == '+' || c == '/')
51 #define IS_B64CH(c) (IS_LOWER(c) || IS_UPPER(c) || IS_NUMBR(c) || IS_OTHER(c))
52 #define IS_B64OE(c) (IS_B64CH(c) || c == '=')
53
54 // --------------------------------------------------------------------------------
55 // Decoding
56 // --------------------------------------------------------------------------------
57
decodeCh(unsigned char c)58 unsigned char decodeCh(unsigned char c) {
59
60 if (IS_UPPER(c))
61 return c - 'A';
62
63 if (IS_LOWER(c))
64 return (c - 'a') + 26;
65
66 if (IS_NUMBR(c))
67 return (c - '0') + 52;
68
69 if (c == '+')
70 return 62;
71 if (c == '/')
72 return 63;
73
74 if (c == '=')
75 return 64;
76
77 return 65; // error;
78
79 }
80
canonicaliseInput(const unsigned char * inData,unsigned int inLength)81 void XSCryptCryptoBase64::canonicaliseInput(const unsigned char *inData,
82 unsigned int inLength) {
83
84 // Canonicalise the input buffer into m_inputBuffer
85
86 unsigned char buf[400]; // Do 400 bytes at a time
87
88 unsigned int i, j;
89 j = 0;
90
91 for (i = 0; i < inLength; ++i) {
92
93 if (IS_B64OE(inData[i])) {
94
95 // Have a base64 or '=' char
96 buf[j++] = inData[i];
97
98 if (j == 400) {
99 m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, 400);
100 m_remainingInput += 400;
101 j = 0;
102 }
103 }
104 }
105
106 if (j > 0) {
107 m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, j);
108 m_remainingInput += j;
109 }
110
111 }
112
113
decodeInit(void)114 void XSCryptCryptoBase64::decodeInit(void) {
115
116 m_remainingInput = m_remainingOutput = 0;
117 m_allDone = false;
118 m_state = B64_DECODE;
119
120 }
121
decode(const unsigned char * inData,unsigned int inLength,unsigned char * outData,unsigned int outLength)122 unsigned int XSCryptCryptoBase64::decode(const unsigned char * inData,
123 unsigned int inLength,
124 unsigned char * outData,
125 unsigned int outLength) {
126
127
128 // Ensure we are in an appropriate state
129 if (m_state != B64_DECODE) {
130
131 throw XSECCryptoException(XSECCryptoException::Base64Error,
132 "XSCrypt:Base64 - Attempt to decode when not in decode state");
133
134 }
135
136 // Copy the data into our input buffer
137 canonicaliseInput(inData, inLength);
138
139 unsigned int i = 0;
140 unsigned char t;
141
142 while (m_allDone != true && m_remainingInput - i >= 4) {
143
144 // BYTE 1
145
146 t = decodeCh(m_inputBuffer[i++]);
147
148 if (t > 63) {
149
150 throw XSECCryptoException(XSECCryptoException::Base64Error,
151 "XSCrypt:Base64 - Invalid character at start of base 64 block");
152
153 }
154
155 m_outputBuffer[m_remainingOutput] = (t << 2);
156
157 // BYTE 2
158
159 t = decodeCh(m_inputBuffer[i++]);
160
161 if (t > 63) {
162
163 throw XSECCryptoException(XSECCryptoException::Base64Error,
164 "XSCrypt:Base64 - Invalid character at start of base 64 block");
165
166 }
167
168 // Take top two bits and place at end of current byte
169 m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] |
170 (t >> 4);
171
172 m_remainingOutput++; // Have a new complete byte
173
174 // Take remaining 4 bits and add to outputBuffer
175 m_outputBuffer[m_remainingOutput] = ( t << 4);
176
177 // BYTE 3
178
179 t = decodeCh(m_inputBuffer[i++]);
180
181 if (t > 64) {
182
183 throw XSECCryptoException(XSECCryptoException::Base64Error,
184 "XSCrypt:Base64 - Invalid character at start of base 64 block");
185
186 }
187
188 if (t == 64) {
189
190 // '=' character found
191
192 m_allDone = true;
193 break;
194
195 }
196
197 // Take 4 bits and append to current buffer
198
199 m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | (t >> 2);
200 m_remainingOutput++;
201
202 // Take last 2 bits and append to buffer
203
204 m_outputBuffer[m_remainingOutput] = (t << 6);
205
206 // BYTE 4
207
208 t = decodeCh(m_inputBuffer[i++]);
209
210 if (t > 64) {
211
212 throw XSECCryptoException(XSECCryptoException::Base64Error,
213 "XSCrypt:Base64 - Invalid character at start of base 64 block");
214
215 }
216
217 if (t == 64) {
218
219 m_allDone = true;
220 break;
221
222 }
223
224 // Place all six bits and end of current byte
225
226 m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | t;
227 m_remainingOutput++;
228
229 }
230
231 // Now whatever we've decoded can be placed in the output buffer
232
233 unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
234
235 m_outputBuffer.sbMemcpyOut(outData, cpyOut);
236
237 // Move the buffers down
238 if (cpyOut != m_remainingOutput) {
239 m_remainingOutput = m_remainingOutput - cpyOut;
240 m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
241 }
242 else
243 m_remainingOutput = 0;
244
245 if (i != m_remainingInput) {
246 m_remainingInput -= i;
247 m_inputBuffer.sbMemshift(0, i, m_remainingInput);
248 }
249 else
250 m_remainingInput = 0;
251
252 // Return however much we have decoded
253 return cpyOut;
254
255 }
256
decodeFinish(unsigned char * outData,unsigned int outLength)257 unsigned int XSCryptCryptoBase64::decodeFinish(unsigned char * outData,
258 unsigned int outLength) {
259
260 if (m_state != B64_DECODE) {
261
262 throw XSECCryptoException(XSECCryptoException::Base64Error,
263 "XSCrypt:Base64 - Attempt to complete a decode when not in decode state");
264
265 }
266
267 m_allDone = true;
268 unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
269
270 m_outputBuffer.sbMemcpyOut(outData, cpyOut);
271
272 // Move the buffers down
273 if (cpyOut != m_remainingOutput) {
274 m_remainingOutput = m_remainingOutput - cpyOut;
275 m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
276 }
277 else {
278 m_remainingOutput = 0;
279 }
280
281 return cpyOut;
282 }
283
284 // --------------------------------------------------------------------------------
285 // Encoding
286 // --------------------------------------------------------------------------------
287
encodeInit(void)288 void XSCryptCryptoBase64::encodeInit(void) {
289
290 m_remainingInput = m_remainingOutput = 0;
291 m_allDone = false;
292 m_charCount = 0;
293 m_state = B64_ENCODE;
294
295 }
296
297
encode(const unsigned char * inData,unsigned int inLength,unsigned char * outData,unsigned int outLength)298 unsigned int XSCryptCryptoBase64::encode(const unsigned char * inData,
299 unsigned int inLength,
300 unsigned char * outData,
301 unsigned int outLength) {
302
303 if (m_state != B64_ENCODE) {
304
305 throw XSECCryptoException(XSECCryptoException::Base64Error,
306 "XSCrypt:Base64 - Attempt to encode when not in encoding state");
307
308 }
309
310 // Copy input data into end of input buffer
311 m_inputBuffer.sbMemcpyIn(m_remainingInput, inData, inLength);
312 m_remainingInput += inLength;
313
314 unsigned int i = 0;
315 unsigned char t;
316
317 while (m_allDone == false && m_remainingInput - i >= 3) {
318
319 // Have a complete block of three bytes to encode
320
321 // First 6 bits;
322 t = (m_inputBuffer[i] >> 2);
323 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
324
325 // 2 bits from byte one and 4 from byte 2
326 t = ((m_inputBuffer[i++] << 4) & 0x30);
327 t |= (m_inputBuffer[i] >> 4);
328 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
329
330 // 4 from byte 2 and 2 from byte 3
331 t = ((m_inputBuffer[i++] << 2) & 0x3C);
332 t |= (m_inputBuffer[i] >> 6);
333 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
334
335 // last 6 bits from byte 3
336 t = m_inputBuffer[i++] & 0x3F;
337 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
338
339 m_charCount += 4;
340
341 if (m_charCount >= 76) {
342
343 m_outputBuffer[m_remainingOutput++] = '\n';
344 m_charCount = 0;
345
346 }
347
348 }
349
350 // Now copy data out to output buffer
351
352 unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
353
354 m_outputBuffer.sbMemcpyOut(outData, cpyOut);
355
356 // Move the buffers down
357 if (cpyOut != m_remainingOutput) {
358 m_remainingOutput = m_remainingOutput - cpyOut;
359 m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
360 }
361 else
362 m_remainingOutput = 0;
363
364 if (i != m_remainingInput) {
365 m_remainingInput -= i;
366 m_inputBuffer.sbMemshift(0, i, m_remainingInput);
367 }
368
369 else
370
371 m_remainingInput = 0;
372
373 // Return however much we have decoded
374 return cpyOut;
375
376 }
377
encodeFinish(unsigned char * outData,unsigned int outLength)378 unsigned int XSCryptCryptoBase64::encodeFinish(unsigned char * outData,
379 unsigned int outLength) {
380
381 if (m_state != B64_ENCODE) {
382
383 throw XSECCryptoException(XSECCryptoException::Base64Error,
384 "XSCrypt:Base64 - Attempt to complete an encode when not in encoding state");
385
386 }
387
388 if (m_allDone == false && m_remainingInput > 0) {
389
390 // Will always be < 3 characters remaining in inputBuffer
391 // If necessary - terminate the Base64 string
392
393 if (m_remainingInput >= 3) {
394
395 throw XSECCryptoException(XSECCryptoException::Base64Error,
396 "XSCrypt:Base64 - Too much remaining input in input buffer");
397
398 }
399
400 // First 6 bits;
401 unsigned int t = (m_inputBuffer[0] >> 2);
402 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
403
404 // 2 bits from byte one and 4 from byte 2
405 t = ((m_inputBuffer[0] << 4) & 0x30);
406
407 if (m_remainingInput == 1) {
408 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
409 m_outputBuffer[m_remainingOutput++] = '=';
410 m_outputBuffer[m_remainingOutput++] = '=';
411 }
412
413 else {
414
415 t |= (m_inputBuffer[1] >> 4);
416 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
417
418 // 4 from byte 2
419 t = ((m_inputBuffer[1] << 2) & 0x3C);
420 m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
421 m_outputBuffer[m_remainingOutput++] = '=';
422 }
423
424 }
425
426 m_allDone = true;
427
428 // Copy out
429 unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
430
431 m_outputBuffer.sbMemcpyOut(outData, cpyOut);
432
433 // Move the buffers down
434 if (cpyOut != m_remainingOutput) {
435 m_remainingOutput = m_remainingOutput - cpyOut;
436 m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
437 }
438 else {
439 m_remainingOutput = 0;
440 }
441
442 return cpyOut;
443 }
444