base64.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2022, 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 https://curl.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. #if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
  25. !defined(CURL_DISABLE_LDAP) || \
  26. !defined(CURL_DISABLE_SMTP) || \
  27. !defined(CURL_DISABLE_POP3) || \
  28. !defined(CURL_DISABLE_IMAP) || \
  29. !defined(CURL_DISABLE_DOH) || defined(USE_SSL)
  30. #include "urldata.h" /* for the Curl_easy definition */
  31. #include "warnless.h"
  32. #include "curl_base64.h"
  33. /* The last 3 #include files should be in this order */
  34. #include "curl_printf.h"
  35. #include "curl_memory.h"
  36. #include "memdebug.h"
  37. /* ---- Base64 Encoding/Decoding Table --- */
  38. static const char base64[]=
  39. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  40. /* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648
  41. section 5 */
  42. static const char base64url[]=
  43. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
  44. static size_t decodeQuantum(unsigned char *dest, const char *src)
  45. {
  46. size_t padding = 0;
  47. const char *s, *p;
  48. unsigned long i, x = 0;
  49. for(i = 0, s = src; i < 4; i++, s++) {
  50. if(*s == '=') {
  51. x = (x << 6);
  52. padding++;
  53. }
  54. else {
  55. unsigned long v = 0;
  56. p = base64;
  57. while(*p && (*p != *s)) {
  58. v++;
  59. p++;
  60. }
  61. if(*p == *s)
  62. x = (x << 6) + v;
  63. else
  64. return 0;
  65. }
  66. }
  67. if(padding < 1)
  68. dest[2] = curlx_ultouc(x & 0xFFUL);
  69. x >>= 8;
  70. if(padding < 2)
  71. dest[1] = curlx_ultouc(x & 0xFFUL);
  72. x >>= 8;
  73. dest[0] = curlx_ultouc(x & 0xFFUL);
  74. return 3 - padding;
  75. }
  76. /*
  77. * Curl_base64_decode()
  78. *
  79. * Given a base64 NUL-terminated string at src, decode it and return a
  80. * pointer in *outptr to a newly allocated memory area holding decoded
  81. * data. Size of decoded data is returned in variable pointed by outlen.
  82. *
  83. * Returns CURLE_OK on success, otherwise specific error code. Function
  84. * output shall not be considered valid unless CURLE_OK is returned.
  85. *
  86. * When decoded data length is 0, returns NULL in *outptr.
  87. *
  88. * @unittest: 1302
  89. */
  90. CURLcode Curl_base64_decode(const char *src,
  91. unsigned char **outptr, size_t *outlen)
  92. {
  93. size_t srclen = 0;
  94. size_t length = 0;
  95. size_t padding = 0;
  96. size_t i;
  97. size_t numQuantums;
  98. size_t rawlen = 0;
  99. unsigned char *pos;
  100. unsigned char *newstr;
  101. *outptr = NULL;
  102. *outlen = 0;
  103. srclen = strlen(src);
  104. /* Check the length of the input string is valid */
  105. if(!srclen || srclen % 4)
  106. return CURLE_BAD_CONTENT_ENCODING;
  107. /* Find the position of any = padding characters */
  108. while((src[length] != '=') && src[length])
  109. length++;
  110. /* A maximum of two = padding characters is allowed */
  111. if(src[length] == '=') {
  112. padding++;
  113. if(src[length + 1] == '=')
  114. padding++;
  115. }
  116. /* Check the = padding characters weren't part way through the input */
  117. if(length + padding != srclen)
  118. return CURLE_BAD_CONTENT_ENCODING;
  119. /* Calculate the number of quantums */
  120. numQuantums = srclen / 4;
  121. /* Calculate the size of the decoded string */
  122. rawlen = (numQuantums * 3) - padding;
  123. /* Allocate our buffer including room for a zero terminator */
  124. newstr = malloc(rawlen + 1);
  125. if(!newstr)
  126. return CURLE_OUT_OF_MEMORY;
  127. pos = newstr;
  128. /* Decode the quantums */
  129. for(i = 0; i < numQuantums; i++) {
  130. size_t result = decodeQuantum(pos, src);
  131. if(!result) {
  132. free(newstr);
  133. return CURLE_BAD_CONTENT_ENCODING;
  134. }
  135. pos += result;
  136. src += 4;
  137. }
  138. /* Zero terminate */
  139. *pos = '\0';
  140. /* Return the decoded data */
  141. *outptr = newstr;
  142. *outlen = rawlen;
  143. return CURLE_OK;
  144. }
  145. static CURLcode base64_encode(const char *table64,
  146. const char *inputbuff, size_t insize,
  147. char **outptr, size_t *outlen)
  148. {
  149. unsigned char ibuf[3];
  150. unsigned char obuf[4];
  151. int i;
  152. int inputparts;
  153. char *output;
  154. char *base64data;
  155. const char *indata = inputbuff;
  156. *outptr = NULL;
  157. *outlen = 0;
  158. if(!insize)
  159. insize = strlen(indata);
  160. #if SIZEOF_SIZE_T == 4
  161. if(insize > UINT_MAX/4)
  162. return CURLE_OUT_OF_MEMORY;
  163. #endif
  164. base64data = output = malloc(insize * 4 / 3 + 4);
  165. if(!output)
  166. return CURLE_OUT_OF_MEMORY;
  167. while(insize > 0) {
  168. for(i = inputparts = 0; i < 3; i++) {
  169. if(insize > 0) {
  170. inputparts++;
  171. ibuf[i] = (unsigned char) *indata;
  172. indata++;
  173. insize--;
  174. }
  175. else
  176. ibuf[i] = 0;
  177. }
  178. obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
  179. obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
  180. ((ibuf[1] & 0xF0) >> 4));
  181. obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
  182. ((ibuf[2] & 0xC0) >> 6));
  183. obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
  184. switch(inputparts) {
  185. case 1: /* only one byte read */
  186. msnprintf(output, 5, "%c%c==",
  187. table64[obuf[0]],
  188. table64[obuf[1]]);
  189. break;
  190. case 2: /* two bytes read */
  191. msnprintf(output, 5, "%c%c%c=",
  192. table64[obuf[0]],
  193. table64[obuf[1]],
  194. table64[obuf[2]]);
  195. break;
  196. default:
  197. msnprintf(output, 5, "%c%c%c%c",
  198. table64[obuf[0]],
  199. table64[obuf[1]],
  200. table64[obuf[2]],
  201. table64[obuf[3]]);
  202. break;
  203. }
  204. output += 4;
  205. }
  206. /* Zero terminate */
  207. *output = '\0';
  208. /* Return the pointer to the new data (allocated memory) */
  209. *outptr = base64data;
  210. /* Return the length of the new data */
  211. *outlen = output - base64data;
  212. return CURLE_OK;
  213. }
  214. /*
  215. * Curl_base64_encode()
  216. *
  217. * Given a pointer to an input buffer and an input size, encode it and
  218. * return a pointer in *outptr to a newly allocated memory area holding
  219. * encoded data. Size of encoded data is returned in variable pointed by
  220. * outlen.
  221. *
  222. * Input length of 0 indicates input buffer holds a NUL-terminated string.
  223. *
  224. * Returns CURLE_OK on success, otherwise specific error code. Function
  225. * output shall not be considered valid unless CURLE_OK is returned.
  226. *
  227. * When encoded data length is 0, returns NULL in *outptr.
  228. *
  229. * @unittest: 1302
  230. */
  231. CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
  232. char **outptr, size_t *outlen)
  233. {
  234. return base64_encode(base64, inputbuff, insize, outptr, outlen);
  235. }
  236. /*
  237. * Curl_base64url_encode()
  238. *
  239. * Given a pointer to an input buffer and an input size, encode it and
  240. * return a pointer in *outptr to a newly allocated memory area holding
  241. * encoded data. Size of encoded data is returned in variable pointed by
  242. * outlen.
  243. *
  244. * Input length of 0 indicates input buffer holds a NUL-terminated string.
  245. *
  246. * Returns CURLE_OK on success, otherwise specific error code. Function
  247. * output shall not be considered valid unless CURLE_OK is returned.
  248. *
  249. * When encoded data length is 0, returns NULL in *outptr.
  250. *
  251. * @unittest: 1302
  252. */
  253. CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
  254. char **outptr, size_t *outlen)
  255. {
  256. return base64_encode(base64url, inputbuff, insize, outptr, outlen);
  257. }
  258. #endif /* no users so disabled */