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#include <stdlib.h> 28#include <string.h> 29 30#define _MPRINTF_REPLACE /* use our functions only */ 31#include <curl/mprintf.h> 32 33#include "urldata.h" /* for the SessionHandle definition */ 34#include "warnless.h" 35#include "curl_base64.h" 36#include "curl_memory.h" 37#include "non-ascii.h" 38 39/* include memdebug.h last */ 40#include "memdebug.h" 41 42/* ---- Base64 Encoding/Decoding Table --- */ 43static const char table64[]= 44 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 45 46static void decodeQuantum(unsigned char *dest, const char *src) 47{ 48 const char *s, *p; 49 unsigned long i, v, x = 0; 50 51 for(i = 0, s = src; i < 4; i++, s++) { 52 v = 0; 53 p = table64; 54 while(*p && (*p != *s)) { 55 v++; 56 p++; 57 } 58 if(*p == *s) 59 x = (x << 6) + v; 60 else if(*s == '=') 61 x = (x << 6); 62 } 63 64 dest[2] = curlx_ultouc(x); 65 x >>= 8; 66 dest[1] = curlx_ultouc(x); 67 x >>= 8; 68 dest[0] = curlx_ultouc(x); 69} 70 71/* 72 * Curl_base64_decode() 73 * 74 * Given a base64 string at src, decode it and return an allocated memory in 75 * the *outptr. Returns the length of the decoded data. 76 * 77 * @unittest: 1302 78 */ 79size_t Curl_base64_decode(const char *src, unsigned char **outptr) 80{ 81 size_t length = 0; 82 size_t equalsTerm = 0; 83 size_t i; 84 size_t numQuantums; 85 unsigned char lastQuantum[3]; 86 size_t rawlen = 0; 87 unsigned char *newstr; 88 89 *outptr = NULL; 90 91 while((src[length] != '=') && src[length]) 92 length++; 93 /* A maximum of two = padding characters is allowed */ 94 if(src[length] == '=') { 95 equalsTerm++; 96 if(src[length+equalsTerm] == '=') 97 equalsTerm++; 98 } 99 numQuantums = (length + equalsTerm) / 4; 100 101 /* Don't allocate a buffer if the decoded length is 0 */ 102 if(numQuantums == 0) 103 return 0; 104 105 rawlen = (numQuantums * 3) - equalsTerm; 106 107 /* The buffer must be large enough to make room for the last quantum 108 (which may be partially thrown out) and the zero terminator. */ 109 newstr = malloc(rawlen+4); 110 if(!newstr) 111 return 0; 112 113 *outptr = newstr; 114 115 /* Decode all but the last quantum (which may not decode to a 116 multiple of 3 bytes) */ 117 for(i = 0; i < numQuantums - 1; i++) { 118 decodeQuantum(newstr, src); 119 newstr += 3; src += 4; 120 } 121 122 /* This final decode may actually read slightly past the end of the buffer 123 if the input string is missing pad bytes. This will almost always be 124 harmless. */ 125 decodeQuantum(lastQuantum, src); 126 for(i = 0; i < 3 - equalsTerm; i++) 127 newstr[i] = lastQuantum[i]; 128 129 newstr[i] = '\0'; /* zero terminate */ 130 return rawlen; 131} 132 133/* 134 * Curl_base64_encode() 135 * 136 * Returns the length of the newly created base64 string. The third argument 137 * is a pointer to an allocated area holding the base64 data. If something 138 * went wrong, 0 is returned. 139 * 140 * @unittest: 1302 141 */ 142size_t Curl_base64_encode(struct SessionHandle *data, 143 const char *inputbuff, size_t insize, 144 char **outptr) 145{ 146 CURLcode res; 147 unsigned char ibuf[3]; 148 unsigned char obuf[4]; 149 int i; 150 int inputparts; 151 char *output; 152 char *base64data; 153 char *convbuf = NULL; 154 155 const char *indata = inputbuff; 156 157 *outptr = NULL; /* set to NULL in case of failure before we reach the end */ 158 159 if(0 == insize) 160 insize = strlen(indata); 161 162 base64data = output = malloc(insize*4/3+4); 163 if(NULL == output) 164 return 0; 165 166 /* 167 * The base64 data needs to be created using the network encoding 168 * not the host encoding. And we can't change the actual input 169 * so we copy it to a buffer, translate it, and use that instead. 170 */ 171 res = Curl_convert_clone(data, indata, insize, &convbuf); 172 if(res) { 173 free(output); 174 return 0; 175 } 176 177 if(convbuf) 178 indata = (char *)convbuf; 179 180 while(insize > 0) { 181 for(i = inputparts = 0; i < 3; i++) { 182 if(insize > 0) { 183 inputparts++; 184 ibuf[i] = (unsigned char) *indata; 185 indata++; 186 insize--; 187 } 188 else 189 ibuf[i] = 0; 190 } 191 192 obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); 193 obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ 194 ((ibuf[1] & 0xF0) >> 4)); 195 obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ 196 ((ibuf[2] & 0xC0) >> 6)); 197 obuf[3] = (unsigned char) (ibuf[2] & 0x3F); 198 199 switch(inputparts) { 200 case 1: /* only one byte read */ 201 snprintf(output, 5, "%c%c==", 202 table64[obuf[0]], 203 table64[obuf[1]]); 204 break; 205 case 2: /* two bytes read */ 206 snprintf(output, 5, "%c%c%c=", 207 table64[obuf[0]], 208 table64[obuf[1]], 209 table64[obuf[2]]); 210 break; 211 default: 212 snprintf(output, 5, "%c%c%c%c", 213 table64[obuf[0]], 214 table64[obuf[1]], 215 table64[obuf[2]], 216 table64[obuf[3]] ); 217 break; 218 } 219 output += 4; 220 } 221 *output=0; 222 *outptr = base64data; /* make it return the actual data memory */ 223 224 if(convbuf) 225 free(convbuf); 226 227 return strlen(base64data); /* return the length of the new data */ 228} 229/* ---- End of Base64 Encoding ---- */ 230