[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

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

   1  <?php
   2  
   3  /**
   4   * Pure-PHP implementation of Triple DES.
   5   *
   6   * Uses mcrypt, if available, and an internal implementation, otherwise.  Operates in the EDE3 mode (encrypt-decrypt-encrypt).
   7   *
   8   * PHP version 5
   9   *
  10   * Here's a short example of how to use this library:
  11   * <code>
  12   * <?php
  13   *    include 'vendor/autoload.php';
  14   *
  15   *    $des = new \phpseclib3\Crypt\TripleDES('ctr');
  16   *
  17   *    $des->setKey('abcdefghijklmnopqrstuvwx');
  18   *
  19   *    $size = 10 * 1024;
  20   *    $plaintext = '';
  21   *    for ($i = 0; $i < $size; $i++) {
  22   *        $plaintext.= 'a';
  23   *    }
  24   *
  25   *    echo $des->decrypt($des->encrypt($plaintext));
  26   * ?>
  27   * </code>
  28   *
  29   * @author    Jim Wigginton <terrafrost@php.net>
  30   * @copyright 2007 Jim Wigginton
  31   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  32   * @link      http://phpseclib.sourceforge.net
  33   */
  34  
  35  namespace phpseclib3\Crypt;
  36  
  37  /**
  38   * Pure-PHP implementation of Triple DES.
  39   *
  40   * @author  Jim Wigginton <terrafrost@php.net>
  41   */
  42  class TripleDES extends DES
  43  {
  44      /**
  45       * Encrypt / decrypt using inner chaining
  46       *
  47       * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (self::MODE_CBC3).
  48       */
  49      const MODE_3CBC = -2;
  50  
  51      /**
  52       * Encrypt / decrypt using outer chaining
  53       *
  54       * Outer chaining is used by SSH-2 and when the mode is set to \phpseclib3\Crypt\Common\BlockCipher::MODE_CBC.
  55       */
  56      const MODE_CBC3 = self::MODE_CBC;
  57  
  58      /**
  59       * Key Length (in bytes)
  60       *
  61       * @see \phpseclib3\Crypt\TripleDES::setKeyLength()
  62       * @var int
  63       */
  64      protected $key_length = 24;
  65  
  66      /**
  67       * The mcrypt specific name of the cipher
  68       *
  69       * @see \phpseclib3\Crypt\DES::cipher_name_mcrypt
  70       * @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
  71       * @var string
  72       */
  73      protected $cipher_name_mcrypt = 'tripledes';
  74  
  75      /**
  76       * Optimizing value while CFB-encrypting
  77       *
  78       * @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
  79       * @var int
  80       */
  81      protected $cfb_init_len = 750;
  82  
  83      /**
  84       * max possible size of $key
  85       *
  86       * @see self::setKey()
  87       * @see \phpseclib3\Crypt\DES::setKey()
  88       * @var string
  89       */
  90      protected $key_length_max = 24;
  91  
  92      /**
  93       * Internal flag whether using self::MODE_3CBC or not
  94       *
  95       * @var bool
  96       */
  97      private $mode_3cbc;
  98  
  99      /**
 100       * The \phpseclib3\Crypt\DES objects
 101       *
 102       * Used only if $mode_3cbc === true
 103       *
 104       * @var array
 105       */
 106      private $des;
 107  
 108      /**
 109       * Default Constructor.
 110       *
 111       * Determines whether or not the mcrypt or OpenSSL extensions should be used.
 112       *
 113       * $mode could be:
 114       *
 115       * - ecb
 116       *
 117       * - cbc
 118       *
 119       * - ctr
 120       *
 121       * - cfb
 122       *
 123       * - ofb
 124       *
 125       * - 3cbc
 126       *
 127       * - cbc3 (same as cbc)
 128       *
 129       * @see \phpseclib3\Crypt\DES::__construct()
 130       * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
 131       * @param string $mode
 132       */
 133      public function __construct($mode)
 134      {
 135          switch (strtolower($mode)) {
 136              // In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
 137              // and additional flag us internally as 3CBC
 138              case '3cbc':
 139                  parent::__construct('cbc');
 140                  $this->mode_3cbc = true;
 141  
 142                  // This three $des'es will do the 3CBC work (if $key > 64bits)
 143                  $this->des = [
 144                      new DES('cbc'),
 145                      new DES('cbc'),
 146                      new DES('cbc'),
 147                  ];
 148  
 149                  // we're going to be doing the padding, ourselves, so disable it in the \phpseclib3\Crypt\DES objects
 150                  $this->des[0]->disablePadding();
 151                  $this->des[1]->disablePadding();
 152                  $this->des[2]->disablePadding();
 153                  break;
 154              case 'cbc3':
 155                  $mode = 'cbc';
 156                  // fall-through
 157              // If not 3CBC, we init as usual
 158              default:
 159                  parent::__construct($mode);
 160  
 161                  if ($this->mode == self::MODE_STREAM) {
 162                      throw new BadModeException('Block ciphers cannot be ran in stream mode');
 163                  }
 164          }
 165      }
 166  
 167      /**
 168       * Test for engine validity
 169       *
 170       * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
 171       *
 172       * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
 173       * @param int $engine
 174       * @return bool
 175       */
 176      protected function isValidEngineHelper($engine)
 177      {
 178          if ($engine == self::ENGINE_OPENSSL) {
 179              $this->cipher_name_openssl_ecb = 'des-ede3';
 180              $mode = $this->openssl_translate_mode();
 181              $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode;
 182          }
 183  
 184          return parent::isValidEngineHelper($engine);
 185      }
 186  
 187      /**
 188       * Sets the initialization vector.
 189       *
 190       * SetIV is not required when \phpseclib3\Crypt\Common\SymmetricKey::MODE_ECB is being used.
 191       *
 192       * @see \phpseclib3\Crypt\Common\SymmetricKey::setIV()
 193       * @param string $iv
 194       */
 195      public function setIV($iv)
 196      {
 197          parent::setIV($iv);
 198          if ($this->mode_3cbc) {
 199              $this->des[0]->setIV($iv);
 200              $this->des[1]->setIV($iv);
 201              $this->des[2]->setIV($iv);
 202          }
 203      }
 204  
 205      /**
 206       * Sets the key length.
 207       *
 208       * Valid key lengths are 128 and 192 bits.
 209       *
 210       * If you want to use a 64-bit key use DES.php
 211       *
 212       * @see \phpseclib3\Crypt\Common\SymmetricKey:setKeyLength()
 213       * @throws \LengthException if the key length is invalid
 214       * @param int $length
 215       */
 216      public function setKeyLength($length)
 217      {
 218          switch ($length) {
 219              case 128:
 220              case 192:
 221                  break;
 222              default:
 223                  throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128 or 192 bits are supported');
 224          }
 225  
 226          parent::setKeyLength($length);
 227      }
 228  
 229      /**
 230       * Sets the key.
 231       *
 232       * Triple DES can use 128-bit (eg. strlen($key) == 16) or 192-bit (eg. strlen($key) == 24) keys.
 233       *
 234       * DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
 235       *
 236       * @see \phpseclib3\Crypt\DES::setKey()
 237       * @see \phpseclib3\Crypt\Common\SymmetricKey::setKey()
 238       * @throws \LengthException if the key length is invalid
 239       * @param string $key
 240       */
 241      public function setKey($key)
 242      {
 243          if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
 244              throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
 245          }
 246  
 247          switch (strlen($key)) {
 248              case 16:
 249                  $key .= substr($key, 0, 8);
 250                  break;
 251              case 24:
 252                  break;
 253              default:
 254                  throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported');
 255          }
 256  
 257          // copied from self::setKey()
 258          $this->key = $key;
 259          $this->key_length = strlen($key);
 260          $this->changed = $this->nonIVChanged = true;
 261          $this->setEngine();
 262  
 263          if ($this->mode_3cbc) {
 264              $this->des[0]->setKey(substr($key, 0, 8));
 265              $this->des[1]->setKey(substr($key, 8, 8));
 266              $this->des[2]->setKey(substr($key, 16, 8));
 267          }
 268      }
 269  
 270      /**
 271       * Encrypts a message.
 272       *
 273       * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
 274       * @param string $plaintext
 275       * @return string $cipertext
 276       */
 277      public function encrypt($plaintext)
 278      {
 279          // parent::en/decrypt() is able to do all the work for all modes and keylengths,
 280          // except for: self::MODE_3CBC (inner chaining CBC) with a key > 64bits
 281  
 282          // if the key is smaller then 8, do what we'd normally do
 283          if ($this->mode_3cbc && strlen($this->key) > 8) {
 284              return $this->des[2]->encrypt(
 285                  $this->des[1]->decrypt(
 286                      $this->des[0]->encrypt(
 287                          $this->pad($plaintext)
 288                      )
 289                  )
 290              );
 291          }
 292  
 293          return parent::encrypt($plaintext);
 294      }
 295  
 296      /**
 297       * Decrypts a message.
 298       *
 299       * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
 300       * @param string $ciphertext
 301       * @return string $plaintext
 302       */
 303      public function decrypt($ciphertext)
 304      {
 305          if ($this->mode_3cbc && strlen($this->key) > 8) {
 306              return $this->unpad(
 307                  $this->des[0]->decrypt(
 308                      $this->des[1]->encrypt(
 309                          $this->des[2]->decrypt(
 310                              str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0")
 311                          )
 312                      )
 313                  )
 314              );
 315          }
 316  
 317          return parent::decrypt($ciphertext);
 318      }
 319  
 320      /**
 321       * Treat consecutive "packets" as if they are a continuous buffer.
 322       *
 323       * Say you have a 16-byte plaintext $plaintext.  Using the default behavior, the two following code snippets
 324       * will yield different outputs:
 325       *
 326       * <code>
 327       *    echo $des->encrypt(substr($plaintext, 0, 8));
 328       *    echo $des->encrypt(substr($plaintext, 8, 8));
 329       * </code>
 330       * <code>
 331       *    echo $des->encrypt($plaintext);
 332       * </code>
 333       *
 334       * The solution is to enable the continuous buffer.  Although this will resolve the above discrepancy, it creates
 335       * another, as demonstrated with the following:
 336       *
 337       * <code>
 338       *    $des->encrypt(substr($plaintext, 0, 8));
 339       *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
 340       * </code>
 341       * <code>
 342       *    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
 343       * </code>
 344       *
 345       * With the continuous buffer disabled, these would yield the same output.  With it enabled, they yield different
 346       * outputs.  The reason is due to the fact that the initialization vector's change after every encryption /
 347       * decryption round when the continuous buffer is enabled.  When it's disabled, they remain constant.
 348       *
 349       * Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt\DES() object changes after each
 350       * encryption / decryption round, whereas otherwise, it'd remain constant.  For this reason, it's recommended that
 351       * continuous buffers not be used.  They do offer better security and are, in fact, sometimes required (SSH uses them),
 352       * however, they are also less intuitive and more likely to cause you problems.
 353       *
 354       * @see \phpseclib3\Crypt\Common\SymmetricKey::enableContinuousBuffer()
 355       * @see self::disableContinuousBuffer()
 356       */
 357      public function enableContinuousBuffer()
 358      {
 359          parent::enableContinuousBuffer();
 360          if ($this->mode_3cbc) {
 361              $this->des[0]->enableContinuousBuffer();
 362              $this->des[1]->enableContinuousBuffer();
 363              $this->des[2]->enableContinuousBuffer();
 364          }
 365      }
 366  
 367      /**
 368       * Treat consecutive packets as if they are a discontinuous buffer.
 369       *
 370       * The default behavior.
 371       *
 372       * @see \phpseclib3\Crypt\Common\SymmetricKey::disableContinuousBuffer()
 373       * @see self::enableContinuousBuffer()
 374       */
 375      public function disableContinuousBuffer()
 376      {
 377          parent::disableContinuousBuffer();
 378          if ($this->mode_3cbc) {
 379              $this->des[0]->disableContinuousBuffer();
 380              $this->des[1]->disableContinuousBuffer();
 381              $this->des[2]->disableContinuousBuffer();
 382          }
 383      }
 384  
 385      /**
 386       * Creates the key schedule
 387       *
 388       * @see \phpseclib3\Crypt\DES::setupKey()
 389       * @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey()
 390       */
 391      protected function setupKey()
 392      {
 393          switch (true) {
 394              // if $key <= 64bits we configure our internal pure-php cipher engine
 395              // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same.
 396              case strlen($this->key) <= 8:
 397                  $this->des_rounds = 1;
 398                  break;
 399  
 400              // otherwise, if $key > 64bits, we configure our engine to work as 3DES.
 401              default:
 402                  $this->des_rounds = 3;
 403  
 404                  // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately.
 405                  if ($this->mode_3cbc) {
 406                      $this->des[0]->setupKey();
 407                      $this->des[1]->setupKey();
 408                      $this->des[2]->setupKey();
 409  
 410                      // because $des[0-2] will, now, do all the work we can return here
 411                      // not need unnecessary stress parent::setupKey() with our, now unused, $key.
 412                      return;
 413                  }
 414          }
 415          // setup our key
 416          parent::setupKey();
 417      }
 418  
 419      /**
 420       * Sets the internal crypt engine
 421       *
 422       * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
 423       * @see \phpseclib3\Crypt\Common\SymmetricKey::setPreferredEngine()
 424       * @param int $engine
 425       */
 426      public function setPreferredEngine($engine)
 427      {
 428          if ($this->mode_3cbc) {
 429              $this->des[0]->setPreferredEngine($engine);
 430              $this->des[1]->setPreferredEngine($engine);
 431              $this->des[2]->setPreferredEngine($engine);
 432          }
 433  
 434          parent::setPreferredEngine($engine);
 435      }
 436  }