Skip to content

Use getrandom in uniqid() and mt_rand() / mt_srand(). #6520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from

Conversation

zeriyoshi
Copy link
Contributor

Proposal to Internals: https://externals.io/message/112525

For these functions, use the more secure random source provided by the operating system if available.
A slight performance degradation is expected (Especially Linux, kernel's uses spinlock.), but the impact is minor and only at first time.

Also, no changes has provided for GENERATE_SEED() in gmp. This is because I am not familiar with this extension.

@zeriyoshi zeriyoshi changed the title Use getrandom in uniqid() and mt_rand() / mt_srand(). WIP: Use getrandom in uniqid() and mt_rand() / mt_srand(). Dec 18, 2020
@zeriyoshi zeriyoshi force-pushed the use_getrandom branch 3 times, most recently from 1628995 to df4c18f Compare December 18, 2020 13:54
@zeriyoshi zeriyoshi changed the title WIP: Use getrandom in uniqid() and mt_rand() / mt_srand(). Use getrandom in uniqid() and mt_rand() / mt_srand(). Dec 18, 2020
@cmb69 cmb69 added the RFC label Dec 19, 2020
@TysonAndre
Copy link
Contributor

At a glance, I don't have any objections

  • Anything that needed deterministic random bytes would already be calling mt_srand() with a provided seed (before using random algorithms) and would be unaffected by this change
  • /dev/urandom shouldn't/doesn't block on unix (not familiar with Windows)
  • The OS's secure random number generator should be an improvement over the existing pseudo-random implementation if this PR is properly checking that enough bytes are fetched.

@cmb69 cmb69 removed the RFC label Dec 20, 2020
if (php_random_bytes_silent(&bytes, sizeof(uint32_t)) == FAILURE) {
seed = php_combined_lcg() * 10;
} else {
seed = (10.0 / ((double) UINT32_MAX / bytes));
Copy link
Member

@nikic nikic Dec 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the double division here rather odd, why not ((double) bytes / UINT32_MAX) * 10.0?

It would be good if you could check how much this impacts performance of uniqid. I'm not really concerned about the seeding for mt_rand as it happens once, but this happens on every call to uniqid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it. I'm so ashamed.

Trying to benchmarking uniqid(), There was no noticeable performance degradation, even in the most unlikely use cases. (In Debian Buster on Docker for Mac)

# original
$ time ./sapi/cli/php -r 'foreach (range(1, 100000) as $i) { uniqid(); }'

real    0m0.674s
user    0m0.071s
sys     0m0.595s

# use php_random_bytes()
$ time ./sapi/cli/php -r 'foreach (range(1, 100000) as $i) { uniqid(); }'

real    0m0.656s
user    0m0.073s
sys     0m0.572s

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The case you are testing does not have more_entropy set, so it does not actually test this code path. However, from my own test the new code is just 35% slower (Ubuntu), so I think this change is not problematic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants