I would like to do some experimenting with javascript and encryption and I got curious as to how unpredictable the implementation of the random function is. Has anyone done any hard tests?
Clearly browsers have the ability to generate strong randomness (for ssl). The questions is do they give javascript access to the same strength.
Note: Math. random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely the window.
For starters, it's not really random Surprise surprise, the answer is that Math. random() doesn't really generate a random number. Not exactly. It just does a really good job of simulating randomness.
As the Math. random() function relies on a weak pseudorandom number generator, this function should not be used for security-critical applications or for protecting sensitive data. In such context, a cryptographically strong pseudorandom number generator (CSPRNG) should be used instead.
With JavaScript's web cryptography API in place, the server can't see data since it's cryptographically secure. Only the sender and receiver have access to communication data.
Generally, the random function is not cryptographically strong, for that you need to make sure you are using a cryptographic pseudo-random-number generator.
Generic random functions generally don't use cryptographically strong generation methods because they take longer than simple ones, (eg. Yarrow is more complicated than Mersenne Twister) and require careful management of the entropy pool, which is not a guarantee that Mozilla, cstdlib, etc. want to make to you.
If you need access to cryptographically strong random number generators, I'd look into getting access to the underlying SSL implementation (which a given browser may or may not allow access to).
Recent browsers expose window.crypto.getRandomValues()
which is cryptographically strong.
There are also JS libraries that implement strong RNGs but without getRandomValues()
it's very hard part to collect entropy. It can be done from mouse & keyboard though it may take a long time.
Math.random()
was weak in most browsers in 2008 - Amit Klein's paper goes into excellent detail - and sadly is almost as weak today.
UPDATE: It seems practically all browsers switched in 2015–2016 to XorShift128+ — a fast variant on LFSR tuned to good statistical properties but also very weak cryptographically: https://lwn.net/Articles/666407/, https://security.stackexchange.com/questions/84906/predicting-math-random-numbers. Details below are out of date.
Firefox used a very weak "our own homebrew LFSR" algorithm; they've been discussing switching to a stronger algoritm and entropy source since 2006 (bug 322529). UPDATE: in 2015 they switched to XorShift128+.
In May 2013 they at least switched the seed from current time to good entropy sources (bug 868860), also removing(?) cross-tab leakage.
Webkit uses a weak fast algorithm (GameRand) since 2009 but seeds since 2010 (in each context) from a strong RNG initialized from strong OS sources.
(I presume this is what Safari uses but I may be confused about the various WebKit ports...)
Chrome doesn't use WebKit's random, does its own in V8, a weak linear thing.
There is no agreement whether Math.random() should be strong (bug 246054).
Not sure how it's seeded. V8 has SetEntropySource() hook, but apparently it was only introduced for unit testing, not called by Chrome. If not called, random()
is used for seeding.
State became per-context in 2011 but that's not very useful with weak seeding.
Opera declared it fixed in Jan 2009 and say here that their Math.random() is cryptographically strong.
Didn't find documentation on what IE does nowdays. They had a weak linear PRNG in 2008 (see paper). They did tell Amit they'll fix it in a service pack, so there might be an advisory somewhere...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With