[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/random_compat/ -> random_bytes_dev_urandom.php (source)

   1  <?php
   2  /**
   3   * Random_* Compatibility Library
   4   * for using the new PHP 7 random_* API in PHP 5 projects
   5   *
   6   * The MIT License (MIT)
   7   *
   8   * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
   9   *
  10   * Permission is hereby granted, free of charge, to any person obtaining a copy
  11   * of this software and associated documentation files (the "Software"), to deal
  12   * in the Software without restriction, including without limitation the rights
  13   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14   * copies of the Software, and to permit persons to whom the Software is
  15   * furnished to do so, subject to the following conditions:
  16   *
  17   * The above copyright notice and this permission notice shall be included in
  18   * all copies or substantial portions of the Software.
  19   *
  20   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26   * SOFTWARE.
  27   */
  28  
  29  if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
  30      define('RANDOM_COMPAT_READ_BUFFER', 8);
  31  }
  32  
  33  if (!is_callable('random_bytes')) {
  34      /**
  35       * Unless open_basedir is enabled, use /dev/urandom for
  36       * random numbers in accordance with best practices
  37       *
  38       * Why we use /dev/urandom and not /dev/random
  39       * @ref https://www.2uo.de/myths-about-urandom
  40       * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
  41       *
  42       * @param int $bytes
  43       *
  44       * @throws Exception
  45       *
  46       * @return string
  47       */
  48      function random_bytes($bytes)
  49      {
  50          /** @var resource $fp */
  51          static $fp = null;
  52  
  53          /**
  54           * This block should only be run once
  55           */
  56          if (empty($fp)) {
  57              /**
  58               * We don't want to ever read C:\dev\random, only /dev/urandom on
  59               * Unix-like operating systems. While we guard against this
  60               * condition in random.php, it doesn't hurt to be defensive in depth
  61               * here.
  62               *
  63               * To that end, we only try to open /dev/urandom if we're on a Unix-
  64               * like operating system (which means the directory separator is set
  65               * to "/" not "\".
  66               */
  67              if (DIRECTORY_SEPARATOR === '/') {
  68                  if (!is_readable('/dev/urandom')) {
  69                      throw new Exception(
  70                          'Environment misconfiguration: ' .
  71                          '/dev/urandom cannot be read.'
  72                      );
  73                  }
  74                  /**
  75                   * We use /dev/urandom if it is a char device.
  76                   * We never fall back to /dev/random
  77                   */
  78                  /** @var resource|bool $fp */
  79                  $fp = fopen('/dev/urandom', 'rb');
  80                  if (is_resource($fp)) {
  81                      /** @var array<string, int> $st */
  82                      $st = fstat($fp);
  83                      if (($st['mode'] & 0170000) !== 020000) {
  84                          fclose($fp);
  85                          $fp = false;
  86                      }
  87                  }
  88              }
  89  
  90              if (is_resource($fp)) {
  91                  /**
  92                   * stream_set_read_buffer() does not exist in HHVM
  93                   *
  94                   * If we don't set the stream's read buffer to 0, PHP will
  95                   * internally buffer 8192 bytes, which can waste entropy
  96                   *
  97                   * stream_set_read_buffer returns 0 on success
  98                   */
  99                  if (is_callable('stream_set_read_buffer')) {
 100                      stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
 101                  }
 102                  if (is_callable('stream_set_chunk_size')) {
 103                      stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);
 104                  }
 105              }
 106          }
 107  
 108          try {
 109              /** @var int $bytes */
 110              $bytes = RandomCompat_intval($bytes);
 111          } catch (TypeError $ex) {
 112              throw new TypeError(
 113                  'random_bytes(): $bytes must be an integer'
 114              );
 115          }
 116  
 117          if ($bytes < 1) {
 118              throw new Error(
 119                  'Length must be greater than 0'
 120              );
 121          }
 122  
 123          /**
 124           * This if() block only runs if we managed to open a file handle
 125           *
 126           * It does not belong in an else {} block, because the above
 127           * if (empty($fp)) line is logic that should only be run once per
 128           * page load.
 129           */
 130          if (is_resource($fp)) {
 131              /**
 132               * @var int
 133               */
 134              $remaining = $bytes;
 135  
 136              /**
 137               * @var string|bool
 138               */
 139              $buf = '';
 140  
 141              /**
 142               * We use fread() in a loop to protect against partial reads
 143               */
 144              do {
 145                  /**
 146                   * @var string|bool
 147                   */
 148                  $read = fread($fp, $remaining);
 149                  if (!is_string($read)) {
 150                      /**
 151                       * We cannot safely read from the file. Exit the
 152                       * do-while loop and trigger the exception condition
 153                       *
 154                       * @var string|bool
 155                       */
 156                      $buf = false;
 157                      break;
 158                  }
 159                  /**
 160                   * Decrease the number of bytes returned from remaining
 161                   */
 162                  $remaining -= RandomCompat_strlen($read);
 163                  /**
 164                   * @var string $buf
 165                   */
 166                  $buf .= $read;
 167              } while ($remaining > 0);
 168  
 169              /**
 170               * Is our result valid?
 171               * @var string|bool $buf
 172               */
 173              if (is_string($buf)) {
 174                  if (RandomCompat_strlen($buf) === $bytes) {
 175                      /**
 176                       * Return our random entropy buffer here:
 177                       */
 178                      return $buf;
 179                  }
 180              }
 181          }
 182  
 183          /**
 184           * If we reach here, PHP has failed us.
 185           */
 186          throw new Exception(
 187              'Error reading from source device'
 188          );
 189      }
 190  }


Generated: Sun Jul 9 01:00:02 2023 Cross-referenced by PHPXref 0.7.1