CSPRNG Documentation

This is a PHP library that implements a CSPRNG and a set of convenience functions for generating cryptographically secure random tokens, numbers, and strings under a MIT or LGPL license. It works under a wide variety of web hosts including Windows and doesn't depend on any specific PHP extensions to be enabled - but will use them if they are enabled (e.g. OpenSSL, mcrypt).

This product works standalone but can also be used with the Ultimate Web Scraper Toolkit for more reliable data retrieval when generating root seeds. The functions in 'support/http.php' just need to be loaded prior to root seed generation.

Features

The following is a short list of features for this product:

And much more.

License

CSPRNG is extracted from Barebones CMS and the license is also your pick of MIT or LGPL. The license and restrictions are identical to the Barebones CMS License.

If you find CSPRNG useful, financial donations are sincerely appreciated and go towards future development efforts.

Installation

Installing CSPRNG is easy. The installation procedure is as follows:

Installation is easy. Using it is a bit more difficult.

Upgrading

Like Barebones CMS, upgrading CSPRNG is easy - just upload the new files to the server and overwrite existing files.

Background

This CSPRNG was born out of the need for generating cryptographically secure random strings for session keys and security tokens in Barebones CMS across all platforms that PHP is supported on. If you have been looking for a good, cross-platform CSPRNG solution for PHP, you can probably stop looking. While this is primarily for generating security tokens, it can also be used to generate random numbers.

Keep in mind that CSPRNGs are slower than their PRNG counterparts. Don't expect too much speed from this even though effort has been made to make this a relatively fast implementation.

The hardest part of creating CSPRNG was that there was (and is) little to no documentation out there on how to actually get entropy. Lots of documentation exists on what to do once I had entropy but there is a huge amount of hand-waving when it comes to entropy gathering techniques. No one just comes out and says, "Here's sample code on how to actually implement the most critical piece of the puzzle." Regardless of the reasoning, a lot of software developers are left scratching their heads when it comes to random number generation. Developing CSPRNG in pure PHP was actually a lot harder than someone might think since there is no single function in PHP that can be called to guarantee enough entropy that will work on all web hosts and there is a ton of misinformation on the PHP website. This is partly the fault of PHP itself for being an incredibly flexible cross-platform tool so that it can run on a wide variety of hosts. Therein lies both its strength and weakness when it comes to application security for PHP.

This is my third attempt or so at a PRNG in this vein, so I do have a clue as to what I'm doing. Full disclosure: I have a slightly creepy fascination with random number/string generators that can optionally accept additional entropy input (random or otherwise) and still have random output.

Generating Root Seeds

Before random numbers or strings can be generated, a root seed has to be created. Barebones CMS creates two root seeds and stores them in the global configuration file during installation. Root seeds form the basis of the security system and must be kept secret at all times. Even if the root seeds are exposed, it is still quite difficult to generate correct session keys and security tokens due to how CSPRNG operates. The root seed approach helps speed up random string/number generation but it also forms a potential attack vector. As long as a root seed stays secure, there is no polynomial-time system that can reverse engineer the root seed itself. I recommend generating a minimum of two root seeds per login system.

Creating a new root seed is fairly simple:

<?php
	require_once "support/random.php";

	$options = array(
		"urls" => RSG_GetRootSeedURLs()
	);
	$info = RSG_GenerateRootSeed($options);
	if ($info["strength"] < 5)
	{
		echo "Insufficient entropy available to this host.\n";
		exit();
	}
	$rootseed = $info["result"];
?>

The code creates the options array with the default, trusted set of secure random entropy sources (highly recommended) and then generates a root seed. This operation can take several seconds to complete. Once that has finished, a root seed is returned along with the strength of the seed. If 'strength' is less than 5, the seed is weak and should be used with caution or not at all depending on the needs of the application.

Because root seeds are expensive to create, an application should, in general, permanently store the root seed somewhere safe for later use. Root seeds should only be created two or three times per 24 hour period per IP address. Internally, the main function calls trusted external web resources, specified by RSG_GetRootSeedURLs(). The URLs have daily bit limitations but they output high-quality randomness. Requesting too much data within a 24 hour period can result in an IP address ban.

Generating Tokens

Once a root seed has been created, any number of tokens can be generated using the root seed. Tokens can be used for any purpose. Barebones CMS generates two tokens for every login session. A public token is generated to be sent across the Internet to the user's browser and a private token is generated to be used internally for that session. Each user account also has a private token for use as entropy data for generating the two login tokens. This creates two degrees of distance between the end-user and the root seeds.

Creating a new token is easy:

<?php
	$token = RSG_GenerateToken($rootseed, $username . serialize($_REQUEST) . $password);
?>

When generating tokens, it is ideal to insert some extra entropy even if it is constant data. Tokens can also be used as entropy data to generate new tokens.

Random Byte and Random Number Streams

The token generator produces very good quality random data at reasonable performance. As such, it can double as a general-purpose random string and random number generator.

The output of the tokens have been tested against the Diehard test suite and, assuming I understand the output correctly, have some shifting bias of the p-values between runs but none of the tests I ran ever "failed badly" according to the author's definition. Basically, in English, it isn't the world's best general-purpose pseudo-random number generator, but its output seems reasonable enough to use for such purposes. My tests and lightweight stats gathering (beyond Diehard) plus some eyeballing of many sample 100,000 number runs showed it to be roughly on par with the PHP Mersenne Twister implementation in similar configurations. All of this, of course, doesn't preclude an expert coming along later and telling me I've misinterpreted the results or exposing some major logical flaw - I know enough to be dangerous but I'm not an expert statistician. I am confident, however, that this is producing very good quality random data that can be used for any purpose.

Included with CSPRNG are two classes that convert tokens into streams of bytes or integers. The first class produces a stream of random bytes and integers:

<?php
	$randgen = new RSG_Stream();
	$randgen->Init($rootseed);
	for ($x = 0; $x < 100; $x++)
	{
		$result = $randgen->RandomInt(0, 40, $x);
		echo $result . "\n";
	}
?>

The example above shows integers between 0 and 40 inclusive being selected at random.

The RSG_Stream class also has a RandomBytes() member function to retrieve a specified number of bytes of random data. Essentially, it just returns a sequence of RSG_GenerateToken() calls.

The second class, RSG_NormalizedStream, produces a stream of random integers that have been normalized:

<?php
	$randgen = new RSG_BalancedStream();
	$randgen->Init(0, 40, $rootseed);
	for ($x = 0; $x < 100; $x++)
	{
		$result = $randgen->RandomInt($x);
		echo $result . "\n";
	}
?>

This is similar to the first example. Technically, the output isn't random since the distances fall into a standard normal distribution along a bell curve with large data sets. However, sometimes this is desirable behavior as each number in the range must be used one time before it can be used again. The behavior could be used to initially scramble an ordered deck of cards and then some further scrambling could be done with the RSG_Stream class, which offers actual randomness.

What's Next?

For details on each function and class, see the Extra Components Documentation.

© CubicleSoft