
Predicting the next Math.random() in Java - nilknarf
http://franklinta.com/2014/08/31/predicting-the-next-math-random-in-java/
======
imaginenore
If you want cryptographic-quality random numbers, both Java and Javascript
have them. Math.random() is simply a super-fast decent RNG.

Example:

    
    
        var buf = new Uint32Array(10); 
        window.crypto.getRandomValues(buf);
        console.log(buf);
    

Outputs things like:

    
    
        [4027145128, 258543382, 1205615760, 2665675208, 4033127244, 
         2280027866, 3983484449, 510932333, 1911490534, 2609399642]
    

This works in Chrome and FF.

IE11 has Crypto.getRandomValues(...)

Java has SecureRandom:

[http://docs.oracle.com/javase/6/docs/api/java/security/Secur...](http://docs.oracle.com/javase/6/docs/api/java/security/SecureRandom.html)

~~~
SeanLuke
> Math.random() is simply a super-fast decent RNG

Actually, java.util.Random is a horrible, horrible RNG. Its least significant
bit (for example) is grotesquely nonrandom. See
[http://www.alife.co.uk/nonrandom/](http://www.alife.co.uk/nonrandom/) for a
wonderful demonstration of its awfulness. There are other serious bugs in
java.util.Random which Sun, er, Oracle, has steadfastly refused to fix or
revise for a decade now due to concerns about "backward compatibility" (in an
RNG!)

> If you want cryptographic-quality random numbers

I think you're confusing "crytographic-quality" with "high quality".

RNGs tend to break down into two different camps. First, there are RNGs meant
for simulation of stochastic processes. These RNGs need to be fast, have good
periods, and have a very high degree of statistical randomness in their
output.

Second, there are RNGs meant for crypto. Speed is less important. Rather it's
important that these RNGs provide good statistical randomness, but also it's
crucial that, given some M previous output numbers of the RNG, you cannot
predict or make any statistical claims about the next number even if you know
how the algorithm works. This isn't important for non-crypto RNGs.

For example, Mersenne Twister is a pretty high quality, widely used RNG. But
it is not cryptographically secure: if you have about 1500 of the previous
output numbers, you can perfectly predict the next number if you know it's MT
producing them.

While there are many applications for crypto RNGs, for a great many tasks, a
non-crypto RNG would be a better fit.

java.util.Random was meant for non-crypto tasks. And it completely fails at
_even those_ tasks.

But SecureRandom is really bad for those tasks too: it is slow. For example,
my MersenneTwister implementation is about 9 times faster than SecureRandom;
and my non-threadsafe MT implementation is about 36 times faster. That's a big
deal if you're pulling down millions and millions of numbers.

~~~
TheLoneWolfling
> There are other serious bugs in java.util.Random which Sun, er, Oracle, has
> steadfastly refused to fix or revise for a decade now due to concerns about
> "backward compatibility" (in an RNG!)

Backward compatibility in a RNG is actually rather important, weirdly enough.
For example, anything that uses deterministic seeds for repeatability of
procedural generation or optimization. (Read: Minecraft, among other more
important things).

That being said, things like this are why I wish more programming languages
had proper (read: fine-grained) versioning of libraries. "I need to link to a
function with this signature, that is one of these versions or any version
that has been declared to be compatible with them, preferably the latest
version that is so". That sort of thing.

> For example, Mersenne Twister is a pretty high quality, widely used RNG. But
> it is not cryptographically secure... But SecureRandom is really bad for
> those tasks too: it is slow. For example, my MersenneTwister implementation
> is about 9 times faster than SecureRandom

By your own words, you're comparing apples to oranges here...

~~~
SeanLuke
> Backward compatibility in a RNG is actually rather important, weirdly
> enough. For example, anything that uses deterministic seeds for
> repeatability of procedural generation or optimization. (Read: Minecraft,
> among other more important things).

This seems like a very, _very_ bad thing to rely on. Other than Java, how many
other languages have guarantees in generator determinism from version to
version as part of the language contract? Certainly Lisp considers it an
antipattern.

~~~
michaelt
Any language that allows the PRNG to be manually seeded, presumably?

I mean, if manually seeding the PRNG doesn't produce a deterministic result,
you wouldn't make it part of the API.

~~~
SeanLuke
Nope.

Essentially all languages allow manual seeding: almost none specify guarantees
with regard to RNG behavior. I'm pretty sure this is because determinism of a
_given_ process important (everyone who does simulation needs that), but
locking into potentially bad RNGs for the language or library itself, in fact
specifying them, is a really bad idea.

------
mnw21cam
That is a nice not-so-subtle reminder. When a PRNG says it is insecure, _it is
insecure_. When a PRNG says it is secure, it _might_ be - get someone very
clever to check it first.

------
phpnode
nitpick, Firefox doesn't use Rhino, it uses SpiderMonkey which is C++.

[https://developer.mozilla.org/en-
US/docs/Mozilla/Projects/Sp...](https://developer.mozilla.org/en-
US/docs/Mozilla/Projects/SpiderMonkey)

------
drinchev
How dangerous this prediction can be? I can't stop thinking of java-backended
real money, poorly written, gaming websites.

~~~
UnoriginalGuy
Those likely won't be vulnerable even if they implemented their site using the
insecure random function. The reason why this works is that you're the only
consumer of Java-randomness, as you add additional consumers it becomes
infinitely more difficult.

Consumers also don't need to be users, AI players and cards dealt will also
consume randomness. You would also need to know the mapping from the random
output into the game (e.g. in card games are there multiple decks each
assigned 1 value of entropy? 2 decks, 3 decks, etc? Plus any mappings or
conversions will make this impossible (as you wouldn't know the real output of
the random number generator)).

Ultimately it will likely work pretty reliably locally, but as soon as you
stick it on a web service then all bets are off.

~~~
banthar
This more probable than you think. Java code is likely to use
Collections.shuffle(). That method uses internal Random which is used only for
shuffling. Shuffling is unlikely to be used for other purposes than shuffling
cards. There isn't that many ways to shuffle them either.

~~~
ivanche
I worked for 6 years in a company which makes online (gambling) games. I can
tell you that anyone who even thinks of using Collections.shuffle() for
shuffling cards _in production code_ is an amateur.

------
xxs
Math.random() should be used only for tests. That's it. Performance sucks as
it's shared. ThreadLocalRandom is a lot better if you need fast but not-
quality random.

And there is SecureRandom for security concerns.

Last fun fact Math.random() and a Monte Carlo test introduced "CAS in Java"
and all that followed with JSR 166.

------
mda
Reminded me an interesting Java Random issue with small seeds and power of two
intervals:

    
    
      for(int i = 0; i < 256; i++) {
          System.out.println(new Random(i).nextInt(8));
      }
    

It returns same number for all seeds.

------
lunixbochs
I tested a similar attack against ApacheCommons' RandomStringUtil. Given a few
bytes of output, I could recover the RNG state in 20 minutes on CPU.

------
jlebar
As another commenter has said, Firefox doesn't use Rhino. Here's the relevant
code in Firefox's JS engine.

[http://dxr.mozilla.org/mozilla-
central/source/js/src/jsmath....](http://dxr.mozilla.org/mozilla-
central/source/js/src/jsmath.cpp#765)

------
Peksa
Hah, funny! I recently did the same to circumvent CSRF-protection based on
java.util.Random. Here's my solver in JS:
[https://peks.as/experiments/random/](https://peks.as/experiments/random/)

