mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
random: Improve the output quality of RANDOM_SEED() (#13730)
* random: Improve the output quality of RANDOM_SEED()
Previously 4 consecutive calls to `RANDOM_SEED()` each for 4 different CLI
requests resulted in:
$ sapi/cli/php test.php
2c13e9fde9caa
2c13e9fd1d6b0
2c13e9fd4de34
2c13e9fd1610e
$ sapi/cli/php test.php
2c1436764fe07
2c14367621770
2c143676c0bf6
2c143676e02f5
$ sapi/cli/php test.php
2c144995a0626
2c14499590fe2
2c144995c65db
2c14499536833
$ sapi/cli/php test.php
2c145cb30860b
2c145cb3ec027
2c145cb33b4ca
2c145cb38ff63
Now they result in:
$ sapi/cli/php test.php
6796973ace1b5f3d
1913daf5c158cb4b
255dbf24237bc8c9
7c3ba22e60f35196
$ sapi/cli/php test.php
afb7cc9ba9819cd2
3e01a71b91ad020c
6b718364d3ef108
bdcd17beeb4b31d2
$ sapi/cli/php test.php
53d36eb9b83f8788
4381c85e816187aa
2e9b32ee9898e71e
31d15c946842bddb
$ sapi/cli/php test.php
2037a3cba88114b4
ba0b0d93a9bb43aa
e13d82d2421269e2
191de474f3292240
* tree-wide: Replace GENERATE_SEED() by php_random_generate_fallback_seed()
* random: Fix NTS build
* random: Fix Windows build
This commit is contained in:
@@ -174,6 +174,11 @@ PHP 8.4 INTERNALS UPGRADE NOTES
|
||||
- The CSPRNG API (php_random_(bytes|int)_*) is now provided by the new
|
||||
and much smaller php_random_csprng.h header. The new header is included
|
||||
in php_random.h for compatibility with existing users.
|
||||
- A new php_random_generate_fallback_seed() function has been added as a
|
||||
replacement for the generically named GENERATE_SEED(). The internal
|
||||
implementation has been improved to generate better seeds, however any
|
||||
users should use the opportunity to verify that seeding is first
|
||||
attempted using the CSPRNG for better output size flexibility.
|
||||
|
||||
c. ext/xsl
|
||||
- The function php_xsl_create_object() was removed as it was not used
|
||||
|
||||
@@ -1734,9 +1734,9 @@ static void gmp_init_random(void)
|
||||
/* Initialize */
|
||||
gmp_randinit_mt(GMPG(rand_state));
|
||||
/* Seed */
|
||||
zend_long seed = 0;
|
||||
if (php_random_bytes_silent(&seed, sizeof(zend_long)) == FAILURE) {
|
||||
seed = GENERATE_SEED();
|
||||
unsigned long int seed = 0;
|
||||
if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) {
|
||||
seed = (unsigned long int)php_random_generate_fallback_seed();
|
||||
}
|
||||
gmp_randseed_ui(GMPG(rand_state), seed);
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@ PHPAPI void php_random_mt19937_seed_default(php_random_status_state_mt19937 *sta
|
||||
uint32_t seed = 0;
|
||||
|
||||
if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) {
|
||||
seed = GENERATE_SEED();
|
||||
seed = (uint32_t)php_random_generate_fallback_seed();
|
||||
}
|
||||
|
||||
php_random_mt19937_seed32(state, seed);
|
||||
|
||||
@@ -37,17 +37,11 @@
|
||||
|
||||
PHPAPI double php_combined_lcg(void);
|
||||
|
||||
PHPAPI uint64_t php_random_generate_fallback_seed(void);
|
||||
|
||||
static inline zend_long GENERATE_SEED(void)
|
||||
{
|
||||
zend_ulong pid;
|
||||
|
||||
# ifdef PHP_WIN32
|
||||
pid = (zend_ulong) GetCurrentProcessId();
|
||||
# else
|
||||
pid = (zend_ulong) getpid();
|
||||
# endif
|
||||
|
||||
return (((zend_long) ((zend_ulong) time(NULL) * pid)) ^ ((zend_long) (1000000.0 * php_combined_lcg())));
|
||||
return (zend_long)php_random_generate_fallback_seed();
|
||||
}
|
||||
|
||||
# define PHP_MT_RAND_MAX ((zend_long) (0x7FFFFFFF)) /* (1<<31) - 1 */
|
||||
@@ -213,6 +207,8 @@ ZEND_BEGIN_MODULE_GLOBALS(random)
|
||||
int random_fd;
|
||||
bool combined_lcg_seeded;
|
||||
bool mt19937_seeded;
|
||||
bool fallback_seed_initialized;
|
||||
unsigned char fallback_seed[20];
|
||||
php_random_status_state_combinedlcg combined_lcg;
|
||||
php_random_status_state_mt19937 mt19937;
|
||||
ZEND_END_MODULE_GLOBALS(random)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Sammy Kaye Powers <me@sammyk.me> |
|
||||
| Go Kudo <zeriyoshi@php.net> |
|
||||
| Tim Düsterhus <timwolla@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
@@ -31,6 +32,7 @@
|
||||
|
||||
#include "php_random.h"
|
||||
#include "php_random_csprng.h"
|
||||
#include "ext/standard/sha1.h"
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
@@ -612,10 +614,101 @@ PHP_FUNCTION(random_int)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void write_32(PHP_SHA1_CTX *c, uint32_t u)
|
||||
{
|
||||
unsigned char buf[4];
|
||||
unsigned char *p = buf;
|
||||
*(p++) = (u >> 0) & 0xff;
|
||||
*(p++) = (u >> 8) & 0xff;
|
||||
*(p++) = (u >> 16) & 0xff;
|
||||
*(p++) = (u >> 24) & 0xff;
|
||||
PHP_SHA1Update(c, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static void write_64(PHP_SHA1_CTX *c, uint64_t u)
|
||||
{
|
||||
write_32(c, u);
|
||||
write_32(c, u >> 32);
|
||||
}
|
||||
|
||||
static void write_p(PHP_SHA1_CTX *c, uintptr_t p)
|
||||
{
|
||||
if (sizeof(p) == 4) {
|
||||
write_32(c, p);
|
||||
} else {
|
||||
write_64(c, p);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t php_random_generate_fallback_seed(void)
|
||||
{
|
||||
/* Mix various values using SHA-1 as a PRF to obtain as
|
||||
* much entropy as possible, hopefully generating an
|
||||
* unpredictable and independent uint64_t. Nevertheless
|
||||
* the output of this function MUST NOT be treated as
|
||||
* being cryptographically safe.
|
||||
*/
|
||||
PHP_SHA1_CTX c;
|
||||
struct timeval tv;
|
||||
char buf[64 + 1];
|
||||
|
||||
PHP_SHA1Init(&c);
|
||||
if (!RANDOM_G(fallback_seed_initialized)) {
|
||||
/* Current time. */
|
||||
gettimeofday(&tv, NULL);
|
||||
write_32(&c, tv.tv_sec);
|
||||
write_32(&c, tv.tv_usec);
|
||||
/* Various PIDs. */
|
||||
write_32(&c, getpid());
|
||||
#ifndef WIN32
|
||||
write_32(&c, getppid());
|
||||
#endif
|
||||
#ifdef ZTS
|
||||
write_32(&c, tsrm_thread_id());
|
||||
#endif
|
||||
/* Pointer values to benefit from ASLR. */
|
||||
write_p(&c, (uintptr_t)&RANDOM_G(fallback_seed_initialized));
|
||||
write_p(&c, (uintptr_t)&c);
|
||||
/* Updated time. */
|
||||
gettimeofday(&tv, NULL);
|
||||
write_32(&c, tv.tv_usec);
|
||||
/* Hostname. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (gethostname(buf, sizeof(buf) - 1) == 0) {
|
||||
PHP_SHA1Update(&c, (unsigned char*)buf, strlen(buf));
|
||||
}
|
||||
/* CSPRNG. */
|
||||
if (php_random_bytes_silent(buf, 16) == SUCCESS) {
|
||||
PHP_SHA1Update(&c, (unsigned char*)buf, 16);
|
||||
}
|
||||
/* Updated time. */
|
||||
gettimeofday(&tv, NULL);
|
||||
write_32(&c, tv.tv_usec);
|
||||
} else {
|
||||
/* Current time. */
|
||||
gettimeofday(&tv, NULL);
|
||||
write_32(&c, tv.tv_sec);
|
||||
write_32(&c, tv.tv_usec);
|
||||
/* Previous state. */
|
||||
PHP_SHA1Update(&c, RANDOM_G(fallback_seed), 20);
|
||||
}
|
||||
PHP_SHA1Final(RANDOM_G(fallback_seed), &c);
|
||||
RANDOM_G(fallback_seed_initialized) = true;
|
||||
|
||||
uint64_t result = 0;
|
||||
|
||||
for (int i = 0; i < sizeof(result); i++) {
|
||||
result = result | (((uint64_t)RANDOM_G(fallback_seed)[i]) << (i * 8));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* {{{ PHP_GINIT_FUNCTION */
|
||||
static PHP_GINIT_FUNCTION(random)
|
||||
{
|
||||
random_globals->random_fd = -1;
|
||||
random_globals->fallback_seed_initialized = false;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
@@ -2879,7 +2879,10 @@ static PHP_GINIT_FUNCTION(ps) /* {{{ */
|
||||
};
|
||||
php_random_uint128_t seed;
|
||||
if (php_random_bytes_silent(&seed, sizeof(seed)) == FAILURE) {
|
||||
seed = php_random_uint128_constant(GENERATE_SEED(), GENERATE_SEED());
|
||||
seed = php_random_uint128_constant(
|
||||
php_random_generate_fallback_seed(),
|
||||
php_random_generate_fallback_seed()
|
||||
);
|
||||
}
|
||||
php_random_pcgoneseq128xslrr64_seed128(ps_globals->random.state, seed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user