PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Util/SecureRandom.php

https://gitlab.com/TouirMohamedMarwen/Symfony2
PHP | 114 lines | 69 code | 16 blank | 29 comment | 15 complexity | 50916f7b44ccd84e38c76cec2097eb1b MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Security\Core\Util;
  11. use Psr\Log\LoggerInterface;
  12. /**
  13. * A secure random number generator implementation.
  14. *
  15. * @author Fabien Potencier <fabien@symfony.com>
  16. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  17. */
  18. final class SecureRandom implements SecureRandomInterface
  19. {
  20. private $logger;
  21. private $useOpenSsl;
  22. private $seed;
  23. private $seedUpdated;
  24. private $seedLastUpdatedAt;
  25. private $seedFile;
  26. /**
  27. * Constructor.
  28. *
  29. * Be aware that a guessable seed will severely compromise the PRNG
  30. * algorithm that is employed.
  31. *
  32. * @param string $seedFile
  33. * @param LoggerInterface $logger
  34. */
  35. public function __construct($seedFile = null, LoggerInterface $logger = null)
  36. {
  37. $this->seedFile = $seedFile;
  38. $this->logger = $logger;
  39. // determine whether to use OpenSSL
  40. if (defined('PHP_WINDOWS_VERSION_BUILD') && PHP_VERSION_ID < 50304) {
  41. $this->useOpenSsl = false;
  42. } elseif (!function_exists('openssl_random_pseudo_bytes')) {
  43. if (null !== $this->logger) {
  44. $this->logger->notice('It is recommended that you enable the "openssl" extension for random number generation.');
  45. }
  46. $this->useOpenSsl = false;
  47. } else {
  48. $this->useOpenSsl = true;
  49. }
  50. }
  51. /**
  52. * {@inheritdoc}
  53. */
  54. public function nextBytes($nbBytes)
  55. {
  56. // try OpenSSL
  57. if ($this->useOpenSsl) {
  58. $bytes = openssl_random_pseudo_bytes($nbBytes, $strong);
  59. if (false !== $bytes && true === $strong) {
  60. return $bytes;
  61. }
  62. if (null !== $this->logger) {
  63. $this->logger->info('OpenSSL did not produce a secure random number.');
  64. }
  65. }
  66. // initialize seed
  67. if (null === $this->seed) {
  68. if (null === $this->seedFile) {
  69. throw new \RuntimeException('You need to specify a file path to store the seed.');
  70. }
  71. if (is_file($this->seedFile)) {
  72. list($this->seed, $this->seedLastUpdatedAt) = $this->readSeed();
  73. } else {
  74. $this->seed = uniqid(mt_rand(), true);
  75. $this->updateSeed();
  76. }
  77. }
  78. $bytes = '';
  79. while (strlen($bytes) < $nbBytes) {
  80. static $incr = 1;
  81. $bytes .= hash('sha512', $incr++.$this->seed.uniqid(mt_rand(), true).$nbBytes, true);
  82. $this->seed = base64_encode(hash('sha512', $this->seed.$bytes.$nbBytes, true));
  83. $this->updateSeed();
  84. }
  85. return substr($bytes, 0, $nbBytes);
  86. }
  87. private function readSeed()
  88. {
  89. return json_decode(file_get_contents($this->seedFile));
  90. }
  91. private function updateSeed()
  92. {
  93. if (!$this->seedUpdated && $this->seedLastUpdatedAt < time() - mt_rand(1, 10)) {
  94. file_put_contents($this->seedFile, json_encode(array($this->seed, microtime(true))));
  95. }
  96. $this->seedUpdated = true;
  97. }
  98. }