1/* 2 * Copyright (c) 2004 Rob Braun 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Rob Braun nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * 1-Oct-2004 31 * DRI: Rob Braun <bbraun@synack.net> 32 */ 33 34#include <stdlib.h> 35#include <string.h> 36 37#ifdef _BTEST_ 38int main(int argc, char* argv[]) { 39 unsigned char* enc = benc(argv[1], strlen(argv[1])); 40 printf("%s", enc); 41 printf("%s\n", bdec(enc, strlen(enc))); 42} 43#endif 44 45 46/* 47 * The code below derives from "Secure Programming Cookbook for C and 48 * C++"* and adapted by Kogule, Ryo (kogule@opendarwin.org). 49 * 50 * *John Viega and Matt Messier, O'Reilly, 2003 51 * http://www.secureprogramming.com/ 52 * 53 * Readability improvements by Luke Bellandi, 2007 (luke@apple.com) 54 */ 55 56typedef enum _B64CommandCodes { 57 B64_NullTerminator = -3, 58 B64_PaddingCharacter = -2, 59 B64_IgnorableCharacter = -1 60} B64CommandCodes; 61 62static char b64revtb[256] = { 63 -3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*0-15*/ 64 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16-31*/ 65 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /*32-47*/ 66 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, /*48-63*/ 67 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /*64-79*/ 68 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /*80-95*/ 69 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /*96-111*/ 70 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /*112-127*/ 71 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128-143*/ 72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*144-159*/ 73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*160-175*/ 74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*176-191*/ 75 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*192-207*/ 76 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*208-223*/ 77 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*224-239*/ 78 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /*240-255*/ 79}; 80 81typedef enum _B64CodecErrorCodes { 82 B64_noError = 0, 83 B64_decodeError = 1, 84 B64_bufferOverrun = 2 85} B64CodecErrorCodes; 86 87#define B64_INPUT_BLOCK_OFFSET ((inputIndex - 1 - ignorableCharacterCount) % 4) 88 89static unsigned int raw_base64_decode( 90 const unsigned char *input, unsigned char *output, size_t inLengthToDecode, 91 size_t *outputDecodedLength) 92{ 93 int currentBase64Value; 94 unsigned int inputIndex = 0; 95 unsigned int ignorableCharacterCount = 0; 96 unsigned int i; 97 unsigned char decodedBuffer[3]; 98 unsigned char currentInputBlockPaddingCharacterCount = 0; 99 size_t *decodedCharacterCount; 100 size_t dummyValue; 101 102 if (outputDecodedLength == NULL) { 103 // do this so that if caller passes in NULL for outputDecodedLength 104 // it can still be handled easily 105 decodedCharacterCount = &dummyValue; 106 } else { 107 decodedCharacterCount = outputDecodedLength; 108 } 109 *decodedCharacterCount = 0; 110 111 while ( (inputIndex <= inLengthToDecode) && 112 (currentInputBlockPaddingCharacterCount == 0) ) 113 { 114 currentBase64Value = b64revtb[input[inputIndex]]; 115 inputIndex++; 116 117 switch (currentBase64Value) { 118 // [1] Handle control characters 119 case B64_NullTerminator: 120 if (B64_INPUT_BLOCK_OFFSET != 0) return B64_decodeError; 121 // copy remaining characters with padding 122 if (currentInputBlockPaddingCharacterCount > 0) { 123 for (i = 0; i < (3 - currentInputBlockPaddingCharacterCount); i++) { 124 *output++ = decodedBuffer[i]; 125 (*decodedCharacterCount)++; 126 } 127 } 128 return B64_noError; 129 130 case B64_PaddingCharacter: 131 if (B64_INPUT_BLOCK_OFFSET < 2) { 132 /* Invalid here -- only characters 3 and/or 4 of the 133 input block can be padding */ 134 return B64_decodeError; 135 } else if (B64_INPUT_BLOCK_OFFSET == 2) { 136 /* Make sure there's appropriate padding */ 137 if (input[inputIndex] != '=') return B64_decodeError; 138 decodedBuffer[2] = 0; 139 currentInputBlockPaddingCharacterCount = 2; 140 break; 141 } else { 142 currentInputBlockPaddingCharacterCount = 1; 143 break; 144 } 145 return B64_noError; 146 147 case B64_IgnorableCharacter: 148 ignorableCharacterCount++; 149 break; 150 151 default: 152 // [2] Handle encoded data 153 switch (B64_INPUT_BLOCK_OFFSET) { 154 case 0: 155 decodedBuffer[0] = currentBase64Value << 2; 156 break; 157 case 1: 158 decodedBuffer[0] |= (currentBase64Value >> 4); 159 decodedBuffer[1] = currentBase64Value << 4; 160 break; 161 case 2: 162 decodedBuffer[1] |= (currentBase64Value >> 2); 163 decodedBuffer[2] = currentBase64Value << 6; 164 break; 165 case 3: 166 decodedBuffer[2] |= currentBase64Value; 167 for (i = 0; i < (3 - currentInputBlockPaddingCharacterCount); i++) { 168 *output++ = decodedBuffer[i]; 169 (*decodedCharacterCount)++; 170 } 171 break; 172 } 173 break; 174 } 175 } 176 177 if (inputIndex > inLengthToDecode) return B64_bufferOverrun; 178 179 for (i = 0; i < (3 - currentInputBlockPaddingCharacterCount); i++) { 180 *output++ = decodedBuffer[i]; 181 (*decodedCharacterCount)++; 182 } 183 184 return B64_noError; 185} 186 187unsigned char* xar_from_base64(const unsigned char* input, size_t inputLength, size_t *outputLength) 188{ 189 int err; 190 unsigned char *output; 191 192 // N.B.: This is a conservative estimate of space needed. It is NOT 193 // an exact value -- the exact length of the decoded data will be 194 // calculated during the decode operation. 195 output = malloc(3 * (inputLength / 4 + 1)); 196 if (output == NULL) return NULL; 197 198 err = raw_base64_decode(input, output, inputLength, outputLength); 199 200 if (err != B64_noError) { 201 free(output); 202 return NULL; 203 } 204 205 return output; 206} 207