25

I know from experience that reading from /dev/random blocks when the Linux kernel entropy pool runs out of entropy. Also, I've seen many articles and blog entries stating that when running on Linux, java.security.SecureRandom uses /dev/random as its entropy source and thus blocks when the kernel entropy pool runs out of entropy.

However, I'm unable to produce an experiment which causes SecureRandom to block. Conversely, it seems easy to get a simple bash one-liner which reads from /dev/random to block.

Here's the java code I'm using for these experiments:

import java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr = new SecureRandom();
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}

It generates just over 1,000,000 random 32-bit integers. That should be 2^(20 + log2(32)) = 2^25 bits or 2^22 (a little over 4 million) bytes of entropy, right? However, it never blocks. It always finishes in about 1.2 seconds no matter whether I wiggle the mouse or not.

The bash one-liner I used is:

head -c 100 /dev/random | xxd

This blocks easily. As long as I keep my hand off of the mouse and keyboard, it'll sit there doing nothing for several minutes. And I'm only asking for 100 bytes of entropy.

Surely I'm missing something here. Could someone explain what's going on?

Thanks!

1
  • 2
    There is no reason for a CSPRNG to block again after it's seeded once. Blocking is useful after reboot, hibernation etc. because you need sufficient initial entropy, but "entropy drain" is not a threat in practice. Commented Aug 14, 2013 at 19:35

5 Answers 5

41

Both OpenJDK and Sun read from /dev/urandom, not /dev/random, at least on the machine where I tested (OpenJDK JRE 6b27 and Sun JRE 6.26 on Debian squeeze amd64). For some reason, they both open /dev/random as well but never read from it. So the blog articles you read either were mistaken or applied to a different version from mine (and, apparently, yours).

You can check whether yours reads from /dev/random or /dev/urandom by tracing it:

strace -o a.strace -f -e file java A

and look for the relevant part of the trace:

21165 open("/dev/random", O_RDONLY)     = 6
…
21165 open("/dev/urandom", O_RDONLY)    = 7
…
21165 read(7, "\322\223\211\262Zs\300\345\3264l\254\354[\6wS\326q@", 20) = 20
…

Don't worry, /dev/urandom is perfectly fine for cryptography.

5
  • 1
    Simple, answers my question, backs up his claims. Thanks and +1. (That is +1 if I had enough reputation to upvote...) Commented Aug 15, 2013 at 13:09
  • 1
    Apparently on Android, SecureRandom has a different implementation which has caused repeated values: theregister.co.uk/2013/08/12/… Commented Apr 13, 2014 at 20:07
  • 5
    @WillSargent Not true. Android's SecureRandom also reads from /dev/urandom so it is conceptually the same deal. There was however, a flaw in the way Android initialized /dev/urandom, causing the issue.
    – DCKing
    Commented Jul 22, 2014 at 11:21
  • @DCKing No, true. The implementation is different, and it caused repeated values. I never said it read from /dev/random. See source at android-developers.blogspot.com.au/2013/08/… Commented Jul 22, 2014 at 15:21
  • 4
    Yes, so to clarify: the differences SecureRandom's implementation between Java and Android were not the cause; it was the difference in the implementation of /dev/urandom on Android and other *nixes that was the cause.
    – DCKing
    Commented Jul 22, 2014 at 15:32
12

Java's SecureRandom does use /dev/random, but only briefly.

Specifically it only uses it when generating seed information, either by explicitly calling SecureRandom.generateSeed() or by the first call to nextInt()

So therefore, to repeat your bash example you can do the following, and it should block.

import java.security.SecureRandom;

public class A {
    public static void main(String[] args) {
        SecureRandom sr;
        int out = 0;
        for (int i = 0; i < 1<<20 ; i++) {
            sr = new SecureRandom();
            out ^= sr.nextInt();
        }
        System.out.println(out);
    }
}
4
  • Does this override securerandom.source in $JAVA_HOME/lib/security/java.security? AFAIK, if securerandom.source is /dev/urandom then it will never use /dev/random Commented Nov 14, 2014 at 16:34
  • The way I understand it this depends greatly on your version (and implementation) of Java. From my own experiments with Oracle JVM 7 the only way to completely ignore /dev/random is to set securerandom.source to /dev/./urandom. Otherwise it will still use /dev/random for seed generation. Commented Nov 15, 2014 at 4:21
  • You say "should block", did you test it? Commented Oct 1, 2015 at 0:51
  • I don't think that I did. Commented Oct 12, 2015 at 23:31
4

$JAVA_HOME/lib/security/java.security: securerandom.source property dictates which device to use when using SecureRandom. The default value is /dev/urandom, which means Java will never block.

For new comers to the topic, /dev/urandom is special version of /dev/random, which will use true entropy from /dev/random when available and then pseudo random data seeded true entropy if it was available.

In headless, VM and Cloud environments, I recommend seeding urandom from an external source, such as http://random.org

3
  • 2
    But you can only retrieve entropy securely from random.org if you have enough entropy to create a secure SSL connection. So you have a chicken-egg problem. Commented Nov 14, 2014 at 11:57
  • V. good point! Back to the drawing board Commented Nov 14, 2014 at 17:00
  • 1
    I'm using Java 8 and the default configuration is: securerandom.source=file:/dev/random
    – ovunccetin
    Commented Feb 4, 2015 at 9:21
4

On recent vintage Linux (last 6 years, say) the computational difference between /dev/random (blocking) and /dev/urandom (non-blocking) is very marginal; the raw entropy is laundered through a random number generator and both devices use the same bits. The only difference is that /dev/random has a rate limiter that prevents it from running too long without reseeding. The rate estimate itself is quite debatable.

This is explained in http://www.2uo.de/myths-about-urandom/ which drives home the point that /dev/urandom is sufficient for seeding your cryptographic algorithms for session keys. If you don't call it too frequently, then both should be of identical or nearly identical quality.

I have seen blocking via /dev/random when running a web crawler that needed to make 1000+ simultaneous SSL connections (session keys), and yes, we switched to /dev/urandom; for bulk generation of long-held public/private key pairs (a rare situation), a custom entropy device is best.

4

Not just to keep an old thread alive but some people might have missed a important part of the long story behind this... It's been about an well known infamous and persistent bug when using /dev/urandom from Java versions 1.4 to versions 1.7. See the links below :

http://bugs.java.com/view_bug.do?bug_id=6202721

http://bugs.java.com/view_bug.do?bug_id=4705093

For that I know, this has finally been addressed in Java 8 as stated by Oracle : https://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html

SHA1PRNG and NativePRNG were fixed to properly respect the SecureRandom seed source properties in the java.security file. (The obscure workaround using file:///dev/urandom and file:/dev/./urandom is no longer required.)

1
  • 3
    It would be better if you included a summary of the Java problem in your answer. Commented Jan 28, 2016 at 18:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .