angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

UrlSafe.php (7731B)


      1 <?php
      2 
      3 /**
      4  * Class ParagonIE_Sodium_Core_Base64UrlSafe
      5  *
      6  *  Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
      7  *  Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
      8  */
      9 class ParagonIE_Sodium_Core_Base64_UrlSafe
     10 {
     11     // COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
     12     /**
     13      * Encode into Base64
     14      *
     15      * Base64 character set "[A-Z][a-z][0-9]+/"
     16      *
     17      * @param string $src
     18      * @return string
     19      * @throws TypeError
     20      */
     21     public static function encode($src)
     22     {
     23         return self::doEncode($src, true);
     24     }
     25 
     26     /**
     27      * Encode into Base64, no = padding
     28      *
     29      * Base64 character set "[A-Z][a-z][0-9]+/"
     30      *
     31      * @param string $src
     32      * @return string
     33      * @throws TypeError
     34      */
     35     public static function encodeUnpadded($src)
     36     {
     37         return self::doEncode($src, false);
     38     }
     39 
     40     /**
     41      * @param string $src
     42      * @param bool $pad   Include = padding?
     43      * @return string
     44      * @throws TypeError
     45      */
     46     protected static function doEncode($src, $pad = true)
     47     {
     48         $dest = '';
     49         $srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
     50         // Main loop (no padding):
     51         for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
     52             /** @var array<int, int> $chunk */
     53             $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
     54             $b0 = $chunk[1];
     55             $b1 = $chunk[2];
     56             $b2 = $chunk[3];
     57 
     58             $dest .=
     59                 self::encode6Bits(               $b0 >> 2       ) .
     60                 self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
     61                 self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
     62                 self::encode6Bits(  $b2                     & 63);
     63         }
     64         // The last chunk, which may have padding:
     65         if ($i < $srcLen) {
     66             /** @var array<int, int> $chunk */
     67             $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
     68             $b0 = $chunk[1];
     69             if ($i + 1 < $srcLen) {
     70                 $b1 = $chunk[2];
     71                 $dest .=
     72                     self::encode6Bits($b0 >> 2) .
     73                     self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
     74                     self::encode6Bits(($b1 << 2) & 63);
     75                 if ($pad) {
     76                     $dest .= '=';
     77                 }
     78             } else {
     79                 $dest .=
     80                     self::encode6Bits( $b0 >> 2) .
     81                     self::encode6Bits(($b0 << 4) & 63);
     82                 if ($pad) {
     83                     $dest .= '==';
     84                 }
     85             }
     86         }
     87         return $dest;
     88     }
     89 
     90     /**
     91      * decode from base64 into binary
     92      *
     93      * Base64 character set "./[A-Z][a-z][0-9]"
     94      *
     95      * @param string $src
     96      * @param bool $strictPadding
     97      * @return string
     98      * @throws RangeException
     99      * @throws TypeError
    100      * @psalm-suppress RedundantCondition
    101      */
    102     public static function decode($src, $strictPadding = false)
    103     {
    104         // Remove padding
    105         $srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
    106         if ($srcLen === 0) {
    107             return '';
    108         }
    109 
    110         if ($strictPadding) {
    111             if (($srcLen & 3) === 0) {
    112                 if ($src[$srcLen - 1] === '=') {
    113                     $srcLen--;
    114                     if ($src[$srcLen - 1] === '=') {
    115                         $srcLen--;
    116                     }
    117                 }
    118             }
    119             if (($srcLen & 3) === 1) {
    120                 throw new RangeException(
    121                     'Incorrect padding'
    122                 );
    123             }
    124             if ($src[$srcLen - 1] === '=') {
    125                 throw new RangeException(
    126                     'Incorrect padding'
    127                 );
    128             }
    129         } else {
    130             $src = rtrim($src, '=');
    131             $srcLen =  ParagonIE_Sodium_Core_Util::strlen($src);
    132         }
    133 
    134         $err = 0;
    135         $dest = '';
    136         // Main loop (no padding):
    137         for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
    138             /** @var array<int, int> $chunk */
    139             $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
    140             $c0 = self::decode6Bits($chunk[1]);
    141             $c1 = self::decode6Bits($chunk[2]);
    142             $c2 = self::decode6Bits($chunk[3]);
    143             $c3 = self::decode6Bits($chunk[4]);
    144 
    145             $dest .= pack(
    146                 'CCC',
    147                 ((($c0 << 2) | ($c1 >> 4)) & 0xff),
    148                 ((($c1 << 4) | ($c2 >> 2)) & 0xff),
    149                 ((($c2 << 6) | $c3) & 0xff)
    150             );
    151             $err |= ($c0 | $c1 | $c2 | $c3) >> 8;
    152         }
    153         // The last chunk, which may have padding:
    154         if ($i < $srcLen) {
    155             /** @var array<int, int> $chunk */
    156             $chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
    157             $c0 = self::decode6Bits($chunk[1]);
    158 
    159             if ($i + 2 < $srcLen) {
    160                 $c1 = self::decode6Bits($chunk[2]);
    161                 $c2 = self::decode6Bits($chunk[3]);
    162                 $dest .= pack(
    163                     'CC',
    164                     ((($c0 << 2) | ($c1 >> 4)) & 0xff),
    165                     ((($c1 << 4) | ($c2 >> 2)) & 0xff)
    166                 );
    167                 $err |= ($c0 | $c1 | $c2) >> 8;
    168             } elseif ($i + 1 < $srcLen) {
    169                 $c1 = self::decode6Bits($chunk[2]);
    170                 $dest .= pack(
    171                     'C',
    172                     ((($c0 << 2) | ($c1 >> 4)) & 0xff)
    173                 );
    174                 $err |= ($c0 | $c1) >> 8;
    175             } elseif ($i < $srcLen && $strictPadding) {
    176                 $err |= 1;
    177             }
    178         }
    179         /** @var bool $check */
    180         $check = ($err === 0);
    181         if (!$check) {
    182             throw new RangeException(
    183                 'Base64::decode() only expects characters in the correct base64 alphabet'
    184             );
    185         }
    186         return $dest;
    187     }
    188     // COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
    189     /**
    190      * Uses bitwise operators instead of table-lookups to turn 6-bit integers
    191      * into 8-bit integers.
    192      *
    193      * Base64 character set:
    194      * [A-Z]      [a-z]      [0-9]      +     /
    195      * 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
    196      *
    197      * @param int $src
    198      * @return int
    199      */
    200     protected static function decode6Bits($src)
    201     {
    202         $ret = -1;
    203 
    204         // if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
    205         $ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
    206 
    207         // if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
    208         $ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
    209 
    210         // if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
    211         $ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
    212 
    213         // if ($src == 0x2c) $ret += 62 + 1;
    214         $ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;
    215 
    216         // if ($src == 0x5f) ret += 63 + 1;
    217         $ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;
    218 
    219         return $ret;
    220     }
    221 
    222     /**
    223      * Uses bitwise operators instead of table-lookups to turn 8-bit integers
    224      * into 6-bit integers.
    225      *
    226      * @param int $src
    227      * @return string
    228      */
    229     protected static function encode6Bits($src)
    230     {
    231         $diff = 0x41;
    232 
    233         // if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
    234         $diff += ((25 - $src) >> 8) & 6;
    235 
    236         // if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
    237         $diff -= ((51 - $src) >> 8) & 75;
    238 
    239         // if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
    240         $diff -= ((61 - $src) >> 8) & 13;
    241 
    242         // if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
    243         $diff += ((62 - $src) >> 8) & 49;
    244 
    245         return pack('C', $src + $diff);
    246     }
    247 }