This is an old revision of the document!
PHP RFC: RNG fixes and changes
- Version: 1.0
- Date: 2016-05-03
- Author: Leigh T leigh@php.net
- Status: Under Discussion
- First Published at: https://wiki.php.net/rfc/rng_fixes
Introduction
There are several long standing issues with random number generation that should be addressed:
- Incorrect implementations
- Platform-specific outputs
- Poor scaling of bounded outputs
- Insecure usage
Some of these fixes alter the output of the RNG or change the behaviour of functions that depend on them, so it makes sense to perform all of the changes at the same time.
Proposal
There are several proposals up for discussion that I hope to fine-tune, improve upon or eliminate completely during the discussion phase. The proposals are:
- Replace mt_rand() and rand() to a strong, modern RNG.
- Alternatively, fix the current mt_rand() implementation.
- Alias rand() to mt_rand().
- Fix RAND_RANGE for large ranges.
- Replace insecure uses of php_rand() with php_random_bytes()
- Make array_rand() more efficient
Replace mt_rand() and rand() to a strong, modern RNG.
Most of the identified issues can be addressed by replacing the implementations of mt_rand()
and rand()
with a more modern random number generator such as (Xoroshiro128+) or (PCG)
As we currently recommend using mt_rand()
over rand()
it doesn't make sense to only replace the implementation of rand()
with a stronger RNG.
This change would alter the output streams of both functions, however it fixes:
- Platform-specific outputs
- Poor scaling of bounded outputs
Fix mt_rand() implementation
The implementation of mt_rand()
in PHP contains a typo that makes it generate a different sequence of numbers to the original mt19937 implementation. See bug #71152
It is not known if the period or the quality of the output from the RNG is negatively affected due to this typo.
As mt_rand()
can be seeded for repeatable sequences the current implementation makes it incompatible with other systems that do use correct implementations. However fixing it also means that the sequence generated for a given seed in PHP will also now be different.
Alias rand() to mt_rand()
rand()
uses the system random number generator. The output of this RNG is system dependant and on many systems produces weak random numbers. (See bug #45301)
Aliasing it to mt_rand()
improves the quality of the output and means the same output can be expected for a given seed regardless of platform.
Replace RAND_RANGE()
The macro used to scale the output of an RNG between two bounds is insufficient for large ranges. (See bug #45184)
The proposed fix is to concatenate multiple outputs for ranges exceeding 32 bits, and use rejection sampling (the same as used in random_bytes()
) to produce unbiased outputs.
Replace insecure uses of php_rand() with php_random_bytes()
There are several instances where rand()
is used internally in a security sensetive context
crypt()
salt generation- SOAP HTTP auth nonce generation
mcrypt_create_iv()
fallback with invalid source.
These instances should all be fixed to use the secure random number generator (even mcrypt which is deprecated)
Backward Incompatible Changes
A call to srand()
or mt_srand()
with a given seed will produce a different output in the following functions:
Proposed PHP Version(s)
7.1
RFC Impact
To SAPIs
None
To Existing Extensions
This is covered in the Backward Incompatible Changes section
To Opcache
None, this is a functional change, no changes to opcodes or code generation are required.
New Constants
None
Open Issues
None
Proposed Voting Choices
This will be an all or nothing vote (after discussion), and as the changes are functional, will require a 50%+1 majority to pass.
Patches and Tests
WIP - I will release a patch after a week or so of discussion has taken place
Implementation
References
Rejected Features
None