71

In a project I'm working on, the application is launched using a command similar to this:

java -Djava.security.egd=file:/dev/urandom -jar app.jar

I've never seen the java.security.egd option before. Searching a bit, it seems to be used to configure random number generation in a Java application.

Is it right? When is it supposed to be applied?

davioooh
  • 23,742
  • 39
  • 159
  • 250

3 Answers3

111

TL;DR

If running Java 8 on modern OSes with support to Deterministic Random Bit Generator (DRBG), I'd recommend using
-Djava.security.egd=file:/dev/urandom to avoid getting the code blocked unexpectedly. If not sure about the OS being used, my suggestion is to stick with the original recommendation, namely:
-Djava.security.egd=file:/dev/./urandom

If running Java 11, I'd recommend simply using
-Djava.security.egd=file:/dev/./urandom to make sure of:

  1. leveraging the strongest SecureRandom implementation available (DRBG) regardless the underpinning platform
  2. avoiding getting the code blocked unexpectedly (securerandom.source=file:/dev/urandom)

Read on to know the details.


Java applications can and should use java.security.SecureRandom class to produce cryptographically strong random values by using a cryptographically strong pseudo-random number generator (CSPRNG). The standard JDK implementations of java.util.Random class are not considered cryptographically strong.

Unix-like operating systems have /dev/random, a special file which serves pseudo random numbers accessing environmental noise collected from device drivers and other sources. However, it blocks if there is less entropy available than requested; /dev/urandom typically never blocks, even if the pseudorandom number generator seed was not fully initialized with entropy since boot. There still is a 3rd special file, /dev/arandom which blocks after boot until the seed has been securely initialized with enough entropy, and then never blocks again.

By default, the JVM seeds the SecureRandom class using /dev/random, therefore your Java code can block unexpectedly. The option -Djava.security.egd=file:/dev/./urandom in the command line invocation used to start the Java process tells the JVM to use /dev/urandom instead.

The extra /./ seems to make the JVM to use the SHA1PRNG algorithm which uses SHA-1 as the foundation of the PRNG (Pseudo Random Number Generator). It is stronger than the NativePRNG algorithm used when /dev/urandom is specified.

Finally, there is a myth that /dev/urandom is a pseudo random number generator, a PRNG, whilst /dev/random is a “true” random number generator. This is simply not true, both /dev/random and /dev/urandom are fed by the same CSPRNG (cryptographically secure pseudorandom number generator). Only their behaviour differs: /dev/random blocks when its randomness pool runs out of entropy according to some estimate, whilst /dev/urandom does not.

What about systems with low entropy? It isn't that bad.

It turns out that “looking random” is the basic requirement for several cryptographic components such as webserver's ephemeral session keys. And if you take the output of a cryptographic hash, it is indistinguishable from a random string so that ciphers will accept it. That's the reason of using the SHA1PRNG algorithm, as it uses a hash function and a counter, together with a seed.

When is supposed to be applied?

Always, I'd say.

Sources:
https://gist.github.com/svrc/5a8accc57219b9548fe1
https://www.2uo.de/myths-about-urandom


EDIT 09/2020:
I have changed this update to reflect the tests with:
-Java 8 on modern OSes
-Java 11 as it is the currently long-term support (LTS) version.

A comment mentions a change on SecureRandom class' behaviour in Java 8.

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.)

This had already been pointed out by the tests referenced on the Sources section above. The extra /./ is required to change the algorithm used by SecureRandom in Java 8 from NativePRNG to SHA1PRNG.
I agree that NativePRNG is more secure than SHA1PRNG, but only when running on modern OSes. I have therefore updated accordingly my conclusion and moved it to the top.

However, I do have some news that I'd like to share. As per the JEP-273, since Java 9 the SecureRandom class implements the three Deterministic Random Bit Generator (DRBG) mechanisms described in NIST 800-90Ar1. These mechanisms implement modern algorithms as strong as SHA-512 and AES-256.

