Release #4Release #4
 GRC's Capability & Compatibility   Research

The evolving high-confidence ultra-high
entropy pseudo random number generator

1536 bits (256 base64 characters) of high-quality server-side entropy:
~ Waiting for page to load ~
1536 bits (256 base64 characters) of entropy from local client's JavaScript:
~ Waiting for page to load ~
Load-time client-side data GRC cannot readily determine:
Local time at start of page load:
Local time at end of page load:
Elapsed time for page load:
Browser's upper-left coordinate:(,)
Document's width and height:w=, h=
Post-load client-side data GRC cannot readily determine:
Last captured mouse position:( - , - )
Time of last event captured:
Count of all events captured:
SHA256 hash of all static and dynamic data collected above:

Click the mouse or press a key to obtain the final 256-bit high-entropy data to be used to key the
local pseudo-random number generator (PRNG).

See the following for details and complete explanation . . .

What's this page all about?

This is my “Steve Learns JavaScript” page. As the first coding I've ever done in JavaScript it serves as a way for me to develop some working familiarity with the language, establish a comfortable coding style, and so on.

But beyond that, since JavaScript is rightfully notorious as a cross-browser and cross-platform minefield, and since I refuse on principle to use any of the popular and powerful encapsulating pre-built libraries that mask these problems from their users (because I want to learn this stuff and do it myself), this page will allow the many participants in GRC's public newsgroups to determine, across their great variety of platforms, whether I have managed to create a browser and platform agnostic JavaScript implementation.

Generating good pseudo random numbers:

I learned JavaScript not only because my becoming fluent in it was overdue, but so that I could prototype a browser-based concept I have developed, known as the “Passcode Designer”. This page, however, is NOT the Passcode Designer.  That comes next.  One of the things the Passcode Designer needs, after being functional on all web browsers, is a cryptographically strong and trustworthy source of pseudo random numbers.

Cryptographically strong, high-quality pseudo random numbers are notoriously difficult for a computer to create because computers are not random. And while the JavaScript language does include a random number function, its quality is left up to the specific implementation. Unfortunately, as this link shows, the most popular browsers, including Microsoft Internet Explorer, Mozilla Firefox, Apple Safari, Google Chrome, Opera, are known to have cryptographically inadequate pseudo random number generators (PRNG).

