How to generate a CPRNG in pure-php?

How to generate a CPRNG in pure-php when openssl and mcrypt are not available both?
How to write ANS X9.31 A.2.4 in php?

On Unix you can read directly from /dev/urandom and on Windows use its native random number generator via the COM extension. I’ve never done it myself but this comment in the manual shows how to do it.

In PHP 7 you can use new functions: random_bytes() and random_int().

It seems COM is deprecated:

That’s Microsofts CAPICOM not PHPs COM

Anyway, I don’t know as it would generate “cryptographically secure” values, but this may suit your needs

Actually, this algorithm is specifically for generating repeatable pseudo-random numbers based on a seed so it’s the opposite of what the OP wants.

I don’t think it’s easy to do without extensions because a good CPRNG will need to have enough entropy from unpredictable sources collected by hardware or by the OS observing the hardware. PHP has very limited access to such data so creating enough entropy is hard (you might make use of some network latency data, microtime, etc. but that is not much). On Linux you can just hook to /dev/urandom and your problem is solved. For Windows you would have to use some tricks.

Since PHP 5.3 mcrypt is built in and should always be available unless someone compiles PHP with mcrypt disabled. However, mcrypt is likely to be removed in the future.

A trick might be to use password_hash() in PHP >=5.5. The output of this function contains a 22-byte salt in the format ./0-9A-Za-z generated by a CPRNG available on the system, which means that you can extract it and base64_decode it and get a string of good (pseudo-)random binary bytes:

// let's use lowest possible cost for speed (it's irrelevant here)
$pass = password_hash('any text', PASSWORD_BCRYPT, ['cost' => 4]);

// base64 strings use + instead of . that password_hash produces;
// string length for base64_decode should be multiple of 4;
// salt starts at position 7:
$salt = str_replace('.', '+', substr($pass, 7, 20));

$bin_rand = base64_decode($salt);

// show hexadecimal representation of the random bytes
echo unpack("H*", $bin_rand)[1];

In this way you can get a 15-byte (or 120-bit) string of very good random bytes. Since the password that follows the salt in the output of password_hash() is a result of a very large number of cryptographic hash iterations then I presume it can be equally treated as a random string that we can use. It is in the same format as the salt (./0-9A-Za-z) so we can retrieve up to 52 characters:

$salt = str_replace('.', '+', substr($pass, 7, 52));

In this way we get a random string of 39 bytes or 312 bits - all without any extensions.

1 Like

You must go through Google you will many blog which post step for generate a CPRNG from them select which will suitable for you

I doubt - can you point us to at least one true CPRNG in pure PHP? This is not as easy as you might think.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.