|
11 | 11 |
|
12 | 12 | namespace Symfony\Component\Security\Core\Util;
|
13 | 13 |
|
14 |
| -use Psr\Log\LoggerInterface; |
15 |
| - |
16 | 14 | /**
|
17 | 15 | * A secure random number generator implementation.
|
18 | 16 | *
|
|
21 | 19 | */
|
22 | 20 | final class SecureRandom implements SecureRandomInterface
|
23 | 21 | {
|
24 |
| - private $logger; |
25 |
| - private $useOpenSsl; |
26 |
| - private $seed; |
27 |
| - private $seedUpdated; |
28 |
| - private $seedLastUpdatedAt; |
29 |
| - private $seedFile; |
30 |
| - |
31 |
| - /** |
32 |
| - * Constructor. |
33 |
| - * |
34 |
| - * Be aware that a guessable seed will severely compromise the PRNG |
35 |
| - * algorithm that is employed. |
36 |
| - * |
37 |
| - * @param string $seedFile |
38 |
| - * @param LoggerInterface $logger |
39 |
| - */ |
40 |
| - public function __construct($seedFile = null, LoggerInterface $logger = null) |
41 |
| - { |
42 |
| - $this->seedFile = $seedFile; |
43 |
| - $this->logger = $logger; |
44 |
| - |
45 |
| - $isUnsupportedPhp = '\\' === DIRECTORY_SEPARATOR && PHP_VERSION_ID < 50304; |
46 |
| - |
47 |
| - // determine whether to use OpenSSL |
48 |
| - if (!function_exists('random_bytes') && ($isUnsupportedPhp || !function_exists('openssl_random_pseudo_bytes'))) { |
49 |
| - if (null !== $this->logger) { |
50 |
| - $this->logger->notice('It is recommended that you install the "paragonie/random_compat" library or enable the "openssl" extension for random number generation.'); |
51 |
| - } |
52 |
| - $this->useOpenSsl = false; |
53 |
| - } else { |
54 |
| - $this->useOpenSsl = true; |
55 |
| - } |
56 |
| - } |
57 |
| - |
58 | 22 | /**
|
59 | 23 | * {@inheritdoc}
|
60 | 24 | */
|
61 | 25 | public function nextBytes($nbBytes)
|
62 | 26 | {
|
63 |
| - if (function_exists('random_bytes')) { |
64 |
| - return random_bytes($nbBytes); |
65 |
| - } |
66 |
| - |
67 |
| - // try OpenSSL |
68 |
| - if ($this->useOpenSsl) { |
69 |
| - $bytes = openssl_random_pseudo_bytes($nbBytes, $strong); |
70 |
| - |
71 |
| - if (false !== $bytes && true === $strong) { |
72 |
| - return $bytes; |
73 |
| - } |
74 |
| - |
75 |
| - if (null !== $this->logger) { |
76 |
| - $this->logger->info('OpenSSL did not produce a secure random number.'); |
77 |
| - } |
78 |
| - } |
79 |
| - |
80 |
| - // initialize seed |
81 |
| - if (null === $this->seed) { |
82 |
| - if (null === $this->seedFile) { |
83 |
| - throw new \RuntimeException('You need to specify a file path to store the seed.'); |
84 |
| - } |
85 |
| - |
86 |
| - if (is_file($this->seedFile)) { |
87 |
| - list($this->seed, $this->seedLastUpdatedAt) = $this->readSeed(); |
88 |
| - } else { |
89 |
| - $this->seed = uniqid(mt_rand(), true); |
90 |
| - $this->updateSeed(); |
91 |
| - } |
92 |
| - } |
93 |
| - |
94 |
| - $bytes = ''; |
95 |
| - while (strlen($bytes) < $nbBytes) { |
96 |
| - static $incr = 1; |
97 |
| - $bytes .= hash('sha512', $incr++.$this->seed.uniqid(mt_rand(), true).$nbBytes, true); |
98 |
| - $this->seed = base64_encode(hash('sha512', $this->seed.$bytes.$nbBytes, true)); |
99 |
| - $this->updateSeed(); |
100 |
| - } |
101 |
| - |
102 |
| - return substr($bytes, 0, $nbBytes); |
103 |
| - } |
104 |
| - |
105 |
| - private function readSeed() |
106 |
| - { |
107 |
| - return json_decode(file_get_contents($this->seedFile)); |
108 |
| - } |
109 |
| - |
110 |
| - private function updateSeed() |
111 |
| - { |
112 |
| - if (!$this->seedUpdated && $this->seedLastUpdatedAt < time() - mt_rand(1, 10)) { |
113 |
| - file_put_contents($this->seedFile, json_encode(array($this->seed, microtime(true)))); |
114 |
| - } |
115 |
| - |
116 |
| - $this->seedUpdated = true; |
| 27 | + return random_bytes($nbBytes); |
117 | 28 | }
|
118 | 29 | }
|
0 commit comments