Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   1  <?php
   2  /**
   3   * Copyright 2005-2008 Matthew Fonda <mfonda@php.net>
   4   * Copyright 2012-2017 Horde LLC (http://www.horde.org/)
   5   *
   6   * See the enclosed file LICENSE for license information (LGPL). If you
   7   * did not receive this file, see http://www.horde.org/licenses/lgpl21.
   8   *
   9   * @author   Matthew Fonda <mfonda@php.net>
  10   * @author   Michael Slusarz <slusarz@horde.org>
  11   * @category Horde
  12   * @license  http://www.horde.org/licenses/lgpl21 LGPL 2.1
  13   * @package  Crypt_Blowfish
  14   */
  15  
  16  /**
  17   * Provides blowfish encryption/decryption, with or without a secret key,
  18   * for PHP strings.
  19   *
  20   * @author    Matthew Fonda <mfonda@php.net>
  21   * @author    Michael Slusarz <slusarz@horde.org>
  22   * @category  Horde
  23   * @copyright 2005-2008 Matthew Fonda
  24   * @copyright 2012-2017 Horde LLC
  25   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  26   * @package   Crypt_Blowfish
  27   *
  28   * @property string $cipher  The cipher block mode ('ecb' or 'cbc').
  29   * @property string $key  The encryption key in use.
  30   * @property mixed $iv  The initialization vector (false if using 'ecb').
  31   */
  32  class Horde_Crypt_Blowfish
  33  {
  34      // Constants for 'ignore' parameter of constructor.
  35      const IGNORE_OPENSSL = 1;
  36      const IGNORE_MCRYPT = 2;
  37  
  38      // Block size for Blowfish
  39      const BLOCKSIZE = 8;
  40  
  41      // Maximum key size for Blowfish
  42      const MAXKEYSIZE = 56;
  43  
  44      // IV Length for CBC
  45      const IV_LENGTH = 8;
  46  
  47      /**
  48       * Blowfish crypt driver.
  49       *
  50       * @var Horde_Crypt_Blowfish_Base
  51       */
  52      protected $_crypt;
  53  
  54      /**
  55       * Constructor.
  56       *
  57       * @param string $key  Encryption key.
  58       * @param array $opts  Additional options:
  59       *   - cipher: (string) Either 'ecb' or 'cbc'.
  60       *   - ignore: (integer) A mask of drivers to ignore (IGNORE_* constants).
  61       *   - iv: (string) IV to use.
  62       */
  63      public function __construct($key, array $opts = array())
  64      {
  65          $opts = array_merge(array(
  66              'cipher' => 'ecb',
  67              'ignore' => 0,
  68              'iv' => null
  69          ), $opts);
  70  
  71          if (!($opts['ignore'] & self::IGNORE_OPENSSL) &&
  72              Horde_Crypt_Blowfish_Openssl::supported()) {
  73              $this->_crypt = new Horde_Crypt_Blowfish_Openssl($opts['cipher']);
  74          } elseif (!($opts['ignore'] & self::IGNORE_MCRYPT) &&
  75                    Horde_Crypt_Blowfish_Mcrypt::supported()) {
  76              $this->_crypt = new Horde_Crypt_Blowfish_Mcrypt($opts['cipher']);
  77          } else {
  78              $this->_crypt = new Horde_Crypt_Blowfish_Php($opts['cipher']);
  79          }
  80  
  81          $this->setKey($key, $opts['iv']);
  82      }
  83  
  84      /**
  85       */
  86      public function __get($name)
  87      {
  88          switch ($name) {
  89          case 'cipher':
  90          case 'key':
  91          case 'iv':
  92              return $this->_crypt->$name;
  93          }
  94      }
  95  
  96      /**
  97       * Encrypts a string.
  98       *
  99       * @param string $text  The string to encrypt.
 100       *
 101       * @return string  The ciphertext.
 102       * @throws Horde_Crypt_Blowfish_Exception
 103       */
 104      public function encrypt($text)
 105      {
 106          if (!is_string($text)) {
 107              throw new Horde_Crypt_Blowfish_Exception('Data to encrypt must be a string.');
 108          }
 109  
 110          return $this->_crypt->encrypt($text);
 111      }
 112  
 113      /**
 114       * Decrypts a string.
 115       *
 116       * @param string $text  The string to decrypt.
 117       *
 118       * @return string  The plaintext.
 119       * @throws Horde_Crypt_Blowfish_Exception
 120       */
 121      public function decrypt($text)
 122      {
 123          if (!is_string($text)) {
 124              throw new Horde_Crypt_Blowfish_Exception('Data to decrypt must be a string.');
 125          }
 126  
 127          return $this->_crypt->decrypt($text);
 128      }
 129  
 130      /**
 131       * Sets the secret key.
 132       *
 133       * The key must be non-zero, and less than or equal to MAXKEYSIZE
 134       * characters (bytes) in length.
 135       *
 136       * @param string $key  Key must be non-empty and less than MAXKEYSIZE
 137       *                     bytes in length.
 138       * @param string $iv   The initialization vector to use. Only needed for
 139       *                     'cbc' cipher. If null, an IV is automatically
 140       *                     generated.
 141       *
 142       * @throws Horde_Crypt_Blowfish_Exception
 143       */
 144      public function setKey($key, $iv = null)
 145      {
 146          if (!is_string($key)) {
 147              throw new Horde_Crypt_Blowfish_Exception('Encryption key must be a string.');
 148          }
 149  
 150          $len = strlen($key);
 151          if (($len > self::MAXKEYSIZE) || ($len == 0)) {
 152              throw new Horde_Crypt_Blowfish_Exception(sprintf('Encryption key must be less than %d characters (bytes) and non-zero. Supplied key length: %d', self::MAXKEYSIZE, $len));
 153          }
 154  
 155          $this->_crypt->key = $key;
 156  
 157          switch ($this->_crypt->cipher) {
 158          case 'cbc':
 159              if (is_null($iv)) {
 160                  if (is_null($this->iv)) {
 161                      $this->_crypt->setIv();
 162                  }
 163              } else {
 164                  $iv = substr($iv, 0, self::IV_LENGTH);
 165                  if (($len = strlen($iv)) < self::IV_LENGTH) {
 166                      $iv .= str_repeat(chr(0), self::IV_LENGTH - $len);
 167                  }
 168                  $this->_crypt->setIv($iv);
 169              }
 170              break;
 171  
 172          case 'ecb':
 173              $this->iv = false;
 174              break;
 175          }
 176      }
 177  
 178  }