[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/ -> RC4.php (source)

   1  <?php
   2  
   3  /**
   4   * Pure-PHP implementation of RC4.
   5   *
   6   * Uses mcrypt, if available, and an internal implementation, otherwise.
   7   *
   8   * PHP version 5
   9   *
  10   * Useful resources are as follows:
  11   *
  12   *  - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
  13   *  - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
  14   *
  15   * RC4 is also known as ARCFOUR or ARC4.  The reason is elaborated upon at Wikipedia.  This class is named RC4 and not
  16   * ARCFOUR or ARC4 because RC4 is how it is referred to in the SSH1 specification.
  17   *
  18   * Here's a short example of how to use this library:
  19   * <code>
  20   * <?php
  21   *    include 'vendor/autoload.php';
  22   *
  23   *    $rc4 = new \phpseclib3\Crypt\RC4();
  24   *
  25   *    $rc4->setKey('abcdefgh');
  26   *
  27   *    $size = 10 * 1024;
  28   *    $plaintext = '';
  29   *    for ($i = 0; $i < $size; $i++) {
  30   *        $plaintext.= 'a';
  31   *    }
  32   *
  33   *    echo $rc4->decrypt($rc4->encrypt($plaintext));
  34   * ?>
  35   * </code>
  36   *
  37   * @author    Jim Wigginton <terrafrost@php.net>
  38   * @copyright 2007 Jim Wigginton
  39   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  40   * @link      http://phpseclib.sourceforge.net
  41   */
  42  
  43  namespace phpseclib3\Crypt;
  44  
  45  use phpseclib3\Crypt\Common\StreamCipher;
  46  
  47  /**
  48   * Pure-PHP implementation of RC4.
  49   *
  50   * @author  Jim Wigginton <terrafrost@php.net>
  51   */
  52  class RC4 extends StreamCipher
  53  {
  54      /**
  55       * @see \phpseclib3\Crypt\RC4::_crypt()
  56       */
  57      const ENCRYPT = 0;
  58  
  59      /**
  60       * @see \phpseclib3\Crypt\RC4::_crypt()
  61       */
  62      const DECRYPT = 1;
  63  
  64      /**
  65       * Key Length (in bytes)
  66       *
  67       * @see \phpseclib3\Crypt\RC4::setKeyLength()
  68       * @var int
  69       */
  70      protected $key_length = 128; // = 1024 bits
  71  
  72      /**
  73       * The mcrypt specific name of the cipher
  74       *
  75       * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
  76       * @var string
  77       */
  78      protected $cipher_name_mcrypt = 'arcfour';
  79  
  80      /**
  81       * The Key
  82       *
  83       * @see self::setKey()
  84       * @var string
  85       */
  86      protected $key;
  87  
  88      /**
  89       * The Key Stream for decryption and encryption
  90       *
  91       * @see self::setKey()
  92       * @var array
  93       */
  94      private $stream;
  95  
  96      /**
  97       * Test for engine validity
  98       *
  99       * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
 100       *
 101       * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
 102       * @param int $engine
 103       * @return bool
 104       */
 105      protected function isValidEngineHelper($engine)
 106      {
 107          if ($engine == self::ENGINE_OPENSSL) {
 108              if ($this->continuousBuffer) {
 109                  return false;
 110              }
 111              // quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
 112              // "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
 113              // in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
 114              if (defined('OPENSSL_VERSION_TEXT') && version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
 115                  return false;
 116              }
 117              $this->cipher_name_openssl = 'rc4-40';
 118          }
 119  
 120          return parent::isValidEngineHelper($engine);
 121      }
 122  
 123      /**
 124       * Sets the key length
 125       *
 126       * Keys can be between 1 and 256 bytes long.
 127       *
 128       * @param int $length
 129       * @throws \LengthException if the key length is invalid
 130       */
 131      public function setKeyLength($length)
 132      {
 133          if ($length < 8 || $length > 2048) {
 134              throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 256 bytes are supported');
 135          }
 136  
 137          $this->key_length = $length >> 3;
 138  
 139          parent::setKeyLength($length);
 140      }
 141  
 142      /**
 143       * Sets the key length
 144       *
 145       * Keys can be between 1 and 256 bytes long.
 146       *
 147       * @param string $key
 148       */
 149      public function setKey($key)
 150      {
 151          $length = strlen($key);
 152          if ($length < 1 || $length > 256) {
 153              throw new \LengthException('Key size of ' . $length . ' bytes is not supported by RC4. Keys must be between 1 and 256 bytes long');
 154          }
 155  
 156          parent::setKey($key);
 157      }
 158  
 159      /**
 160       * Encrypts a message.
 161       *
 162       * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
 163       * @see self::crypt()
 164       * @param string $plaintext
 165       * @return string $ciphertext
 166       */
 167      public function encrypt($plaintext)
 168      {
 169          if ($this->engine != self::ENGINE_INTERNAL) {
 170              return parent::encrypt($plaintext);
 171          }
 172          return $this->crypt($plaintext, self::ENCRYPT);
 173      }
 174  
 175      /**
 176       * Decrypts a message.
 177       *
 178       * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
 179       * At least if the continuous buffer is disabled.
 180       *
 181       * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
 182       * @see self::crypt()
 183       * @param string $ciphertext
 184       * @return string $plaintext
 185       */
 186      public function decrypt($ciphertext)
 187      {
 188          if ($this->engine != self::ENGINE_INTERNAL) {
 189              return parent::decrypt($ciphertext);
 190          }
 191          return $this->crypt($ciphertext, self::DECRYPT);
 192      }
 193  
 194      /**
 195       * Encrypts a block
 196       *
 197       * @param string $in
 198       */
 199      protected function encryptBlock($in)
 200      {
 201          // RC4 does not utilize this method
 202      }
 203  
 204      /**
 205       * Decrypts a block
 206       *
 207       * @param string $in
 208       */
 209      protected function decryptBlock($in)
 210      {
 211          // RC4 does not utilize this method
 212      }
 213  
 214      /**
 215       * Setup the key (expansion)
 216       *
 217       * @see \phpseclib3\Crypt\Common\SymmetricKey::_setupKey()
 218       */
 219      protected function setupKey()
 220      {
 221          $key = $this->key;
 222          $keyLength = strlen($key);
 223          $keyStream = range(0, 255);
 224          $j = 0;
 225          for ($i = 0; $i < 256; $i++) {
 226              $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
 227              $temp = $keyStream[$i];
 228              $keyStream[$i] = $keyStream[$j];
 229              $keyStream[$j] = $temp;
 230          }
 231  
 232          $this->stream = [];
 233          $this->stream[self::DECRYPT] = $this->stream[self::ENCRYPT] = [
 234              0, // index $i
 235              0, // index $j
 236              $keyStream
 237          ];
 238      }
 239  
 240      /**
 241       * Encrypts or decrypts a message.
 242       *
 243       * @see self::encrypt()
 244       * @see self::decrypt()
 245       * @param string $text
 246       * @param int $mode
 247       * @return string $text
 248       */
 249      private function crypt($text, $mode)
 250      {
 251          if ($this->changed) {
 252              $this->setup();
 253          }
 254  
 255          $stream = &$this->stream[$mode];
 256          if ($this->continuousBuffer) {
 257              $i = &$stream[0];
 258              $j = &$stream[1];
 259              $keyStream = &$stream[2];
 260          } else {
 261              $i = $stream[0];
 262              $j = $stream[1];
 263              $keyStream = $stream[2];
 264          }
 265  
 266          $len = strlen($text);
 267          for ($k = 0; $k < $len; ++$k) {
 268              $i = ($i + 1) & 255;
 269              $ksi = $keyStream[$i];
 270              $j = ($j + $ksi) & 255;
 271              $ksj = $keyStream[$j];
 272  
 273              $keyStream[$i] = $ksj;
 274              $keyStream[$j] = $ksi;
 275              $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]);
 276          }
 277  
 278          return $text;
 279      }
 280  }