1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23/* Base64 encoding/decoding */ 24 25#include "setup.h" 26 27#define _MPRINTF_REPLACE /* use our functions only */ 28#include <curl/mprintf.h> 29 30#include "urldata.h" /* for the SessionHandle definition */ 31#include "warnless.h" 32#include "curl_base64.h" 33#include "curl_memory.h" 34#include "non-ascii.h" 35 36/* include memdebug.h last */ 37#include "memdebug.h" 38 39/* ---- Base64 Encoding/Decoding Table --- */ 40static const char table64[]= 41 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 42 43static void decodeQuantum(unsigned char *dest, const char *src) 44{ 45 const char *s, *p; 46 unsigned long i, v, x = 0; 47 48 for(i = 0, s = src; i < 4; i++, s++) { 49 v = 0; 50 p = table64; 51 while(*p && (*p != *s)) { 52 v++; 53 p++; 54 } 55 if(*p == *s) 56 x = (x << 6) + v; 57 else if(*s == '=') 58 x = (x << 6); 59 } 60 61 dest[2] = curlx_ultouc(x); 62 x >>= 8; 63 dest[1] = curlx_ultouc(x); 64 x >>= 8; 65 dest[0] = curlx_ultouc(x); 66} 67 68/* 69 * Curl_base64_decode() 70 * 71 * Given a base64 NUL-terminated string at src, decode it and return a 72 * pointer in *outptr to a newly allocated memory area holding decoded 73 * data. Size of decoded data is returned in variable pointed by outlen. 74 * 75 * Returns CURLE_OK on success, otherwise specific error code. Function 76 * output shall not be considered valid unless CURLE_OK is returned. 77 * 78 * When decoded data length is 0, returns NULL in *outptr. 79 * 80 * @unittest: 1302 81 */ 82CURLcode Curl_base64_decode(const char *src, 83 unsigned char **outptr, size_t *outlen) 84{ 85 size_t length = 0; 86 size_t equalsTerm = 0; 87 size_t i; 88 size_t numQuantums; 89 unsigned char lastQuantum[3]; 90 size_t rawlen = 0; 91 unsigned char *newstr; 92 93 *outptr = NULL; 94 *outlen = 0; 95 96 while((src[length] != '=') && src[length]) 97 length++; 98 /* A maximum of two = padding characters is allowed */ 99 if(src[length] == '=') { 100 equalsTerm++; 101 if(src[length+equalsTerm] == '=') 102 equalsTerm++; 103 } 104 numQuantums = (length + equalsTerm) / 4; 105 106 /* Don't allocate a buffer if the decoded length is 0 */ 107 if(numQuantums == 0) 108 return CURLE_OK; 109 110 rawlen = (numQuantums * 3) - equalsTerm; 111 112 /* The buffer must be large enough to make room for the last quantum 113 (which may be partially thrown out) and the zero terminator. */ 114 newstr = malloc(rawlen+4); 115 if(!newstr) 116 return CURLE_OUT_OF_MEMORY; 117 118 *outptr = newstr; 119 120 /* Decode all but the last quantum (which may not decode to a 121 multiple of 3 bytes) */ 122 for(i = 0; i < numQuantums - 1; i++) { 123 decodeQuantum(newstr, src); 124 newstr += 3; src += 4; 125 } 126 127 /* This final decode may actually read slightly past the end of the buffer 128 if the input string is missing pad bytes. This will almost always be 129 harmless. */ 130 decodeQuantum(lastQuantum, src); 131 for(i = 0; i < 3 - equalsTerm; i++) 132 newstr[i] = lastQuantum[i]; 133 134 newstr[i] = '\0'; /* zero terminate */ 135 136 *outlen = rawlen; /* return size of decoded data */ 137 138 return CURLE_OK; 139} 140 141/* 142 * Curl_base64_encode() 143 * 144 * Given a pointer to an input buffer and an input size, encode it and 145 * return a pointer in *outptr to a newly allocated memory area holding 146 * encoded data. Size of encoded data is returned in variable pointed by 147 * outlen. 148 * 149 * Input length of 0 indicates input buffer holds a NUL-terminated string. 150 * 151 * Returns CURLE_OK on success, otherwise specific error code. Function 152 * output shall not be considered valid unless CURLE_OK is returned. 153 * 154 * When encoded data length is 0, returns NULL in *outptr. 155 * 156 * @unittest: 1302 157 */ 158CURLcode Curl_base64_encode(struct SessionHandle *data, 159 const char *inputbuff, size_t insize, 160 char **outptr, size_t *outlen) 161{ 162 CURLcode error; 163 unsigned char ibuf[3]; 164 unsigned char obuf[4]; 165 int i; 166 int inputparts; 167 char *output; 168 char *base64data; 169 char *convbuf = NULL; 170 171 const char *indata = inputbuff; 172 173 *outptr = NULL; 174 *outlen = 0; 175 176 if(0 == insize) 177 insize = strlen(indata); 178 179 base64data = output = malloc(insize*4/3+4); 180 if(NULL == output) 181 return CURLE_OUT_OF_MEMORY; 182 183 /* 184 * The base64 data needs to be created using the network encoding 185 * not the host encoding. And we can't change the actual input 186 * so we copy it to a buffer, translate it, and use that instead. 187 */ 188 error = Curl_convert_clone(data, indata, insize, &convbuf); 189 if(error) { 190 free(output); 191 return error; 192 } 193 194 if(convbuf) 195 indata = (char *)convbuf; 196 197 while(insize > 0) { 198 for(i = inputparts = 0; i < 3; i++) { 199 if(insize > 0) { 200 inputparts++; 201 ibuf[i] = (unsigned char) *indata; 202 indata++; 203 insize--; 204 } 205 else 206 ibuf[i] = 0; 207 } 208 209 obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); 210 obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ 211 ((ibuf[1] & 0xF0) >> 4)); 212 obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ 213 ((ibuf[2] & 0xC0) >> 6)); 214 obuf[3] = (unsigned char) (ibuf[2] & 0x3F); 215 216 switch(inputparts) { 217 case 1: /* only one byte read */ 218 snprintf(output, 5, "%c%c==", 219 table64[obuf[0]], 220 table64[obuf[1]]); 221 break; 222 case 2: /* two bytes read */ 223 snprintf(output, 5, "%c%c%c=", 224 table64[obuf[0]], 225 table64[obuf[1]], 226 table64[obuf[2]]); 227 break; 228 default: 229 snprintf(output, 5, "%c%c%c%c", 230 table64[obuf[0]], 231 table64[obuf[1]], 232 table64[obuf[2]], 233 table64[obuf[3]] ); 234 break; 235 } 236 output += 4; 237 } 238 *output = '\0'; 239 *outptr = base64data; /* return pointer to new data, allocated memory */ 240 241 if(convbuf) 242 free(convbuf); 243 244 *outlen = strlen(base64data); /* return the length of the new data */ 245 246 return CURLE_OK; 247} 248/* ---- End of Base64 Encoding ---- */ 249