MicroTime.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. /*
  3. * The RandomLib library for securely generating random numbers and strings in PHP
  4. *
  5. * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
  6. * @copyright 2011 The Authors
  7. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  8. * @version Build @@version@@
  9. */
  10. /**
  11. * The Microtime Random Number Source
  12. *
  13. * This uses the current micro-second (looped several times) for a **very** weak
  14. * random number source. This is only useful when combined with several other
  15. * stronger sources
  16. *
  17. * PHP version 5.3
  18. *
  19. * @category PHPCryptLib
  20. * @package Random
  21. * @subpackage Source
  22. *
  23. * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
  24. * @author Paragon Initiative Enterprises <security@paragonie.com>
  25. * @copyright 2011 The Authors
  26. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  27. *
  28. * @version Build @@version@@
  29. */
  30. namespace RandomLib\Source;
  31. use SecurityLib\Util;
  32. /**
  33. * The Microtime Random Number Source
  34. *
  35. * This uses the current micro-second (looped several times) for a **very** weak
  36. * random number source. This is only useful when combined with several other
  37. * stronger sources
  38. *
  39. * @category PHPCryptLib
  40. * @package Random
  41. * @subpackage Source
  42. *
  43. * @author Anthony Ferrara <ircmaxell@ircmaxell.com>
  44. * @author Paragon Initiative Enterprises <security@paragonie.com>
  45. * @codeCoverageIgnore
  46. */
  47. final class MicroTime extends \RandomLib\AbstractSource
  48. {
  49. /**
  50. * A static counter to ensure unique hashes and prevent state collisions
  51. *
  52. * @var int A counter
  53. */
  54. private static $counter = null;
  55. /**
  56. * The current state of the random number generator.
  57. *
  58. * @var string The state of the PRNG
  59. */
  60. private static $state = '';
  61. public function __construct()
  62. {
  63. $state = self::$state;
  64. if (function_exists('posix_times')) {
  65. $state .= serialize(posix_times());
  66. }
  67. if (!defined('HHVM_VERSION') && function_exists('zend_thread_id')) {
  68. $state .= zend_thread_id();
  69. }
  70. if (function_exists('hphp_get_thread_id')) {
  71. $state .= hphp_get_thread_id();
  72. }
  73. $state .= getmypid() . memory_get_usage();
  74. $state .= serialize($_ENV);
  75. $state .= serialize($_SERVER);
  76. $state .= count(debug_backtrace(false));
  77. self::$state = hash('sha512', $state, true);
  78. if (is_null(self::$counter)) {
  79. list(, self::$counter) = unpack("i", Util::safeSubstr(self::$state, 0, 4));
  80. $seed = $this->generate(Util::safeStrlen(dechex(PHP_INT_MAX)));
  81. list(, self::$counter) = unpack("i", $seed);
  82. }
  83. }
  84. /**
  85. * Generate a random string of the specified size
  86. *
  87. * @param int $size The size of the requested random string
  88. *
  89. * @return string A string of the requested size
  90. */
  91. public function generate($size)
  92. {
  93. $result = '';
  94. /** @var string $seed */
  95. $seed = (string) \microtime() . \memory_get_usage();
  96. self::$state = hash('sha512', self::$state . $seed, true);
  97. /**
  98. * Make the generated randomness a bit better by forcing a GC run which
  99. * should complete in a indeterminate amount of time, hence improving
  100. * the strength of the randomness a bit. It's still not crypto-safe,
  101. * but at least it's more difficult to predict.
  102. */
  103. gc_collect_cycles();
  104. for ($i = 0; $i < $size; $i += 8) {
  105. $seed = self::$state .
  106. (string) \microtime() .
  107. (string) \pack('Ni', $i, self::counter());
  108. self::$state = \hash('sha512', $seed, true);
  109. /**
  110. * We only use the first 8 bytes here to prevent exposing the state
  111. * in its entirety, which could potentially expose other random
  112. * generations in the future (in the same process)...
  113. */
  114. $result .= Util::safeSubstr(self::$state, 0, 8);
  115. }
  116. return Util::safeSubstr($result, 0, $size);
  117. }
  118. /**
  119. * @return int
  120. */
  121. private static function counter()
  122. {
  123. if (self::$counter >= PHP_INT_MAX) {
  124. self::$counter = -1 * PHP_INT_MAX - 1;
  125. } else {
  126. self::$counter++;
  127. }
  128. return self::$counter;
  129. }
  130. }