Version 1
[yaffs-website] / vendor / paragonie / random_compat / lib / random.php
1 <?php
2 /**
3  * Random_* Compatibility Library
4  * for using the new PHP 7 random_* API in PHP 5 projects
5  *
6  * @version 2.0.10
7  * @released 2017-03-13
8  *
9  * The MIT License (MIT)
10  *
11  * Copyright (c) 2015 - 2017 Paragon Initiative Enterprises
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is
18  * furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29  * SOFTWARE.
30  */
31
32 if (!defined('PHP_VERSION_ID')) {
33     // This constant was introduced in PHP 5.2.7
34     $RandomCompatversion = array_map('intval', explode('.', PHP_VERSION));
35     define(
36         'PHP_VERSION_ID',
37         $RandomCompatversion[0] * 10000
38         + $RandomCompatversion[1] * 100
39         + $RandomCompatversion[2]
40     );
41     $RandomCompatversion = null;
42 }
43
44 /**
45  * PHP 7.0.0 and newer have these functions natively.
46  */
47 if (PHP_VERSION_ID >= 70000) {
48     return;
49 }
50
51 if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
52     define('RANDOM_COMPAT_READ_BUFFER', 8);
53 }
54
55 $RandomCompatDIR = dirname(__FILE__);
56
57 require_once $RandomCompatDIR . '/byte_safe_strings.php';
58 require_once $RandomCompatDIR . '/cast_to_int.php';
59 require_once $RandomCompatDIR . '/error_polyfill.php';
60
61 if (!is_callable('random_bytes')) {
62     /**
63      * PHP 5.2.0 - 5.6.x way to implement random_bytes()
64      *
65      * We use conditional statements here to define the function in accordance
66      * to the operating environment. It's a micro-optimization.
67      *
68      * In order of preference:
69      *   1. Use libsodium if available.
70      *   2. fread() /dev/urandom if available (never on Windows)
71      *   3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM)
72      *   4. COM('CAPICOM.Utilities.1')->GetRandom()
73      *
74      * See RATIONALE.md for our reasoning behind this particular order
75      */
76     if (extension_loaded('libsodium')) {
77         // See random_bytes_libsodium.php
78         if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) {
79             require_once $RandomCompatDIR . '/random_bytes_libsodium.php';
80         } elseif (method_exists('Sodium', 'randombytes_buf')) {
81             require_once $RandomCompatDIR . '/random_bytes_libsodium_legacy.php';
82         }
83     }
84
85     /**
86      * Reading directly from /dev/urandom:
87      */
88     if (DIRECTORY_SEPARATOR === '/') {
89         // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast
90         // way to exclude Windows.
91         $RandomCompatUrandom = true;
92         $RandomCompat_basedir = ini_get('open_basedir');
93
94         if (!empty($RandomCompat_basedir)) {
95             $RandomCompat_open_basedir = explode(
96                 PATH_SEPARATOR,
97                 strtolower($RandomCompat_basedir)
98             );
99             $RandomCompatUrandom = (array() !== array_intersect(
100                 array('/dev', '/dev/', '/dev/urandom'),
101                 $RandomCompat_open_basedir
102             ));
103             $RandomCompat_open_basedir = null;
104         }
105
106         if (
107             !is_callable('random_bytes')
108             &&
109             $RandomCompatUrandom
110             &&
111             @is_readable('/dev/urandom')
112         ) {
113             // Error suppression on is_readable() in case of an open_basedir
114             // or safe_mode failure. All we care about is whether or not we
115             // can read it at this point. If the PHP environment is going to
116             // panic over trying to see if the file can be read in the first
117             // place, that is not helpful to us here.
118
119             // See random_bytes_dev_urandom.php
120             require_once $RandomCompatDIR . '/random_bytes_dev_urandom.php';
121         }
122         // Unset variables after use
123         $RandomCompat_basedir = null;
124     } else {
125         $RandomCompatUrandom = false;
126     }
127
128     /**
129      * mcrypt_create_iv()
130      *
131      * We only want to use mcypt_create_iv() if:
132      *
133      * - random_bytes() hasn't already been defined
134      * - the mcrypt extensions is loaded
135      * - One of these two conditions is true:
136      *   - We're on Windows (DIRECTORY_SEPARATOR !== '/')
137      *   - We're not on Windows and /dev/urandom is readabale
138      *     (i.e. we're not in a chroot jail)
139      * - Special case:
140      *   - If we're not on Windows, but the PHP version is between
141      *     5.6.10 and 5.6.12, we don't want to use mcrypt. It will
142      *     hang indefinitely. This is bad.
143      *   - If we're on Windows, we want to use PHP >= 5.3.7 or else
144      *     we get insufficient entropy errors.
145      */
146     if (
147         !is_callable('random_bytes')
148         &&
149         // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be.
150         (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307)
151         &&
152         // Prevent this code from hanging indefinitely on non-Windows;
153         // see https://bugs.php.net/bug.php?id=69833
154         (
155             DIRECTORY_SEPARATOR !== '/' ||
156             (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613)
157         )
158         &&
159         extension_loaded('mcrypt')
160     ) {
161         // See random_bytes_mcrypt.php
162         require_once $RandomCompatDIR . '/random_bytes_mcrypt.php';
163     }
164     $RandomCompatUrandom = null;
165
166     /**
167      * This is a Windows-specific fallback, for when the mcrypt extension
168      * isn't loaded.
169      */
170     if (
171         !is_callable('random_bytes')
172         &&
173         extension_loaded('com_dotnet')
174         &&
175         class_exists('COM')
176     ) {
177         $RandomCompat_disabled_classes = preg_split(
178             '#\s*,\s*#',
179             strtolower(ini_get('disable_classes'))
180         );
181
182         if (!in_array('com', $RandomCompat_disabled_classes)) {
183             try {
184                 $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1');
185                 if (method_exists($RandomCompatCOMtest, 'GetRandom')) {
186                     // See random_bytes_com_dotnet.php
187                     require_once $RandomCompatDIR . '/random_bytes_com_dotnet.php';
188                 }
189             } catch (com_exception $e) {
190                 // Don't try to use it.
191             }
192         }
193         $RandomCompat_disabled_classes = null;
194         $RandomCompatCOMtest = null;
195     }
196
197     /**
198      * throw new Exception
199      */
200     if (!is_callable('random_bytes')) {
201         /**
202          * We don't have any more options, so let's throw an exception right now
203          * and hope the developer won't let it fail silently.
204          *
205          * @param mixed $length
206          * @return void
207          * @throws Exception
208          */
209         function random_bytes($length)
210         {
211             unset($length); // Suppress "variable not used" warnings.
212             throw new Exception(
213                 'There is no suitable CSPRNG installed on your system'
214             );
215         }
216     }
217 }
218
219 if (!is_callable('random_int')) {
220     require_once $RandomCompatDIR . '/random_int.php';
221 }
222
223 $RandomCompatDIR = null;