|
12 | 12 | +----------------------------------------------------------------------+
|
13 | 13 | | Authors: Sammy Kaye Powers <[email protected]> |
|
14 | 14 |
|
| 15 | + | Tim Düsterhus <[email protected]> | |
15 | 16 | +----------------------------------------------------------------------+
|
16 | 17 | */
|
17 | 18 |
|
|
31 | 32 |
|
32 | 33 | #include "php_random.h"
|
33 | 34 | #include "php_random_csprng.h"
|
| 35 | +#include "ext/standard/sha1.h" |
34 | 36 |
|
35 | 37 | #if HAVE_UNISTD_H
|
36 | 38 | # include <unistd.h>
|
@@ -612,10 +614,101 @@ PHP_FUNCTION(random_int)
|
612 | 614 | }
|
613 | 615 | /* }}} */
|
614 | 616 |
|
| 617 | +static void write_32(PHP_SHA1_CTX *c, uint32_t u) |
| 618 | +{ |
| 619 | + unsigned char buf[4]; |
| 620 | + unsigned char *p = buf; |
| 621 | + *(p++) = (u >> 0) & 0xff; |
| 622 | + *(p++) = (u >> 8) & 0xff; |
| 623 | + *(p++) = (u >> 16) & 0xff; |
| 624 | + *(p++) = (u >> 24) & 0xff; |
| 625 | + PHP_SHA1Update(c, buf, sizeof(buf)); |
| 626 | +} |
| 627 | + |
| 628 | +static void write_64(PHP_SHA1_CTX *c, uint64_t u) |
| 629 | +{ |
| 630 | + write_32(c, u); |
| 631 | + write_32(c, u >> 32); |
| 632 | +} |
| 633 | + |
| 634 | +static void write_p(PHP_SHA1_CTX *c, uintptr_t p) |
| 635 | +{ |
| 636 | + if (sizeof(p) == 4) { |
| 637 | + write_32(c, p); |
| 638 | + } else { |
| 639 | + write_64(c, p); |
| 640 | + } |
| 641 | +} |
| 642 | + |
| 643 | +uint64_t php_random_generate_fallback_seed(void) |
| 644 | +{ |
| 645 | + /* Mix various values using SHA-1 as a PRF to obtain as |
| 646 | + * much entropy as possible, hopefully generating an |
| 647 | + * unpredictable and independent uint64_t. Nevertheless |
| 648 | + * the output of this function MUST NOT be treated as |
| 649 | + * being cryptographically safe. |
| 650 | + */ |
| 651 | + PHP_SHA1_CTX c; |
| 652 | + struct timeval tv; |
| 653 | + char buf[64 + 1]; |
| 654 | + |
| 655 | + PHP_SHA1Init(&c); |
| 656 | + if (!RANDOM_G(fallback_seed_initialized)) { |
| 657 | + /* Current time. */ |
| 658 | + gettimeofday(&tv, NULL); |
| 659 | + write_32(&c, tv.tv_sec); |
| 660 | + write_32(&c, tv.tv_usec); |
| 661 | + /* Various PIDs. */ |
| 662 | + write_32(&c, getpid()); |
| 663 | +#ifndef WIN32 |
| 664 | + write_32(&c, getppid()); |
| 665 | +#endif |
| 666 | +#ifdef ZTS |
| 667 | + write_32(&c, tsrm_thread_id()); |
| 668 | +#endif |
| 669 | + /* Pointer values to benefit from ASLR. */ |
| 670 | + write_p(&c, (uintptr_t)&RANDOM_G(fallback_seed_initialized)); |
| 671 | + write_p(&c, (uintptr_t)&c); |
| 672 | + /* Updated time. */ |
| 673 | + gettimeofday(&tv, NULL); |
| 674 | + write_32(&c, tv.tv_usec); |
| 675 | + /* Hostname. */ |
| 676 | + memset(buf, 0, sizeof(buf)); |
| 677 | + if (gethostname(buf, sizeof(buf) - 1) == 0) { |
| 678 | + PHP_SHA1Update(&c, (unsigned char*)buf, strlen(buf)); |
| 679 | + } |
| 680 | + /* CSPRNG. */ |
| 681 | + if (php_random_bytes_silent(buf, 16) == SUCCESS) { |
| 682 | + PHP_SHA1Update(&c, (unsigned char*)buf, 16); |
| 683 | + } |
| 684 | + /* Updated time. */ |
| 685 | + gettimeofday(&tv, NULL); |
| 686 | + write_32(&c, tv.tv_usec); |
| 687 | + } else { |
| 688 | + /* Current time. */ |
| 689 | + gettimeofday(&tv, NULL); |
| 690 | + write_32(&c, tv.tv_sec); |
| 691 | + write_32(&c, tv.tv_usec); |
| 692 | + /* Previous state. */ |
| 693 | + PHP_SHA1Update(&c, RANDOM_G(fallback_seed), 20); |
| 694 | + } |
| 695 | + PHP_SHA1Final(RANDOM_G(fallback_seed), &c); |
| 696 | + RANDOM_G(fallback_seed_initialized) = true; |
| 697 | + |
| 698 | + uint64_t result = 0; |
| 699 | + |
| 700 | + for (int i = 0; i < sizeof(result); i++) { |
| 701 | + result = result | (((uint64_t)RANDOM_G(fallback_seed)[i]) << (i * 8)); |
| 702 | + } |
| 703 | + |
| 704 | + return result; |
| 705 | +} |
| 706 | + |
615 | 707 | /* {{{ PHP_GINIT_FUNCTION */
|
616 | 708 | static PHP_GINIT_FUNCTION(random)
|
617 | 709 | {
|
618 | 710 | random_globals->random_fd = -1;
|
| 711 | + random_globals->fallback_seed_initialized = false; |
619 | 712 | }
|
620 | 713 | /* }}} */
|
621 | 714 |
|
|
0 commit comments