Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * _ _ ____ _ |
| 3 | * Project ___| | | | _ \| | |
| 4 | * / __| | | | |_) | | |
| 5 | * | (__| |_| | _ <| |___ |
| 6 | * \___|\___/|_| \_\_____| |
| 7 | * |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 8 | * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 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 |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 12 | * are also available at https://curl.haxx.se/docs/copyright.html. |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 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 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 23 | /* Base64 encoding/decoding */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 24 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 25 | #include "curl_setup.h" |
Alex Deymo | e3149cc | 2016-10-05 11:18:42 -0700 | [diff] [blame] | 26 | #include "urldata.h" /* for the Curl_easy definition */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 27 | #include "warnless.h" |
| 28 | #include "curl_base64.h" |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 29 | #include "non-ascii.h" |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 30 | |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 31 | /* The last 3 #include files should be in this order */ |
| 32 | #include "curl_printf.h" |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 33 | #include "curl_memory.h" |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 34 | #include "memdebug.h" |
| 35 | |
| 36 | /* ---- Base64 Encoding/Decoding Table --- */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 37 | static const char base64[]= |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 38 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 39 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 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 | |
| 45 | static size_t decodeQuantum(unsigned char *dest, const char *src) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 46 | { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 47 | size_t padding = 0; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 48 | const char *s, *p; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 49 | unsigned long i, x = 0; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 50 | |
| 51 | for(i = 0, s = src; i < 4; i++, s++) { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 52 | unsigned long v = 0; |
| 53 | |
| 54 | if(*s == '=') { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 55 | x = (x << 6); |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 56 | padding++; |
| 57 | } |
| 58 | else { |
| 59 | p = base64; |
| 60 | |
| 61 | while(*p && (*p != *s)) { |
| 62 | v++; |
| 63 | p++; |
| 64 | } |
| 65 | |
| 66 | if(*p == *s) |
| 67 | x = (x << 6) + v; |
| 68 | else |
| 69 | return 0; |
| 70 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 71 | } |
| 72 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 73 | if(padding < 1) |
| 74 | dest[2] = curlx_ultouc(x & 0xFFUL); |
| 75 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 76 | x >>= 8; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 77 | if(padding < 2) |
| 78 | dest[1] = curlx_ultouc(x & 0xFFUL); |
| 79 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 80 | x >>= 8; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 81 | dest[0] = curlx_ultouc(x & 0xFFUL); |
| 82 | |
| 83 | return 3 - padding; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | /* |
| 87 | * Curl_base64_decode() |
| 88 | * |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 89 | * Given a base64 NUL-terminated string at src, decode it and return a |
| 90 | * pointer in *outptr to a newly allocated memory area holding decoded |
| 91 | * data. Size of decoded data is returned in variable pointed by outlen. |
| 92 | * |
| 93 | * Returns CURLE_OK on success, otherwise specific error code. Function |
| 94 | * output shall not be considered valid unless CURLE_OK is returned. |
| 95 | * |
| 96 | * When decoded data length is 0, returns NULL in *outptr. |
| 97 | * |
| 98 | * @unittest: 1302 |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 99 | */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 100 | CURLcode Curl_base64_decode(const char *src, |
| 101 | unsigned char **outptr, size_t *outlen) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 102 | { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 103 | size_t srclen = 0; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 104 | size_t length = 0; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 105 | size_t padding = 0; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 106 | size_t i; |
| 107 | size_t numQuantums; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 108 | size_t rawlen = 0; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 109 | unsigned char *pos; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 110 | unsigned char *newstr; |
| 111 | |
| 112 | *outptr = NULL; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 113 | *outlen = 0; |
| 114 | srclen = strlen(src); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 115 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 116 | /* Check the length of the input string is valid */ |
| 117 | if(!srclen || srclen % 4) |
| 118 | return CURLE_BAD_CONTENT_ENCODING; |
| 119 | |
| 120 | /* Find the position of any = padding characters */ |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 121 | while((src[length] != '=') && src[length]) |
| 122 | length++; |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 123 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 124 | /* A maximum of two = padding characters is allowed */ |
| 125 | if(src[length] == '=') { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 126 | padding++; |
| 127 | if(src[length + 1] == '=') |
| 128 | padding++; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 129 | } |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 130 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 131 | /* Check the = padding characters weren't part way through the input */ |
| 132 | if(length + padding != srclen) |
| 133 | return CURLE_BAD_CONTENT_ENCODING; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 134 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 135 | /* Calculate the number of quantums */ |
| 136 | numQuantums = srclen / 4; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 137 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 138 | /* Calculate the size of the decoded string */ |
| 139 | rawlen = (numQuantums * 3) - padding; |
| 140 | |
| 141 | /* Allocate our buffer including room for a zero terminator */ |
| 142 | newstr = malloc(rawlen + 1); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 143 | if(!newstr) |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 144 | return CURLE_OUT_OF_MEMORY; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 145 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 146 | pos = newstr; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 147 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 148 | /* Decode the quantums */ |
| 149 | for(i = 0; i < numQuantums; i++) { |
| 150 | size_t result = decodeQuantum(pos, src); |
| 151 | if(!result) { |
| 152 | free(newstr); |
| 153 | |
| 154 | return CURLE_BAD_CONTENT_ENCODING; |
| 155 | } |
| 156 | |
| 157 | pos += result; |
| 158 | src += 4; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 159 | } |
| 160 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 161 | /* Zero terminate */ |
| 162 | *pos = '\0'; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 163 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 164 | /* Return the decoded data */ |
| 165 | *outptr = newstr; |
| 166 | *outlen = rawlen; |
| 167 | |
| 168 | return CURLE_OK; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 169 | } |
| 170 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 171 | static CURLcode base64_encode(const char *table64, |
Alex Deymo | e3149cc | 2016-10-05 11:18:42 -0700 | [diff] [blame] | 172 | struct Curl_easy *data, |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 173 | const char *inputbuff, size_t insize, |
| 174 | char **outptr, size_t *outlen) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 175 | { |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 176 | CURLcode result; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 177 | unsigned char ibuf[3]; |
| 178 | unsigned char obuf[4]; |
| 179 | int i; |
| 180 | int inputparts; |
| 181 | char *output; |
| 182 | char *base64data; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 183 | char *convbuf = NULL; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 184 | |
| 185 | const char *indata = inputbuff; |
| 186 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 187 | *outptr = NULL; |
| 188 | *outlen = 0; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 189 | |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 190 | if(!insize) |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 191 | insize = strlen(indata); |
| 192 | |
Elliott Hughes | cee0338 | 2017-06-23 12:17:18 -0700 | [diff] [blame] | 193 | #if SIZEOF_SIZE_T == 4 |
| 194 | if(insize > UINT_MAX/4) |
| 195 | return CURLE_OUT_OF_MEMORY; |
| 196 | #endif |
| 197 | |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 198 | base64data = output = malloc(insize * 4 / 3 + 4); |
| 199 | if(!output) |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 200 | return CURLE_OUT_OF_MEMORY; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 201 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 202 | /* |
| 203 | * The base64 data needs to be created using the network encoding |
| 204 | * not the host encoding. And we can't change the actual input |
| 205 | * so we copy it to a buffer, translate it, and use that instead. |
| 206 | */ |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 207 | result = Curl_convert_clone(data, indata, insize, &convbuf); |
| 208 | if(result) { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 209 | free(output); |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 210 | return result; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 211 | } |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 212 | |
| 213 | if(convbuf) |
| 214 | indata = (char *)convbuf; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 215 | |
| 216 | while(insize > 0) { |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 217 | for(i = inputparts = 0; i < 3; i++) { |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 218 | if(insize > 0) { |
| 219 | inputparts++; |
| 220 | ibuf[i] = (unsigned char) *indata; |
| 221 | indata++; |
| 222 | insize--; |
| 223 | } |
| 224 | else |
| 225 | ibuf[i] = 0; |
| 226 | } |
| 227 | |
| 228 | obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); |
| 229 | obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ |
| 230 | ((ibuf[1] & 0xF0) >> 4)); |
| 231 | obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ |
| 232 | ((ibuf[2] & 0xC0) >> 6)); |
| 233 | obuf[3] = (unsigned char) (ibuf[2] & 0x3F); |
| 234 | |
| 235 | switch(inputparts) { |
| 236 | case 1: /* only one byte read */ |
| 237 | snprintf(output, 5, "%c%c==", |
| 238 | table64[obuf[0]], |
| 239 | table64[obuf[1]]); |
| 240 | break; |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 241 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 242 | case 2: /* two bytes read */ |
| 243 | snprintf(output, 5, "%c%c%c=", |
| 244 | table64[obuf[0]], |
| 245 | table64[obuf[1]], |
| 246 | table64[obuf[2]]); |
| 247 | break; |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 248 | |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 249 | default: |
| 250 | snprintf(output, 5, "%c%c%c%c", |
| 251 | table64[obuf[0]], |
| 252 | table64[obuf[1]], |
| 253 | table64[obuf[2]], |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 254 | table64[obuf[3]]); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 255 | break; |
| 256 | } |
| 257 | output += 4; |
| 258 | } |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 259 | |
| 260 | /* Zero terminate */ |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 261 | *output = '\0'; |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 262 | |
| 263 | /* Return the pointer to the new data (allocated memory) */ |
| 264 | *outptr = base64data; |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 265 | |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 266 | free(convbuf); |
| 267 | |
Alex Deymo | d15eaac | 2016-06-28 14:49:26 -0700 | [diff] [blame] | 268 | /* Return the length of the new data */ |
| 269 | *outlen = strlen(base64data); |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 270 | |
| 271 | return CURLE_OK; |
| 272 | } |
| 273 | |
| 274 | /* |
| 275 | * Curl_base64_encode() |
| 276 | * |
| 277 | * Given a pointer to an input buffer and an input size, encode it and |
| 278 | * return a pointer in *outptr to a newly allocated memory area holding |
| 279 | * encoded data. Size of encoded data is returned in variable pointed by |
| 280 | * outlen. |
| 281 | * |
| 282 | * Input length of 0 indicates input buffer holds a NUL-terminated string. |
| 283 | * |
| 284 | * Returns CURLE_OK on success, otherwise specific error code. Function |
| 285 | * output shall not be considered valid unless CURLE_OK is returned. |
| 286 | * |
| 287 | * When encoded data length is 0, returns NULL in *outptr. |
| 288 | * |
| 289 | * @unittest: 1302 |
| 290 | */ |
Alex Deymo | e3149cc | 2016-10-05 11:18:42 -0700 | [diff] [blame] | 291 | CURLcode Curl_base64_encode(struct Curl_easy *data, |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 292 | const char *inputbuff, size_t insize, |
| 293 | char **outptr, size_t *outlen) |
| 294 | { |
| 295 | return base64_encode(base64, data, inputbuff, insize, outptr, outlen); |
| 296 | } |
| 297 | |
| 298 | /* |
| 299 | * Curl_base64url_encode() |
| 300 | * |
| 301 | * Given a pointer to an input buffer and an input size, encode it and |
| 302 | * return a pointer in *outptr to a newly allocated memory area holding |
| 303 | * encoded data. Size of encoded data is returned in variable pointed by |
| 304 | * outlen. |
| 305 | * |
| 306 | * Input length of 0 indicates input buffer holds a NUL-terminated string. |
| 307 | * |
| 308 | * Returns CURLE_OK on success, otherwise specific error code. Function |
| 309 | * output shall not be considered valid unless CURLE_OK is returned. |
| 310 | * |
| 311 | * When encoded data length is 0, returns NULL in *outptr. |
| 312 | * |
| 313 | * @unittest: 1302 |
| 314 | */ |
Alex Deymo | e3149cc | 2016-10-05 11:18:42 -0700 | [diff] [blame] | 315 | CURLcode Curl_base64url_encode(struct Curl_easy *data, |
Bertrand SIMONNET | e6cd738 | 2015-07-01 15:39:44 -0700 | [diff] [blame] | 316 | const char *inputbuff, size_t insize, |
| 317 | char **outptr, size_t *outlen) |
| 318 | { |
| 319 | return base64_encode(base64url, data, inputbuff, insize, outptr, outlen); |
Kristian Monsen | 5ab5018 | 2010-05-14 18:53:44 +0100 | [diff] [blame] | 320 | } |