ru-se.com

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

Common.php (6679B)


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