tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

base64.c (7027B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "plbase64.h"
      7 #include "prlog.h" /* For PR_NOT_REACHED */
      8 #include "prmem.h" /* for malloc / PR_MALLOC */
      9 
     10 #include <string.h> /* for strlen */
     11 
     12 static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     13 
     14 static void encode3to4(const unsigned char* src, unsigned char* dest) {
     15  PRUint32 b32 = (PRUint32)0;
     16  PRIntn i, j = 18;
     17 
     18  for (i = 0; i < 3; i++) {
     19    b32 <<= 8;
     20    b32 |= (PRUint32)src[i];
     21  }
     22 
     23  for (i = 0; i < 4; i++) {
     24    dest[i] = base[(PRUint32)((b32 >> j) & 0x3F)];
     25    j -= 6;
     26  }
     27 
     28  return;
     29 }
     30 
     31 static void encode2to4(const unsigned char* src, unsigned char* dest) {
     32  dest[0] = base[(PRUint32)((src[0] >> 2) & 0x3F)];
     33  dest[1] = base[(PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F))];
     34  dest[2] = base[(PRUint32)((src[1] & 0x0F) << 2)];
     35  dest[3] = (unsigned char)'=';
     36  return;
     37 }
     38 
     39 static void encode1to4(const unsigned char* src, unsigned char* dest) {
     40  dest[0] = base[(PRUint32)((src[0] >> 2) & 0x3F)];
     41  dest[1] = base[(PRUint32)((src[0] & 0x03) << 4)];
     42  dest[2] = (unsigned char)'=';
     43  dest[3] = (unsigned char)'=';
     44  return;
     45 }
     46 
     47 static void encode(const unsigned char* src, PRUint32 srclen,
     48                   unsigned char* dest) {
     49  while (srclen >= 3) {
     50    encode3to4(src, dest);
     51    src += 3;
     52    dest += 4;
     53    srclen -= 3;
     54  }
     55 
     56  switch (srclen) {
     57    case 2:
     58      encode2to4(src, dest);
     59      break;
     60    case 1:
     61      encode1to4(src, dest);
     62      break;
     63    case 0:
     64      break;
     65    default:
     66      PR_NOT_REACHED("coding error");
     67  }
     68 
     69  return;
     70 }
     71 
     72 /*
     73 * PL_Base64Encode
     74 *
     75 * If the destination argument is NULL, a return buffer is
     76 * allocated, and the data therein will be null-terminated.
     77 * If the destination argument is not NULL, it is assumed to
     78 * be of sufficient size, and the contents will not be null-
     79 * terminated by this routine.
     80 *
     81 * Returns null if the allocation fails.
     82 */
     83 
     84 PR_IMPLEMENT(char*)
     85 PL_Base64Encode(const char* src, PRUint32 srclen, char* dest) {
     86  if (0 == srclen) {
     87    size_t len = strlen(src);
     88    srclen = len;
     89    /* Detect truncation. */
     90    if (srclen != len) {
     91      return (char*)0;
     92    }
     93  }
     94 
     95  if ((char*)0 == dest) {
     96    PRUint32 destlen;
     97    /* Ensure all PRUint32 values stay within range. */
     98    if (srclen > (PR_UINT32_MAX / 4) * 3) {
     99      return (char*)0;
    100    }
    101    destlen = ((srclen + 2) / 3) * 4;
    102    dest = (char*)PR_MALLOC(destlen + 1);
    103    if ((char*)0 == dest) {
    104      return (char*)0;
    105    }
    106    dest[destlen] = (char)0; /* null terminate */
    107  }
    108 
    109  encode((const unsigned char*)src, srclen, (unsigned char*)dest);
    110  return dest;
    111 }
    112 
    113 static PRInt32 codetovalue(unsigned char c) {
    114  if ((c >= (unsigned char)'A') && (c <= (unsigned char)'Z')) {
    115    return (PRInt32)(c - (unsigned char)'A');
    116  } else if ((c >= (unsigned char)'a') && (c <= (unsigned char)'z')) {
    117    return ((PRInt32)(c - (unsigned char)'a') + 26);
    118  } else if ((c >= (unsigned char)'0') && (c <= (unsigned char)'9')) {
    119    return ((PRInt32)(c - (unsigned char)'0') + 52);
    120  } else if ((unsigned char)'+' == c) {
    121    return (PRInt32)62;
    122  } else if ((unsigned char)'/' == c) {
    123    return (PRInt32)63;
    124  } else {
    125    return -1;
    126  }
    127 }
    128 
    129 static PRStatus decode4to3(const unsigned char* src, unsigned char* dest) {
    130  PRUint32 b32 = (PRUint32)0;
    131  PRInt32 bits;
    132  PRIntn i;
    133 
    134  for (i = 0; i < 4; i++) {
    135    bits = codetovalue(src[i]);
    136    if (bits < 0) {
    137      return PR_FAILURE;
    138    }
    139 
    140    b32 <<= 6;
    141    b32 |= bits;
    142  }
    143 
    144  dest[0] = (unsigned char)((b32 >> 16) & 0xFF);
    145  dest[1] = (unsigned char)((b32 >> 8) & 0xFF);
    146  dest[2] = (unsigned char)((b32) & 0xFF);
    147 
    148  return PR_SUCCESS;
    149 }
    150 
    151 static PRStatus decode3to2(const unsigned char* src, unsigned char* dest) {
    152  PRUint32 b32 = (PRUint32)0;
    153  PRInt32 bits;
    154  PRUint32 ubits;
    155 
    156  bits = codetovalue(src[0]);
    157  if (bits < 0) {
    158    return PR_FAILURE;
    159  }
    160 
    161  b32 = (PRUint32)bits;
    162  b32 <<= 6;
    163 
    164  bits = codetovalue(src[1]);
    165  if (bits < 0) {
    166    return PR_FAILURE;
    167  }
    168 
    169  b32 |= (PRUint32)bits;
    170  b32 <<= 4;
    171 
    172  bits = codetovalue(src[2]);
    173  if (bits < 0) {
    174    return PR_FAILURE;
    175  }
    176 
    177  ubits = (PRUint32)bits;
    178  b32 |= (ubits >> 2);
    179 
    180  dest[0] = (unsigned char)((b32 >> 8) & 0xFF);
    181  dest[1] = (unsigned char)((b32) & 0xFF);
    182 
    183  return PR_SUCCESS;
    184 }
    185 
    186 static PRStatus decode2to1(const unsigned char* src, unsigned char* dest) {
    187  PRUint32 b32;
    188  PRUint32 ubits;
    189  PRInt32 bits;
    190 
    191  bits = codetovalue(src[0]);
    192  if (bits < 0) {
    193    return PR_FAILURE;
    194  }
    195 
    196  ubits = (PRUint32)bits;
    197  b32 = (ubits << 2);
    198 
    199  bits = codetovalue(src[1]);
    200  if (bits < 0) {
    201    return PR_FAILURE;
    202  }
    203 
    204  ubits = (PRUint32)bits;
    205  b32 |= (ubits >> 4);
    206 
    207  dest[0] = (unsigned char)b32;
    208 
    209  return PR_SUCCESS;
    210 }
    211 
    212 static PRStatus decode(const unsigned char* src, PRUint32 srclen,
    213                       unsigned char* dest) {
    214  PRStatus rv;
    215 
    216  while (srclen >= 4) {
    217    rv = decode4to3(src, dest);
    218    if (PR_SUCCESS != rv) {
    219      return PR_FAILURE;
    220    }
    221 
    222    src += 4;
    223    dest += 3;
    224    srclen -= 4;
    225  }
    226 
    227  switch (srclen) {
    228    case 3:
    229      rv = decode3to2(src, dest);
    230      break;
    231    case 2:
    232      rv = decode2to1(src, dest);
    233      break;
    234    case 1:
    235      rv = PR_FAILURE;
    236      break;
    237    case 0:
    238      rv = PR_SUCCESS;
    239      break;
    240    default:
    241      PR_NOT_REACHED("coding error");
    242  }
    243 
    244  return rv;
    245 }
    246 
    247 /*
    248 * PL_Base64Decode
    249 *
    250 * If the destination argument is NULL, a return buffer is
    251 * allocated and the data therein will be null-terminated.
    252 * If the destination argument is not null, it is assumed
    253 * to be of sufficient size, and the data will not be null-
    254 * terminated by this routine.
    255 *
    256 * Returns null if the allocation fails, or if the source string is
    257 * not well-formed.
    258 */
    259 
    260 PR_IMPLEMENT(char*)
    261 PL_Base64Decode(const char* src, PRUint32 srclen, char* dest) {
    262  PRStatus status;
    263  PRBool allocated = PR_FALSE;
    264 
    265  if ((char*)0 == src) {
    266    return (char*)0;
    267  }
    268 
    269  if (0 == srclen) {
    270    size_t len = strlen(src);
    271    srclen = len;
    272    /* Detect truncation. */
    273    if (srclen != len) {
    274      return (char*)0;
    275    }
    276  }
    277 
    278  if (srclen && (0 == (srclen & 3))) {
    279    if ((char)'=' == src[srclen - 1]) {
    280      if ((char)'=' == src[srclen - 2]) {
    281        srclen -= 2;
    282      } else {
    283        srclen -= 1;
    284      }
    285    }
    286  }
    287 
    288  if ((char*)0 == dest) {
    289    /* The following computes ((srclen * 3) / 4) without overflow. */
    290    PRUint32 destlen = (srclen / 4) * 3 + ((srclen % 4) * 3) / 4;
    291    dest = (char*)PR_MALLOC(destlen + 1);
    292    if ((char*)0 == dest) {
    293      return (char*)0;
    294    }
    295    dest[destlen] = (char)0; /* null terminate */
    296    allocated = PR_TRUE;
    297  }
    298 
    299  status = decode((const unsigned char*)src, srclen, (unsigned char*)dest);
    300  if (PR_SUCCESS != status) {
    301    if (PR_TRUE == allocated) {
    302      PR_DELETE(dest);
    303    }
    304 
    305    return (char*)0;
    306  }
    307 
    308  return dest;
    309 }