It is well known that a stream of high-quality pseudo random numbers can be generated by using a cryptographic cipher to encrypt an incrementing counter. (Note that this essentially the scheme used by GRC's Perfect Paper Passwords system):


As shown above, to generate one of 'N' unpredictable pseudo random integers falling in the range from zero (0) to 'N-1', used to choose one character from a larger set of characters, we increment a 128-bit counter, encrypt the counter's new value under the influence of a fixed 256-bit key, then take the remainder (modulus) of dividing the 128-bit result by 'N'. This process can be repeated as often as necessary as long as the 128-bit input counter is never allowed to wrap-around, since it would then begin repeating its original count values.

As you can see, there's nothing truly “random” about this approach. In fact, quite the opposite is true: The same input counter value encrypted under the same cipher key will always produce the same result. But the value and power of this simple scheme is that the output characters are impossible to practically predict as long as the cipher's key is unknown to anyone trying to guess the system's output.

A 128-bit counter generates 340,282,366,920,938,463,463,374,607,431,768,211,456 values before it begins to repeat. So this application's need for only a small handful of pseudo random numbers means that we don't need to worry about “reseeding” our pseudo random number generator with a new key before the counter's value wraps around because, for all practical purposes, it never will.

But!  . . . What we DO need to consider is where and how we get the one 256-bit cipher key that we need to determine the pseudo random sequence? It must be obtained in such a way that the user of our Passcode Designer can trust that it is absolutely unknowable and unpredictable by any outside agency, including GRC. And THAT is the purpose of this page!

What does the JavaScript on this page do?

A trustworthy client-side (browser-based) passcode creation system needs to be based upon a high-entropy (highly random) “seed” so that it can produce passcodes that absolutely cannot be predicted by attackers. It is easy for us to obtain such a seed from GRC, since GRC's server maintains a high-entropy system used to drive its very popular Perfect Passwords page. But that would mean that GRC would know the seed being used to generate your passcodes, which is no way to design a cryptographically secure system.

While GRC is absolutely trustworthy, and has no interest in knowing anyone's passcodes, we want to be unable to respond to a court order requiring us to reveal whatever we might know. Since we already retain no logs of any kind of any server activity, it's already impossible for us to respond, but since it's easy for us to go further, that's what we have done here:

We start with a unique ultra-high-entropy seed received from
GRC, then we add further entropy to it locally so that
GRC will have no idea what final seed was used.

It's important to start with a unique high-entropy seed (which is easily provided by GRC) since we may not be able to guarantee the addition of a huge amount of local entropy. But we don't need to add much, only enough to make the final result unknowable by GRC's server. And entropy (randomness) is additive. Adding additional entropy to something that already has a guaranteed high level, only increases its randomness and makes the result even more secure.

Referring to the numbering show above, this is the source and meaning of each of the sections of data shown above:
1This is the original, 256-bit, guaranteed-unique “starter seed” delivered by GRC with this instance of this page. This seed has never been delivered before, and will never be delivered again. It is guaranteed to be unique. The seed is transmitted as a short-lived session cookie named "prng" (pseudo random number generator) in the response headers of this page. Since this page will only allow itself to be served by GRC's server over an encrypted and authenticated secure https: (SSL/TLS) connection, observation of the cookie's seed value is protected from eavesdroppers. And since this seed is further randomized after its receipt (see the following sections), even knowledge of it would provide little value to an attacker. As stated above, its purpose is to provide a high guaranteed lower level of entropy, which the user's browser then further increases.
2This section gathers data that cannot be exactly known to anyone outside of the browser, whether by GRC or some other attacker. This includes the exact millisecond of local time when the page began loading, the exact millisecond of local time when the page finished loading, a single pseudo random value from the browser's local JavaScript interpreter, the pixel coordinates of the browser's window and the pixel width and height of the web page's document window. Of all of these, the pseudo random value from the local JavaScrip interpreter certainly adds the most entropy—and a lot of it at that! Even though JavaScript might not be trustworthy to generate huge volumes of random data, there's no way for anyone to predict what any one value will be. The other data provides additional entropic frosting. It was included because it was economical to add and certainly doesn't hurt..
3In the interest of using all of the entropy available (because, why not?), the page also monitors and collects every movement of the user's mouse. Some mouse movement is likely and perhaps even unavoidable. And every specific unpredictable motion pours additional “uncertainty” into our ever-growing bucket of entropy (which is already pretty much overflowing). So we continuously collect all mouse movement data (X & Y position and time) and pour it all into our ever-growing entropy pot.
4Whenever the mouse is moved (at all) or any mouse key is pressed or released, or any keyboard key is pressed, released, or allowed to repeat, we capture the count of that event, the time of that event and, in the case of the mouse movement, the mouse's new position and feed all of that into an evolving cryptographic message digest (a 256-bit SHA256 hash).
5It's interesting to witness the comprehensive scrambling power of a cryptographically strong hashing algorithm. The latest 256-bit hash of all previously collected data is continuously presented on the page. When this technology is eventually used to key a cipher-based pseudo-random number generator, the latest hash value will be used as the cipher's new key.
Oh... and one last thing:

As a pure browser compatibility check, since the Passcode Designer will be utilizing mouse rollovers to help indicate that some graphical elements can be clicked upon (for those who refuse to read the manual), I want to verify that my code for rollover handling is also cross-browser. So . . . if you mouse over the text below, PLEASE let me know if it DOESN'T change! (Note: This is NOT expected to work with non-mouse-based touch interfaces which inherently lack “hovering” capability.)

Rollover Test
Mouse and Touch Event Log
arrow Oldest events(click or touch log to clear)Newest events arrow-r
( - , - )
1 - mousedown2 - mousemove3 - mouseup4 - touchstart5 - touchmove6 - touchend


And thanks VERY MUCH in advance for any feedback you can provide about the functioning, and especially the non-functioning, of this page under any whacky platform you may be able to conjure up!

Release History
1Initial release
As we see from the succession of additional released, although this first release worked well in the general case, it had a number of problems that were resolved, one by one, with the following releases.
2Cookies are bad
The initial design of this page had GRC's server communicating its 256-bits of pseudo random number generator “seed” entropy to the page's JavaScript through a first-party secured cookie over SSL. While it was safe to do this, we quickly learned that many people are not only blocking third-party cookies, but first-party cookies as well. This release changed the server's seed planting by embedding the seed directly into the page's JavaScript code as the page is being downloaded.
3Collecting “history” is bad
The initial design of this page had the JavaScript collecting every move of the mouse into a growing array and continuously hashing and rehashing all static and dynamic data as the dynamic data grew. Some people found that as the size of this mouse history grew, their browser began slowing down and, in some cases, stopping or pausing for extended periods of time. So the whole approach was scrapped. Now, instead of accumulating a growing history, the page “chains hashes” by merging the last hash data with any new event data, such as mouse movements, and re-hashing that merged collection to create a new hash.
4Fixing rollover animation hesitancy -&- Getting more client-side entropy
  • GRC's server had not been using an expires header to explicitly set the expiration of its objects in the future. This was forcing the browser to check back in with GRC to see whether the cached rollover image was still current. It always was, but the need to check was slowing down the animation. GRC's web assets are now all set to expire in one hour (3600 seconds) which should be long enough to accommodate typical visitors while not giving us a problem with modified assets not being refreshed.
  • Before now we were only pulling a single pseudo random number from the client's local JavaScript pseudo random number generator (PRNG). That was dumb. While the client's PRNG might not be cryptographically strong in its ability to generate massive volumes of pseudo random data, it is certainly good enough to generate a highly entropic small volume of good unpredictable data. JavaScript stores all numbers in IEEE 754 double precision floating point and its pseudo random number generator returns a fractional number ranging between 0 and 1. This means that each fractional number is able to represent 54 bits. We now take five numbers from the client's PRNG for a total of 270 bits of probably high quality entropy.


Jump to top of page
Gibson Research Corporation is owned and operated by Steve Gibson.  The contents
of this page are Copyright (c) 2020 Gibson Research Corporation. SpinRite, ShieldsUP,
NanoProbe, and any other indicated trademarks are registered trademarks of Gibson
Research Corporation, Laguna Hills, CA, USA. GRC's web and customer privacy policy.
Jump to top of page