Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/Util/Random.php
<?php

namespace XF\Util;

use function
in_array, intval, is_string, strlen;

class
Random
{
    protected static
$sources = null;
    protected static
$lastUsed = null;

    public static function
getRandomBytes($length)
    {
        if (
self::$sources === null)
        {
           
self::$sources = self::getAvailableSources();
        }

       
$length = intval($length);
        if (
$length < 1)
        {
            throw new \
LogicException("Must fetch 1 or more random bytes");
        }

       
$output = '';
       
$remaining = $length;
       
$lastUsed = null;

        foreach (
self::$sources AS $type => $fn)
        {
           
$result = self::$fn($remaining);
            if (
is_string($result) && $added = strlen($result))
            {
               
$lastUsed = $type;

               
$output .= $result;
               
$remaining -= $added;
                if (
$remaining <= 0)
                {
                    break;
                }
            }
        }

        if (
strlen($output) < $length)
        {
            throw new \
ErrorException("Could not generate random bytes of significant length");
        }

       
self::$lastUsed = $lastUsed;

        return
substr($output, 0, $length);
    }

    public static function
getRandomString($length)
    {
       
$random = self::getRandomBytes($length);
       
$string = strtr(base64_encode($random), [
           
'=' => '',
           
"\r" => '',
           
"\n" => '',
           
'+' => '-',
           
'/' => '_'
       
]);

        return
substr($string, 0, $length);
    }

   
/**
     * Returns the name of the last used source of random data.
     *
     * @return string
     */
   
public static function getLastUsedSource()
    {
        if (
self::$lastUsed === null)
        {
           
self::getRandomBytes(1);
        }

        return
self::$lastUsed;
    }

    protected static function
_genRandomBytes($length)
    {
        return
random_bytes($length);
    }

    protected static
$urandomFp;

    protected static function
_genUrandom($length)
    {
        if (!
self::$urandomFp)
        {
           
$fp = @fopen('/dev/urandom', 'rb');
            if (!
$fp)
            {
                return
false;
            }

           
stream_set_read_buffer($fp, 8);
           
stream_set_chunk_size($fp, 8);

           
self::$urandomFp = $fp;
        }

        return
fread(self::$urandomFp, $length);
    }

    protected static function
_genMcrypt($length)
    {
        return
mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
    }

    protected static function
_genOpenSsl($length)
    {
       
$random = openssl_random_pseudo_bytes($length);
       
// mixing for fork safety https://wiki.openssl.org/index.php/Random_fork-safety
       
return self::mixWithInternal($random);
    }

    protected static function
_genInternal($length)
    {
       
$data = '';
        do
        {
           
$data .= self::getInternalRandomData();
        }
        while (
strlen($data) < $length);

        return
substr($data, 0, $length);
    }

    protected static function
mixWithInternal($random)
    {
       
$length = strlen($random);
       
$internal = self::_genInternal($length);
       
$blockSize = 20; // length of the hash, change if hash changed

       
$randomParts = str_split($random, $blockSize);
       
$internalParts = str_split($internal, $blockSize);

       
$output = '';
        foreach (
$randomParts AS $i => $randomPart)
        {
           
$internalPart = $internalParts[$i];
            if (
$i % 2 == 0)
            {
               
$output .= hash_hmac('sha1', $internalPart, $randomPart, true);
            }
            else
            {
               
$output .= hash_hmac('sha1', $randomPart, $internalPart, true);
            }
        }

        return
substr($output, 0, $length);
    }

    protected static
$internalRandomState;

    protected static function
getInternalRandomData()
    {
        if (!
self::$internalRandomState)
        {
           
self::$internalRandomState = sha1(
                (
                   
memory_get_usage()
                    .
getmypid()
                    .
serialize($_ENV)
                    .
serialize($_SERVER)
                    .
mt_rand()
                    .
microtime()
                    .
spl_object_hash(new \stdClass)
                ),
               
true
           
);
        }

       
gc_collect_cycles();
       
$parts = mt_rand()
            .
memory_get_usage()
            .
microtime()
            .
self::$internalRandomState;
       
self::$internalRandomState = sha1($parts, true);

        return
substr(self::$internalRandomState, 0, 10);
    }

    public static function
getAvailableSources()
    {
       
$available = [
           
'random_byes' => '_genRandomBytes'
       
];

        if (
function_exists('mcrypt_create_iv'))
        {
           
$available['mcrypt'] = '_genMcrypt';
        }

        if (\
XF::$DS === '/')
        {
           
$baseDir = @ini_get('open_basedir');
            if (
$baseDir)
            {
               
$uRandomAllowed = false;
               
$dirs = explode(':', $baseDir);
                foreach ([
'/dev', '/dev/', '/dev/urandom'] AS $c)
                {
                    if (
in_array($c, $dirs))
                    {
                       
$uRandomAllowed = true;
                        break;
                    }
                }
            }
            else
            {
               
$uRandomAllowed = true;
            }

            if (
$uRandomAllowed && @is_readable('/dev/urandom'))
            {
               
$available['urandom'] = '_genUrandom';
            }
        }

        if (
function_exists('openssl_random_pseudo_bytes'))
        {
           
$available['openssl'] = '_genOpenSsl';
        }

       
$available['internal'] = '_genInternal';

        return
$available;
    }

    public static function
removeSource($source)
    {
        if (
self::$sources === null)
        {
           
self::$sources = self::getAvailableSources();
        }

        unset(
self::$sources[$source]);
    }
}