blob: bf6952ee6182dd2f710bd4902ff8136d8c298145 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* XSEC
*
* XSCryptCryptoBase64 := Internal implementation of a base64
* encoder/decoder
*
* Author(s): Berin Lautenbach
*
* $Id$
*
*/
#include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp>
#include <xsec/enc/XSECCryptoException.hpp>
// --------------------------------------------------------------------------------
// Lookup tables and macros
// --------------------------------------------------------------------------------
char Base64LookupTable[] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9','+','/',
};
#define IS_UPPER(c) (c >= 'A' && c <= 'Z')
#define IS_LOWER(c) (c >= 'a' && c <= 'z')
#define IS_NUMBR(c) (c >= '0' && c <= '9')
#define IS_OTHER(c) (c == '+' || c == '/')
#define IS_B64CH(c) (IS_LOWER(c) || IS_UPPER(c) || IS_NUMBR(c) || IS_OTHER(c))
#define IS_B64OE(c) (IS_B64CH(c) || c == '=')
// --------------------------------------------------------------------------------
// Decoding
// --------------------------------------------------------------------------------
unsigned char decodeCh(unsigned char c) {
if (IS_UPPER(c))
return c - 'A';
if (IS_LOWER(c))
return (c - 'a') + 26;
if (IS_NUMBR(c))
return (c - '0') + 52;
if (c == '+')
return 62;
if (c == '/')
return 63;
if (c == '=')
return 64;
return 65; // error;
}
void XSCryptCryptoBase64::canonicaliseInput(const unsigned char *inData,
unsigned int inLength) {
// Canonicalise the input buffer into m_inputBuffer
unsigned char buf[400]; // Do 400 bytes at a time
unsigned int i, j;
j = 0;
for (i = 0; i < inLength; ++i) {
if (IS_B64OE(inData[i])) {
// Have a base64 or '=' char
buf[j++] = inData[i];
if (j == 400) {
m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, 400);
m_remainingInput += 400;
j = 0;
}
}
}
if (j > 0) {
m_inputBuffer.sbMemcpyIn(m_remainingInput, buf, j);
m_remainingInput += j;
}
}
void XSCryptCryptoBase64::decodeInit(void) {
m_remainingInput = m_remainingOutput = 0;
m_allDone = false;
m_state = B64_DECODE;
}
unsigned int XSCryptCryptoBase64::decode(const unsigned char * inData,
unsigned int inLength,
unsigned char * outData,
unsigned int outLength) {
// Ensure we are in an appropriate state
if (m_state != B64_DECODE) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Attempt to decode when not in decode state");
}
// Copy the data into our input buffer
canonicaliseInput(inData, inLength);
unsigned int i = 0;
unsigned char t;
while (m_allDone != true && m_remainingInput - i >= 4) {
// BYTE 1
t = decodeCh(m_inputBuffer[i++]);
if (t > 63) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Invalid character at start of base 64 block");
}
m_outputBuffer[m_remainingOutput] = (t << 2);
// BYTE 2
t = decodeCh(m_inputBuffer[i++]);
if (t > 63) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Invalid character at start of base 64 block");
}
// Take top two bits and place at end of current byte
m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] |
(t >> 4);
m_remainingOutput++; // Have a new complete byte
// Take remaining 4 bits and add to outputBuffer
m_outputBuffer[m_remainingOutput] = ( t << 4);
// BYTE 3
t = decodeCh(m_inputBuffer[i++]);
if (t > 64) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Invalid character at start of base 64 block");
}
if (t == 64) {
// '=' character found
m_allDone = true;
break;
}
// Take 4 bits and append to current buffer
m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | (t >> 2);
m_remainingOutput++;
// Take last 2 bits and append to buffer
m_outputBuffer[m_remainingOutput] = (t << 6);
// BYTE 4
t = decodeCh(m_inputBuffer[i++]);
if (t > 64) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Invalid character at start of base 64 block");
}
if (t == 64) {
m_allDone = true;
break;
}
// Place all six bits and end of current byte
m_outputBuffer[m_remainingOutput] = m_outputBuffer[m_remainingOutput] | t;
m_remainingOutput++;
}
// Now whatever we've decoded can be placed in the output buffer
unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
m_outputBuffer.sbMemcpyOut(outData, cpyOut);
// Move the buffers down
if (cpyOut != m_remainingOutput) {
m_remainingOutput = m_remainingOutput - cpyOut;
m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
}
else
m_remainingOutput = 0;
if (i != m_remainingInput) {
m_remainingInput -= i;
m_inputBuffer.sbMemshift(0, i, m_remainingInput);
}
else
m_remainingInput = 0;
// Return however much we have decoded
return cpyOut;
}
unsigned int XSCryptCryptoBase64::decodeFinish(unsigned char * outData,
unsigned int outLength) {
if (m_state != B64_DECODE) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Attempt to complete a decode when not in decode state");
}
m_allDone = true;
unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
m_outputBuffer.sbMemcpyOut(outData, cpyOut);
// Move the buffers down
if (cpyOut != m_remainingOutput) {
m_remainingOutput = m_remainingOutput - cpyOut;
m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
}
else {
m_remainingOutput = 0;
}
return cpyOut;
}
// --------------------------------------------------------------------------------
// Encoding
// --------------------------------------------------------------------------------
void XSCryptCryptoBase64::encodeInit(void) {
m_remainingInput = m_remainingOutput = 0;
m_allDone = false;
m_charCount = 0;
m_state = B64_ENCODE;
}
unsigned int XSCryptCryptoBase64::encode(const unsigned char * inData,
unsigned int inLength,
unsigned char * outData,
unsigned int outLength) {
if (m_state != B64_ENCODE) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Attempt to encode when not in encoding state");
}
// Copy input data into end of input buffer
m_inputBuffer.sbMemcpyIn(m_remainingInput, inData, inLength);
m_remainingInput += inLength;
unsigned int i = 0;
unsigned char t;
while (m_allDone == false && m_remainingInput - i >= 3) {
// Have a complete block of three bytes to encode
// First 6 bits;
t = (m_inputBuffer[i] >> 2);
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
// 2 bits from byte one and 4 from byte 2
t = ((m_inputBuffer[i++] << 4) & 0x30);
t |= (m_inputBuffer[i] >> 4);
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
// 4 from byte 2 and 2 from byte 3
t = ((m_inputBuffer[i++] << 2) & 0x3C);
t |= (m_inputBuffer[i] >> 6);
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
// last 6 bits from byte 3
t = m_inputBuffer[i++] & 0x3F;
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
m_charCount += 4;
if (m_charCount >= 76) {
m_outputBuffer[m_remainingOutput++] = '\n';
m_charCount = 0;
}
}
// Now copy data out to output buffer
unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
m_outputBuffer.sbMemcpyOut(outData, cpyOut);
// Move the buffers down
if (cpyOut != m_remainingOutput) {
m_remainingOutput = m_remainingOutput - cpyOut;
m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
}
else
m_remainingOutput = 0;
if (i != m_remainingInput) {
m_remainingInput -= i;
m_inputBuffer.sbMemshift(0, i, m_remainingInput);
}
else
m_remainingInput = 0;
// Return however much we have decoded
return cpyOut;
}
unsigned int XSCryptCryptoBase64::encodeFinish(unsigned char * outData,
unsigned int outLength) {
if (m_state != B64_ENCODE) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Attempt to complete an encode when not in encoding state");
}
if (m_allDone == false && m_remainingInput > 0) {
// Will always be < 3 characters remaining in inputBuffer
// If necessary - terminate the Base64 string
if (m_remainingInput >= 3) {
throw XSECCryptoException(XSECCryptoException::Base64Error,
"XSCrypt:Base64 - Too much remaining input in input buffer");
}
// First 6 bits;
unsigned int t = (m_inputBuffer[0] >> 2);
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
// 2 bits from byte one and 4 from byte 2
t = ((m_inputBuffer[0] << 4) & 0x30);
if (m_remainingInput == 1) {
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
m_outputBuffer[m_remainingOutput++] = '=';
m_outputBuffer[m_remainingOutput++] = '=';
}
else {
t |= (m_inputBuffer[1] >> 4);
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
// 4 from byte 2
t = ((m_inputBuffer[1] << 2) & 0x3C);
m_outputBuffer[m_remainingOutput++] = Base64LookupTable[t];
m_outputBuffer[m_remainingOutput++] = '=';
}
}
m_allDone = true;
// Copy out
unsigned int cpyOut = (m_remainingOutput < outLength ? m_remainingOutput : outLength);
m_outputBuffer.sbMemcpyOut(outData, cpyOut);
// Move the buffers down
if (cpyOut != m_remainingOutput) {
m_remainingOutput = m_remainingOutput - cpyOut;
m_outputBuffer.sbMemshift(0, cpyOut, m_remainingOutput);
}
else {
m_remainingOutput = 0;
}
return cpyOut;
}