The JDK previously had two kinds of SecureRandom implementations:

  • One is platform-dependent and based on native calls or OS devices such as reading /dev/{u}random on Unix or using the CryptoAPI on Windows. The latest releases of Linux and Windows already support DRBG, but older releases and embedded systems might not.
  • The other kind is a pure Java implementation that uses an older SHA1-based RNG implementation, which is not as strong as the algorithms used by approved DRBG mechanisms.

Meanwhile the Java 11 Security Developer’s Guide still reads

On Linux and macOS, if the entropy gathering device in java.security is set to file:/dev/urandom or file:/dev/random, then NativePRNG is preferred to SHA1PRNG. Otherwise, SHA1PRNG is preferred.

To clarify how the new DRBG mechanisms play together with the previous PRNGs, I ran some tests on macOS (Darwin) with AdoptOpenJDK (build 11.0.7+10). Here are the results:


-Djava.security.egd=file:/dev/random (This equals the default option)
Default algorithm: NativePRNG
Provider: SecureRandom.NativePRNG algorithm from: SUN

-Djava.security.egd=file:/dev/urandom
Default algorithm: NativePRNG
Provider: SecureRandom.NativePRNG algorithm from: SUN

-Djava.security.egd=file:/dev/./urandom
Default algorithm: DRBG
Provider: SecureRandom.DRBG algorithm from: SUN


Finally, the point of using /dev/urandom as source of randomness still remains paramount even when using modern OSes, as we can read on this very interesting post:

Sharing /dev/random is a challenge for any Linux container technology...
The low amount of entropy on virtualized servers problem is exacerbated because ... Linux Containers running on the same host compete for a limited supply of entropy. This type of problem is sometimes referred to as a stampeding herd. The /dev/random device is a scarce shared system resource that Linux Container tenants likely have not realised they are sharing. When they all try to use it at the same time they are effectively causing a denial of service on each other.

Sources:
https://www.openssl.org/blog/blog/2017/08/12/random/

dbaltor
  • 2,737
  • 3
  • 24
  • 36
  • 1
    As of Java 8, the "obscure workaround" of the extra ./ in the file name is not required any more, so you can just use "/dev/urandom", see: https://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html – Kamal Apr 27 '20 at 19:27
  • Thanks for updating the answer (specially about the changes in Java 9 and 13). Per my understanding though, as of Java 8 setting the "entropy gathering device" to /dev/urandom or /dev/./urandom should yield exactly the same results, otherwise the fix wouldn't make sense. From an OS perspective, those point to the same identical file, so that shouldn't affect Java (it did before the fix, but that was a bug, not an intended feature). Therefore your statement "The extra /./ is required to influence the PRNG selection." should no longer be true, as of Java 8. – Kamal Apr 30 '20 at 11:23
  • 1
    Thanks @Kamal for your comments. My previous phrase "PRNG selection" wasn't clear enough. I've rephrased it to clarify I'm talking about the algorithm used: NativePRNG or SHA1PRNG. The use of `/dev/urandom` selects NativePRNG fed by `/dev/urandom` whilst `/dev/./urandom` picks SHA1PRNG up (also fed by `/dev/urandom`) when using Java 8. From Java 9 onwards, DRBG takes precedence when `/dev/./urandom` source is specified. – dbaltor May 01 '20 at 18:46
  • 1
    Thanks again dbaltor. I would still recommend updating the original part of your answer "The extra /./ seems to make the JVM to use the SHA1PRNG ..." clarifying that it's only for Java 8 and earlier (Java 8 is still popular AFAIK). Also, the way it's phrased makes it sound as if SHA1PRNG is a safer or better choice. I'm no expert, but https://tersesystems.com/blog/2015/12/17/the-right-way-to-use-securerandom/ and https://stackoverflow.com/a/27638413/279726 seem to recommend leaving it to Java to determine the appropriate PRNG, rather than forcing SHA1PRNG, which is less safe in certain cases. – Kamal May 08 '20 at 19:35
  • P.s. Small typo in "SecureRanom" ; ) – Kamal May 08 '20 at 19:37
  • I do not agree "urandom" is the optimal solution in terms of security. Of course other solutions may be quite complex to be implemented. See for example this [video](https://youtu.be/1cUUfMeOijg) that explain solutions used by Cloudfare. – Mariano Paniga Aug 11 '20 at 10:24
  • I'm confused by seemingly contradictory mentions of blocking reads. TL;DR says "avoiding getting the code blocked unexpectedly" and then uses `file:/dev/urandom` in the example (with the letter U). But the section about "myth" says "`/dev/random` blocks [...] whilst `/dev/urandom` does **not**" (emphasis mine). Am I misunderstanding the answer, or is there a discrepancy? – andrybak Feb 09 '22 at 15:50
  • 2
    Thanks. Java 17 is LTS now. According to spec your answers for jvm 11 is still valid for jvm 17 Specs: https://docs.oracle.com/en/java/javase/17/security/oracle-providers.html – aholbreich Feb 09 '22 at 16:28
  • Thanks @andrybak for your question. The myth is about `/dev/urandom` being a **pseudo** random number generator whilst `/dev/random` would be a “true” random number generator. Both get their numbers from the same source (CSPRNG). – dbaltor Feb 11 '22 at 01:46
  • @dbaltor could you please clarify which of the two has blocking reads? – andrybak Feb 12 '22 at 11:43
  • `/dev/random` can block unexpectedly. – dbaltor Feb 14 '22 at 13:55
1

This is related to the difference of linux /dev/random and /dev/urandom random number generator.

Taken from this link

Java Bug 6202721 states that java.security.SecureRandom uses /dev/random rather than /dev/urandom even if /dev/urandom is specified because at the time (around 2004) /dev/urandom was not working properly. The bug has never been reversed now that /dev/urandom works quite well. Therefore, you have to fake it out by obscuring the setting by using /dev/./urandom to force the use of SHA1PRNG rather than /dev/random.

To answer your question

When is supposed to be applied?

Based on the above link, that is something unique to Java versions 5 and following that resulted from problems with /dev/urandom on Linux systems back in 2004.

Community
  • 1
  • 1
Ruelos Joel
  • 2,209
  • 3
  • 19
  • 33
  • There is probably a typo in that article, as Java Bug 6202721 actually states "This is a problem if /dev/urandom was chosen because /dev/random is not working properly.". Therefore your conclusion "resulted from problems with /dev/urandom" is incorrect. See the accepted answer for an explanation on choosing /dev/urandom instead of the default (/dev/random). It's a good idea in most cases. – Kamal Apr 30 '20 at 11:33
0

This is no longer required if you are using JDK 8 or higher

The issue has been fixed by Java and here are some links

Outline

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.)

For more info (search for random in the page):

https://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html

https://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html​​​​​​​

Venu
  • 1,513
  • 3
  • 19
  • 37
  • I do not believe this is correct. For background: https://tersesystems.com/blog/2015/12/17/the-right-way-to-use-securerandom/ The fixes in Java 8 only say that they now respect the SecureRandom seed source properties in the java.security file. But by default that still contains: securerandom.source=file:/dev/random The "obscure workaround" refers to the extra ./ in the file name, also mentioned by the accepted (and most voted) answer here. – Kamal Apr 27 '20 at 19:13
  • 1
    The "obscure workaround" _was_ only required in specific circumstances, see: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6202721 – Kamal Apr 27 '20 at 19:24
  • @Kamal The links you posted refers to Java 6 and earlier, – Venu Apr 28 '20 at 23:45
  • 1
    That's exactly the point, it was fixed in Java 8. According to the bug report, the "obscure workaround" (adding the extra ./ in the file name) was required after Java 1.4.2 and up to 6. I'm assuming in Java 7 too, otherwise it wouldn't be mentioned as fixed in Java 8. Setting /dev/urandom instead of /dev/random is still required though, if you want to use a non-blocking device. – Kamal Apr 30 '20 at 11:08
  • Is this fixed in OpenJDK 8 as well ? Or does this apply to Oracle 8 only. – souser Jul 08 '20 at 23:20
  • 2
    @souser it was fixed in openjdk 8 as well – Venu Jul 09 '20 at 07:19
  • 1
    this is not correct, today i am having this problem, then i used this then it got fixed,, so i don't think so it is fixed on java 8 – Mugeesh Husain Sep 24 '20 at 06:20