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