Practical way to generate random numbers from PRNG which are indistinguishable from true random I am working on a project where I want the user to be able to create random data. For that I use a cryptographically random generator (Java's SecureRandom, which uses OS entropy source if available). Additionally I will seed this PRNG with a true 16 byte (or is more needed?) random number (from e.g. random.org). One seed usually only creates less than 1 MB of random data.

Is that a sound approach to generate random data that is indistinguishable from true random data?

Are there any steps to take to strengthen the security? Eg. scramble the seed to make it harder for an attacker who is listening to know what seed was used?
CAUTION: The seeding planned in the question has the potential to remove the default best-effort seeding normally provided by SecureRandom. It will actually do so with some security Providers. Some others will produce true random no matter what.

Worse, the seeding planned might make the output predictable by spying the machine's communication with random.org.



The specification of SecureRandom in Java (1.)5 and down to at least (1.)3 states (emphasis added):


  The SecureRandom implementation attempts to completely randomize the internal state of the generator itself unless the caller follows the call to a getInstance method with a call to one of the setSeed methods.


Java 8 is even clearer:


  If setSeed is not called, the first call to nextBytes will force the SecureRandom object to seed itself. This self-seeding will not occur if setSeed was previously called.




Recommendable practical ways to generate random numbers which are indistinguishable from true random assuming everything works as specified are:


Right after the SecureRandom constructor, perform a single nextBytes with some small numBytes >0 and disregard the result (even though 0 should do if a Vulcan implemented the spec), then setseed with whatever unpredictable data at hand, then use nextBytes.
Do not setseed, directly use nextBytes; but that additionally assumes that the runtime is able to supply entropy.


Method 1 is guaranteed not to lose the default best-effort seed, for in setseed:


  The given seed supplements, rather than replaces, the existing seed.


The above statement is leaving out an implicit and much needed: if any ! Notice that the additional statement:


  Thus, repeated calls are guaranteed never to reduce randomness.


only guarantees that the second and later setseed can't reduce randomness.

This quirk of the Java crypto API is a feature intended for testing: an initial setseed can make tests reproducible. That can be useful. Unfortunately it works, or not, depending on security Providers (at least, and to my knowledge only), and I know no way to tell other than trying. More generally the Java crypto API is complex and occasionally error-prone, to the point that it is hard to be sure that you will reliably get what you want to get, even though casual testing might suggest so.