| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 | 
							- <?php
 - 
 - namespace JMS\SecurityExtraBundle\Security\Util;
 - 
 - use Doctrine\DBAL\Types\Type;
 - use Doctrine\DBAL\Connection;
 - use Symfony\Component\HttpKernel\Log\LoggerInterface;
 - 
 - /**
 -  * A secure random number generator implementation.
 -  *
 -  * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 -  */
 - final class SecureRandom
 - {
 -     private $logger;
 -     private $useOpenSsl;
 -     private $con;
 -     private $seed;
 -     private $seedTableName;
 -     private $seedUpdated;
 -     private $seedLastUpdatedAt;
 -     private $seedProvider;
 - 
 -     public function __construct(LoggerInterface $logger)
 -     {
 -         $this->logger = $logger;
 - 
 -         // determine whether to use OpenSSL
 -         if (0 === stripos(PHP_OS, 'win')) {
 -             $this->useOpenSsl = false;
 -         } elseif (!function_exists('openssl_random_pseudo_bytes')) {
 -             $this->logger->notice('It is recommended that you enable the "openssl" extension for random number generation.');
 -             $this->useOpenSsl = false;
 -         } else {
 -             $this->useOpenSsl = true;
 -         }
 -     }
 - 
 -     /**
 -      * Sets the Doctrine seed provider.
 -      *
 -      * @param Connection $con
 -      * @param string     $tableName
 -      */
 -     public function setConnection(Connection $con, $tableName)
 -     {
 -         $this->con = $con;
 -         $this->seedTableName = $tableName;
 -     }
 - 
 -     /**
 -      * Sets a custom seed provider implementation.
 -      *
 -      * Be aware that a guessable seed will severely compromise the PRNG
 -      * algorithm that is employed.
 -      *
 -      * @param SeedProviderInterface $provider
 -      */
 -     public function setSeedProvider(SeedProviderInterface $provider)
 -     {
 -         $this->seedProvider = $provider;
 -     }
 - 
 -     /**
 -      * Generates the specified number of secure random bytes.
 -      *
 -      * @param  integer $nbBytes
 -      * @return string
 -      */
 -     public function nextBytes($nbBytes)
 -     {
 -         // try OpenSSL
 -         if ($this->useOpenSsl) {
 -             $strong = false;
 -             $bytes = openssl_random_pseudo_bytes($nbBytes, $strong);
 - 
 -             if (false !== $bytes && true === $strong) {
 -                 return $bytes;
 -             }
 - 
 -             $this->logger->info('OpenSSL did not produce a secure random number.');
 -         }
 - 
 -         // initialize seed
 -         if (null === $this->seed) {
 -             if (null !== $this->seedProvider) {
 -                 list($this->seed, $this->seedLastUpdatedAt) = $this->seedProvider->loadSeed();
 -             } elseif (null !== $this->con) {
 -                 $this->initializeSeedFromDatabase();
 -             } else {
 -                 throw new \RuntimeException('You need to either specify a database connection, or a custom seed provider.');
 -             }
 -         }
 - 
 -         $bytes = '';
 -         while (strlen($bytes) < $nbBytes) {
 -             static $incr = 1;
 -             $bytes .= hash('sha512', $incr++.$this->seed.uniqid(mt_rand(), true).$nbBytes, true);
 -             $this->seed = base64_encode(hash('sha512', $this->seed.$bytes.$nbBytes, true));
 - 
 -             if (!$this->seedUpdated && $this->seedLastUpdatedAt->getTimestamp() < time() - mt_rand(1, 10)) {
 -                 if (null !== $this->seedProvider) {
 -                     $this->seedProvider->updateSeed($this->seed);
 -                 } elseif (null !== $this->con) {
 -                     $this->saveSeedToDatabase();
 -                 }
 - 
 -                 $this->seedUpdated = true;
 -             }
 -         }
 - 
 -         return substr($bytes, 0, $nbBytes);
 -     }
 - 
 -     private function saveSeedToDatabase()
 -     {
 -         $this->con->executeQuery("UPDATE {$this->seedTableName} SET seed = :seed, updated_at = :updatedAt", array(
 -             ':seed' => $this->seed,
 -             ':updatedAt' => new \DateTime(),
 -         ), array(
 -             ':updatedAt' => Type::DATETIME,
 -         ));
 -     }
 - 
 -     private function initializeSeedFromDatabase()
 -     {
 -         $stmt = $this->con->executeQuery("SELECT seed, updated_at FROM {$this->seedTableName}");
 - 
 -         if (false === $this->seed = $stmt->fetchColumn(0)) {
 -             throw new \RuntimeException('You need to initialize the generator by running the console command "init:jms-secure-random".');
 -         }
 - 
 -         $this->seedLastUpdatedAt = new \DateTime($stmt->fetchColumn(1));
 -     }
 - }
 
 
  |