base64.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. /* Base64 encoding/decoding */
  23. #include "curl_setup.h"
  24. #define _MPRINTF_REPLACE /* use our functions only */
  25. #include <curl/mprintf.h>
  26. #include "urldata.h" /* for the SessionHandle definition */
  27. #include "warnless.h"
  28. #include "curl_base64.h"
  29. #include "curl_memory.h"
  30. #include "non-ascii.h"
  31. /* include memdebug.h last */
  32. #include "memdebug.h"
  33. /* ---- Base64 Encoding/Decoding Table --- */
  34. static const char table64[]=
  35. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  36. static size_t decodeQuantum(unsigned char *dest, const char *src)
  37. {
  38. size_t padding = 0;
  39. const char *s, *p;
  40. unsigned long i, v, x = 0;
  41. for(i = 0, s = src; i < 4; i++, s++) {
  42. v = 0;
  43. if(*s == '=') {
  44. x = (x << 6);
  45. padding++;
  46. }
  47. else {
  48. p = table64;
  49. while(*p && (*p != *s)) {
  50. v++;
  51. p++;
  52. }
  53. if(*p == *s)
  54. x = (x << 6) + v;
  55. else
  56. return 0;
  57. }
  58. }
  59. if(padding < 1)
  60. dest[2] = curlx_ultouc(x & 0xFFUL);
  61. x >>= 8;
  62. if(padding < 2)
  63. dest[1] = curlx_ultouc(x & 0xFFUL);
  64. x >>= 8;
  65. dest[0] = curlx_ultouc(x & 0xFFUL);
  66. return 3 - padding;
  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. */
  82. CURLcode Curl_base64_decode(const char *src,
  83. unsigned char **outptr, size_t *outlen)
  84. {
  85. size_t srclen = 0;
  86. size_t length = 0;
  87. size_t padding = 0;
  88. size_t i;
  89. size_t result;
  90. size_t numQuantums;
  91. size_t rawlen = 0;
  92. unsigned char *pos;
  93. unsigned char *newstr;
  94. *outptr = NULL;
  95. *outlen = 0;
  96. srclen = strlen(src);
  97. /* Check the length of the input string is valid */
  98. if(!srclen || srclen % 4)
  99. return CURLE_BAD_CONTENT_ENCODING;
  100. /* Find the position of any = padding characters */
  101. while((src[length] != '=') && src[length])
  102. length++;
  103. /* A maximum of two = padding characters is allowed */
  104. if(src[length] == '=') {
  105. padding++;
  106. if(src[length + 1] == '=')
  107. padding++;
  108. }
  109. /* Check the = padding characters weren't part way through the input */
  110. if(length + padding != srclen)
  111. return CURLE_BAD_CONTENT_ENCODING;
  112. /* Calculate the number of quantums */
  113. numQuantums = srclen / 4;
  114. /* Calculate the size of the decoded string */
  115. rawlen = (numQuantums * 3) - padding;
  116. /* Allocate our buffer including room for a zero terminator */
  117. newstr = malloc(rawlen + 1);
  118. if(!newstr)
  119. return CURLE_OUT_OF_MEMORY;
  120. pos = newstr;
  121. /* Decode the quantums */
  122. for(i = 0; i < numQuantums; i++) {
  123. result = decodeQuantum(pos, src);
  124. if(!result) {
  125. Curl_safefree(newstr);
  126. return CURLE_BAD_CONTENT_ENCODING;
  127. }
  128. pos += result;
  129. src += 4;
  130. }
  131. /* Zero terminate */
  132. *pos = '\0';
  133. /* Return the decoded data */
  134. *outptr = newstr;
  135. *outlen = rawlen;
  136. return CURLE_OK;
  137. }
  138. /*
  139. * Curl_base64_encode()
  140. *
  141. * Given a pointer to an input buffer and an input size, encode it and
  142. * return a pointer in *outptr to a newly allocated memory area holding
  143. * encoded data. Size of encoded data is returned in variable pointed by
  144. * outlen.
  145. *
  146. * Input length of 0 indicates input buffer holds a NUL-terminated string.
  147. *
  148. * Returns CURLE_OK on success, otherwise specific error code. Function
  149. * output shall not be considered valid unless CURLE_OK is returned.
  150. *
  151. * When encoded data length is 0, returns NULL in *outptr.
  152. *
  153. * @unittest: 1302
  154. */
  155. CURLcode Curl_base64_encode(struct SessionHandle *data,
  156. const char *inputbuff, size_t insize,
  157. char **outptr, size_t *outlen)
  158. {
  159. CURLcode error;
  160. unsigned char ibuf[3];
  161. unsigned char obuf[4];
  162. int i;
  163. int inputparts;
  164. char *output;
  165. char *base64data;
  166. char *convbuf = NULL;
  167. const char *indata = inputbuff;
  168. *outptr = NULL;
  169. *outlen = 0;
  170. if(0 == insize)
  171. insize = strlen(indata);
  172. base64data = output = malloc(insize*4/3+4);
  173. if(NULL == output)
  174. return CURLE_OUT_OF_MEMORY;
  175. /*
  176. * The base64 data needs to be created using the network encoding
  177. * not the host encoding. And we can't change the actual input
  178. * so we copy it to a buffer, translate it, and use that instead.
  179. */
  180. error = Curl_convert_clone(data, indata, insize, &convbuf);
  181. if(error) {
  182. free(output);
  183. return error;
  184. }
  185. if(convbuf)
  186. indata = (char *)convbuf;
  187. while(insize > 0) {
  188. for(i = inputparts = 0; i < 3; i++) {
  189. if(insize > 0) {
  190. inputparts++;
  191. ibuf[i] = (unsigned char) *indata;
  192. indata++;
  193. insize--;
  194. }
  195. else
  196. ibuf[i] = 0;
  197. }
  198. obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
  199. obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
  200. ((ibuf[1] & 0xF0) >> 4));
  201. obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
  202. ((ibuf[2] & 0xC0) >> 6));
  203. obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
  204. switch(inputparts) {
  205. case 1: /* only one byte read */
  206. snprintf(output, 5, "%c%c==",
  207. table64[obuf[0]],
  208. table64[obuf[1]]);
  209. break;
  210. case 2: /* two bytes read */
  211. snprintf(output, 5, "%c%c%c=",
  212. table64[obuf[0]],
  213. table64[obuf[1]],
  214. table64[obuf[2]]);
  215. break;
  216. default:
  217. snprintf(output, 5, "%c%c%c%c",
  218. table64[obuf[0]],
  219. table64[obuf[1]],
  220. table64[obuf[2]],
  221. table64[obuf[3]] );
  222. break;
  223. }
  224. output += 4;
  225. }
  226. *output = '\0';
  227. *outptr = base64data; /* return pointer to new data, allocated memory */
  228. if(convbuf)
  229. free(convbuf);
  230. *outlen = strlen(base64data); /* return the length of the new data */
  231. return CURLE_OK;
  232. }
  233. /* ---- End of Base64 Encoding ---- */