quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

base64.c (8363B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 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  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 /* Base64 encoding/decoding */
     26 
     27 #include "../curl_setup.h"
     28 
     29 #if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
     30   !defined(CURL_DISABLE_LDAP) || \
     31   !defined(CURL_DISABLE_SMTP) || \
     32   !defined(CURL_DISABLE_POP3) || \
     33   !defined(CURL_DISABLE_IMAP) || \
     34   !defined(CURL_DISABLE_DIGEST_AUTH) || \
     35   !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || !defined(BUILDING_LIBCURL)
     36 #include <curl/curl.h>
     37 #include "warnless.h"
     38 #include "base64.h"
     39 
     40 /* The last 2 #include files should be in this order */
     41 #ifdef BUILDING_LIBCURL
     42 #include "../curl_memory.h"
     43 #endif
     44 #include "../memdebug.h"
     45 
     46 /* ---- Base64 Encoding/Decoding Table --- */
     47 const char Curl_base64encdec[]=
     48   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     49 
     50 /* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648
     51    section 5 */
     52 static const char base64url[]=
     53   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
     54 
     55 static const unsigned char decodetable[] =
     56 { 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255,
     57   255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
     58   17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28,
     59   29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
     60   48, 49, 50, 51 };
     61 /*
     62  * curlx_base64_decode()
     63  *
     64  * Given a base64 null-terminated string at src, decode it and return a
     65  * pointer in *outptr to a newly allocated memory area holding decoded data.
     66  * Size of decoded data is returned in variable pointed by outlen.
     67  *
     68  * Returns CURLE_OK on success, otherwise specific error code. Function
     69  * output shall not be considered valid unless CURLE_OK is returned.
     70  *
     71  * When decoded data length is 0, returns NULL in *outptr.
     72  *
     73  * @unittest: 1302
     74  */
     75 CURLcode curlx_base64_decode(const char *src,
     76                              unsigned char **outptr, size_t *outlen)
     77 {
     78   size_t srclen = 0;
     79   size_t padding = 0;
     80   size_t i;
     81   size_t numQuantums;
     82   size_t fullQuantums;
     83   size_t rawlen = 0;
     84   unsigned char *pos;
     85   unsigned char *newstr;
     86   unsigned char lookup[256];
     87 
     88   *outptr = NULL;
     89   *outlen = 0;
     90   srclen = strlen(src);
     91 
     92   /* Check the length of the input string is valid */
     93   if(!srclen || srclen % 4)
     94     return CURLE_BAD_CONTENT_ENCODING;
     95 
     96   /* srclen is at least 4 here */
     97   while(src[srclen - 1 - padding] == '=') {
     98     /* count padding characters */
     99     padding++;
    100     /* A maximum of two = padding characters is allowed */
    101     if(padding > 2)
    102       return CURLE_BAD_CONTENT_ENCODING;
    103   }
    104 
    105   /* Calculate the number of quantums */
    106   numQuantums = srclen / 4;
    107   fullQuantums = numQuantums - (padding ? 1 : 0);
    108 
    109   /* Calculate the size of the decoded string */
    110   rawlen = (numQuantums * 3) - padding;
    111 
    112   /* Allocate our buffer including room for a null-terminator */
    113   newstr = malloc(rawlen + 1);
    114   if(!newstr)
    115     return CURLE_OUT_OF_MEMORY;
    116 
    117   pos = newstr;
    118 
    119   memset(lookup, 0xff, sizeof(lookup));
    120   memcpy(&lookup['+'], decodetable, sizeof(decodetable));
    121 
    122   /* Decode the complete quantums first */
    123   for(i = 0; i < fullQuantums; i++) {
    124     unsigned char val;
    125     unsigned int x = 0;
    126     int j;
    127 
    128     for(j = 0; j < 4; j++) {
    129       val = lookup[(unsigned char)*src++];
    130       if(val == 0xff) /* bad symbol */
    131         goto bad;
    132       x = (x << 6) | val;
    133     }
    134     pos[2] = x & 0xff;
    135     pos[1] = (x >> 8) & 0xff;
    136     pos[0] = (x >> 16) & 0xff;
    137     pos += 3;
    138   }
    139   if(padding) {
    140     /* this means either 8 or 16 bits output */
    141     unsigned char val;
    142     unsigned int x = 0;
    143     int j;
    144     size_t padc = 0;
    145     for(j = 0; j < 4; j++) {
    146       if(*src == '=') {
    147         x <<= 6;
    148         src++;
    149         if(++padc > padding)
    150           /* this is a badly placed '=' symbol! */
    151           goto bad;
    152       }
    153       else {
    154         val = lookup[(unsigned char)*src++];
    155         if(val == 0xff) /* bad symbol */
    156           goto bad;
    157         x = (x << 6) | val;
    158       }
    159     }
    160     if(padding == 1)
    161       pos[1] = (x >> 8) & 0xff;
    162     pos[0] = (x >> 16) & 0xff;
    163     pos += 3 - padding;
    164   }
    165 
    166   /* Zero terminate */
    167   *pos = '\0';
    168 
    169   /* Return the decoded data */
    170   *outptr = newstr;
    171   *outlen = rawlen;
    172 
    173   return CURLE_OK;
    174 bad:
    175   free(newstr);
    176   return CURLE_BAD_CONTENT_ENCODING;
    177 }
    178 
    179 static CURLcode base64_encode(const char *table64,
    180                               unsigned char padbyte,
    181                               const char *inputbuff, size_t insize,
    182                               char **outptr, size_t *outlen)
    183 {
    184   char *output;
    185   char *base64data;
    186   const unsigned char *in = (const unsigned char *)inputbuff;
    187 
    188   *outptr = NULL;
    189   *outlen = 0;
    190 
    191   if(!insize)
    192     insize = strlen(inputbuff);
    193 
    194 #if SIZEOF_SIZE_T == 4
    195   if(insize > UINT_MAX/4)
    196     return CURLE_OUT_OF_MEMORY;
    197 #endif
    198 
    199   base64data = output = malloc((insize + 2) / 3 * 4 + 1);
    200   if(!output)
    201     return CURLE_OUT_OF_MEMORY;
    202 
    203   while(insize >= 3) {
    204     *output++ = table64[ in[0] >> 2 ];
    205     *output++ = table64[ ((in[0] & 0x03) << 4) | (in[1] >> 4) ];
    206     *output++ = table64[ ((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ];
    207     *output++ = table64[ in[2] & 0x3F ];
    208     insize -= 3;
    209     in += 3;
    210   }
    211   if(insize) {
    212     /* this is only one or two bytes now */
    213     *output++ = table64[ in[0] >> 2 ];
    214     if(insize == 1) {
    215       *output++ = table64[ ((in[0] & 0x03) << 4) ];
    216       if(padbyte) {
    217         *output++ = padbyte;
    218         *output++ = padbyte;
    219       }
    220     }
    221     else {
    222       /* insize == 2 */
    223       *output++ = table64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4) ];
    224       *output++ = table64[ ((in[1] & 0x0F) << 2) ];
    225       if(padbyte)
    226         *output++ = padbyte;
    227     }
    228   }
    229 
    230   /* Zero terminate */
    231   *output = '\0';
    232 
    233   /* Return the pointer to the new data (allocated memory) */
    234   *outptr = base64data;
    235 
    236   /* Return the length of the new data */
    237   *outlen = (size_t)(output - base64data);
    238 
    239   return CURLE_OK;
    240 }
    241 
    242 /*
    243  * curlx_base64_encode()
    244  *
    245  * Given a pointer to an input buffer and an input size, encode it and
    246  * return a pointer in *outptr to a newly allocated memory area holding
    247  * encoded data. Size of encoded data is returned in variable pointed by
    248  * outlen.
    249  *
    250  * Input length of 0 indicates input buffer holds a null-terminated string.
    251  *
    252  * Returns CURLE_OK on success, otherwise specific error code. Function
    253  * output shall not be considered valid unless CURLE_OK is returned.
    254  *
    255  * @unittest: 1302
    256  */
    257 CURLcode curlx_base64_encode(const char *inputbuff, size_t insize,
    258                              char **outptr, size_t *outlen)
    259 {
    260   return base64_encode(Curl_base64encdec, '=',
    261                        inputbuff, insize, outptr, outlen);
    262 }
    263 
    264 /*
    265  * curlx_base64url_encode()
    266  *
    267  * Given a pointer to an input buffer and an input size, encode it and
    268  * return a pointer in *outptr to a newly allocated memory area holding
    269  * encoded data. Size of encoded data is returned in variable pointed by
    270  * outlen.
    271  *
    272  * Input length of 0 indicates input buffer holds a null-terminated string.
    273  *
    274  * Returns CURLE_OK on success, otherwise specific error code. Function
    275  * output shall not be considered valid unless CURLE_OK is returned.
    276  *
    277  * @unittest: 1302
    278  */
    279 CURLcode curlx_base64url_encode(const char *inputbuff, size_t insize,
    280                                 char **outptr, size_t *outlen)
    281 {
    282   return base64_encode(base64url, 0, inputbuff, insize, outptr, outlen);
    283 }
    284 
    285 #endif /* no users so disabled */