Is there any good way to generate cryptographically strong pseudorandom (or true random) numbers in Javascript?
The crucial requirement: if a.com's Javascript generates some random numbers, no one else should be able to predict those random numbers. For instance, Javascript on evil.com should not be able to predict the random numbers that a.com got.
Summary of what I know about this subject. Here's what I've been able to find, in my own research:
All browsers provide
Math.random()
as a library call to generate pseudorandom numbers. Unfortunately, it does not provide crypto-quality random numbers and fails the requirement above. On the browsers I've seen,Math.random()
uses a non-cryptographic PRNG, and its internal state is shared across multiple sites. Therefore, evil.com can callMath.random()
a bunch of times, recover the internal state of the PRNG, and then infer what random numbers a.com got when it calledMath.random()
. Also, it uses a non-cryptographic-quality PRNG, so if a.com generates a random key and a random IV usingMath.random()
and then publishes the IV, it might be possible to infer the PRNG's internal state (from the IV) and then recover the key. So,Math.random()
is right out.I found a research paper that looks at doing cryptography in Javascript. Their code, the Stanford Javascript Crypto Library, is publicly available. It does include a crypto-strength pseudorandom number.
However, it appears to have a hefty limitation: if I'm reading the paper correctly, it takes 10-40 seconds of user interaction with your site before the pseudorandom number gets adequately seeded. Moreover, each site has to start over from scratch: if a.com includes the SJCL library, then it looks like a.com's script has to wait for the user to interact with the a.com site for 10-40 seconds (typically) before a.com can generate crypto-quality random numbers. This is a pretty significant limitation.
Here's their paper:
- Emily Stark, Michael Hamburg, Dan Boneh. Fast symmetric cryptography in Javascript. ACSAC 2009.
The classic essay, Javascript Cryptography Considered Harmful, mentions the lack of any good way to get crypto-strength random numbers in Javascript as a major barrier to doing secure cryptography in Javascript. The essay considers several obvious approaches and explains why they are flawed.
The bottom line is that I don't know of any reasonable solution; the options I found all seem pretty problematic. However, it has been several years since those papers and essays were written, and I know that web technology can change rapidly. Does anyone know of any good solution to this problem?