1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2013, 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 "curl_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 size_t decodeQuantum(unsigned char *dest, const char *src) 44{ 45 size_t padding = 0; 46 const char *s, *p; 47 unsigned long i, v, x = 0; 48 49 for(i = 0, s = src; i < 4; i++, s++) { 50 v = 0; 51 52 if(*s == '=') { 53 x = (x << 6); 54 padding++; 55 } 56 else { 57 p = table64; 58 59 while(*p && (*p != *s)) { 60 v++; 61 p++; 62 } 63 64 if(*p == *s) 65 x = (x << 6) + v; 66 else 67 return 0; 68 } 69 } 70 71 if(padding < 1) 72 dest[2] = curlx_ultouc(x & 0xFFUL); 73 74 x >>= 8; 75 if(padding < 2) 76 dest[1] = curlx_ultouc(x & 0xFFUL); 77 78 x >>= 8; 79 dest[0] = curlx_ultouc(x & 0xFFUL); 80 81 return 3 - padding; 82} 83 84/* 85 * Curl_base64_decode() 86 * 87 * Given a base64 NUL-terminated string at src, decode it and return a 88 * pointer in *outptr to a newly allocated memory area holding decoded 89 * data. Size of decoded data is returned in variable pointed by outlen. 90 * 91 * Returns CURLE_OK on success, otherwise specific error code. Function 92 * output shall not be considered valid unless CURLE_OK is returned. 93 * 94 * When decoded data length is 0, returns NULL in *outptr. 95 * 96 * @unittest: 1302 97 */ 98CURLcode Curl_base64_decode(const char *src, 99 unsigned char **outptr, size_t *outlen) 100{ 101 size_t srclen = 0; 102 size_t length = 0; 103 size_t padding = 0; 104 size_t i; 105 size_t result; 106 size_t numQuantums; 107 size_t rawlen = 0; 108 unsigned char *pos; 109 unsigned char *newstr; 110 111 *outptr = NULL; 112 *outlen = 0; 113 srclen = strlen(src); 114 115 /* Check the length of the input string is valid */ 116 if(!srclen || srclen % 4) 117 return CURLE_BAD_CONTENT_ENCODING; 118 119 /* Find the position of any = padding characters */ 120 while((src[length] != '=') && src[length]) 121 length++; 122 123 /* A maximum of two = padding characters is allowed */ 124 if(src[length] == '=') { 125 padding++; 126 if(src[length + 1] == '=') 127 padding++; 128 } 129 130 /* Check the = padding characters weren't part way through the input */ 131 if(length + padding != srclen) 132 return CURLE_BAD_CONTENT_ENCODING; 133 134 /* Calculate the number of quantums */ 135 numQuantums = srclen / 4; 136 137 /* Calculate the size of the decoded string */ 138 rawlen = (numQuantums * 3) - padding; 139 140 /* Allocate our buffer including room for a zero terminator */ 141 newstr = malloc(rawlen + 1); 142 if(!newstr) 143 return CURLE_OUT_OF_MEMORY; 144 145 pos = newstr; 146 147 /* Decode the quantums */ 148 for(i = 0; i < numQuantums; i++) { 149 result = decodeQuantum(pos, src); 150 if(!result) { 151 Curl_safefree(newstr); 152 153 return CURLE_BAD_CONTENT_ENCODING; 154 } 155 156 pos += result; 157 src += 4; 158 } 159 160 /* Zero terminate */ 161 *pos = '\0'; 162 163 /* Return the decoded data */ 164 *outptr = newstr; 165 *outlen = rawlen; 166 167 return CURLE_OK; 168} 169 170/* 171 * Curl_base64_encode() 172 * 173 * Given a pointer to an input buffer and an input size, encode it and 174 * return a pointer in *outptr to a newly allocated memory area holding 175 * encoded data. Size of encoded data is returned in variable pointed by 176 * outlen. 177 * 178 * Input length of 0 indicates input buffer holds a NUL-terminated string. 179 * 180 * Returns CURLE_OK on success, otherwise specific error code. Function 181 * output shall not be considered valid unless CURLE_OK is returned. 182 * 183 * When encoded data length is 0, returns NULL in *outptr. 184 * 185 * @unittest: 1302 186 */ 187CURLcode Curl_base64_encode(struct SessionHandle *data, 188 const char *inputbuff, size_t insize, 189 char **outptr, size_t *outlen) 190{ 191 CURLcode error; 192 unsigned char ibuf[3]; 193 unsigned char obuf[4]; 194 int i; 195 int inputparts; 196 char *output; 197 char *base64data; 198 char *convbuf = NULL; 199 200 const char *indata = inputbuff; 201 202 *outptr = NULL; 203 *outlen = 0; 204 205 if(0 == insize) 206 insize = strlen(indata); 207 208 base64data = output = malloc(insize*4/3+4); 209 if(NULL == output) 210 return CURLE_OUT_OF_MEMORY; 211 212 /* 213 * The base64 data needs to be created using the network encoding 214 * not the host encoding. And we can't change the actual input 215 * so we copy it to a buffer, translate it, and use that instead. 216 */ 217 error = Curl_convert_clone(data, indata, insize, &convbuf); 218 if(error) { 219 free(output); 220 return error; 221 } 222 223 if(convbuf) 224 indata = (char *)convbuf; 225 226 while(insize > 0) { 227 for(i = inputparts = 0; i < 3; i++) { 228 if(insize > 0) { 229 inputparts++; 230 ibuf[i] = (unsigned char) *indata; 231 indata++; 232 insize--; 233 } 234 else 235 ibuf[i] = 0; 236 } 237 238 obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); 239 obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ 240 ((ibuf[1] & 0xF0) >> 4)); 241 obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ 242 ((ibuf[2] & 0xC0) >> 6)); 243 obuf[3] = (unsigned char) (ibuf[2] & 0x3F); 244 245 switch(inputparts) { 246 case 1: /* only one byte read */ 247 snprintf(output, 5, "%c%c==", 248 table64[obuf[0]], 249 table64[obuf[1]]); 250 break; 251 case 2: /* two bytes read */ 252 snprintf(output, 5, "%c%c%c=", 253 table64[obuf[0]], 254 table64[obuf[1]], 255 table64[obuf[2]]); 256 break; 257 default: 258 snprintf(output, 5, "%c%c%c%c", 259 table64[obuf[0]], 260 table64[obuf[1]], 261 table64[obuf[2]], 262 table64[obuf[3]] ); 263 break; 264 } 265 output += 4; 266 } 267 *output = '\0'; 268 *outptr = base64data; /* return pointer to new data, allocated memory */ 269 270 if(convbuf) 271 free(convbuf); 272 273 *outlen = strlen(base64data); /* return the length of the new data */ 274 275 return CURLE_OK; 276} 277/* ---- End of Base64 Encoding ---- */ 278