Update #6: JEP 123: SecureRandom Draft and Implementation.

Brad Wetmore bradford.wetmore at oracle.com
Wed Apr 10 16:28:34 PDT 2013

Fixed some stupidness in the tests.


Also, ignore the make/sun/splashscreen change.  That will be fixed 
elsewhere, but I needed it to be able to build using the old system.


On 4/10/2013 3:07 PM, Brad Wetmore wrote:
> Hi Florian,
>  > I wonder if this change to src/share/lib/security/java.security-linux
>  >
>  > -securerandom.source=file:/dev/urandom
>  > +securerandom.source=file:/dev/random
>  >
>  > causes the return of the blocking behavior.
> Welcome to my "can of worms." [1]  I hope everything I've said below is
> correct, and haven't made any typos!
>  >  In the past, I saw
>  > /dev/random-related blocking during server start-up because too many
>  > SecureRandom instances needed seeding.  If I follow the code
>  > correctly,
> If you came to this code fresh and understood it all in 7 hours, I would
> either give you a medal, or hand in my badge.  :)  It's really twisted
> stuff.
>  > seeding of non-strong generators now uses /dev/random again, which is
>  > subject to blocking.
> Given the long history of the JDK and concerns about backwards
> compatibility, our SecureRandom implementations have become *REALLY*
> hard to understand.  Trying to make sense of all this, and now cleaning
> it up, was actually more than 1/2 of the project.  It took me a couple
> weeks of intense code scrutiny/archeology, and then needed to write a
> wiki page just to keep my head wrapped around it.  Likely the most
> confusing issue I've ever worked on.
> In a nutshell, the current implementation of SHA1PRNG does indeed read
> from /dev/random while seeding itself and supplying bytes via
> generateSeed(), which is in opposition to the documented behavior of the
> security properties:  Remember the infamous "file:/dev/./urandom"
> workaround for SHA1PRNG? [2]  (sigh...)
> I'll try to simplify as much as I can.  I'll be including parts of this
> for the JDK 8 Oracle's Provider Impl page.
> In the current environment, here's our current list of providers, in
> default preference order.
> Solaris:
> Linux/Mac:
> Windows:
> As you probably know, "new SecureRandom()" obtains the first
> implementation in the list, unless you call
> "SecureRandom.getInstance("alg") or SecureRandom.getInstance("alg",
> "provider"), which gets a specific algorithm, either most preferred
> version or by a specific provider, respectively.
> The securerandom.source/java.security.egd currently only affects
> SHA1PRNG, but there's a slight wrinkle in that certain property values
> promote NativePRNG ahead of SHA1PRNG in the list of algorithms in the
> SUN provider.  More on this later.
> Current behavior:
> =================
> NativePRNG:
> -----------
> does not use securerandom.source/java.security.egd at all
> engineGenerateSeed: always reads from /dev/random
> engineNextBytes:    always reads from /dev/urandom
> ---------
> Since this is a real PRNG [3], SHA1PRNG requires a very strong seed
> (initial) value, as strong as possible.  If not initially seeded by the
> user via setSeed, SHA1PRNG will call SeedGenerator.getSystemEntropy +
> SeedGenerator.generateSeed() to generate a strong seed for itself.
> There are three seed generators which have SeedGenerator as their parent:
>      ThreadedSeedGenerator was the original Seeder which uses
>      system load to generate seed values, and is only used as a
>      last resort.  (SLOW!)
>      URLSeedGenerator takes a URL and reads from it.
>      NativeSeedGenerator uses /dev/random.
> When the SeedGenerator class initializes, if the properties
> (securerandom.source/java.security.egd) resolve to either the exact
> strings "file:/dev/random" or "file:/dev/urandom", it will use
> NativeSeedGenerator (/dev/random).  (Yeah, try explaining that to
> customers!)  If the properties resolve to any other URL, then we use
> URLSeedGenerator with that URL.  Note, this is why the infamous
> workaround "file:///dev/urandom" or "file:/dev/./urandom" works.  [2] As
> someone once said, this has got to be the most confusing workaround in
> the history of the JDK.  I would agree!  :)  If neither SeedGenerator is
> available, then we use ThreadedSeedGenerator as the last resort.
> Once seeded, then later calls to this SHA1PRNG SecureRandom instance are:
> engineGenerateSeed: always reads from SeedGenerator
> engineNextBytes:    Number generation using the current state as
>                      input into SHA1.
> So even though the EGD properties point to file:/dev/urandom, it's not
> correct when it comes to the seeder.
> Back in JDK 5, adding NativePRNG was the "workaround" for this problem.
> When setting up the default order of implementations in the SUN
> provider, if the properties URL is "file:/dev/urandom", then NativePRNG
> becomes the most preferred provider (over SHA1PRNG).  So for those Linux
> implementations which just asked for the "most preferred" (i.e. new
> SecureRandom()), they get an instance of NativePRNG which uses
> /dev/urandom for nextBytes.  (Note well:
> NativeSeedGenerator.generateSeed() still reads from /dev/random).
> So since you're not seeding a SHA1PRNG, using NativePRNG.nextBytes()
> makes it appear as though there is no more stalling, as long as you only
> call nextBytes() and not generateSeed().  But if you specifically asked
> for SHA1PRNG (which a lot of customers had baked into their code), you
> still go through the above, and will stall when SHA1PRNG tried to seed
> itself.
> (Again, try to explain this to customers.  We've had many escalations
> over the years!)
> PKCS11/Windows-PRNG:
> --------------------
> Didn't touch.  Their behavior doesn't allow have the concept of a EGD.
> New Behavior:
> =============
> So, what do my change do?
> .  Corrects the java.security files to reflect the new implementation,
> and corrects vagueness/long-standing errors.  In particular, the
> security property default becomes "file:/dev/random" which matches the
> old AND new implementations, which is what triggered this long discussion!
> .  SUN provider:  If the properties are *EITHER* "file:/dev/random" or
> "file:/dev/urandom", then it promotes NativePRNG ahead of SHA1PRNG in
> the list of preferred impls.  If it's not one of those, then SHA1PRNG is
> preferred over NativePRNG.
> .  NativePRNG:  Now respects the seeder properties.  If the property
> isn't "file:/" or doesn't exist, we'll fall back to /dev/random.
> .  Adds blocking and nonblocking variants of NativePRNG:
> NativePRNGBlocking/NativePRNGJNonBlocking.  The
> generateSeed()/nextBytes() methods both use /dev/random or /dev/urandom,
> respectively.
> .  NativeSeedGenerator:  essentially, this becomes the same as a
> URLSeedGenerator.  Instead of only using "/dev/random", it will the
> specified value of "file:/dev/random" or "file:/dev/urandom"
> .  Adds SecureRandom.getStrongSecureRandom.  Uses a security property to
> specify the strongest impl(s) on this system.  See the API for more
> details.
> .  Minor style cleanups
> I hope this is clear.
> Brad
> [1] https://www.google.com/search?q=define%3A+can+of+worms
> [2]
> http://security.stackexchange.com/questions/14386/what-do-i-need-to-configure-to-make-sure-my-software-uses-dev-urandom
> [3] http://en.wikipedia.org/wiki/Pseudorandom_number_generator

More information about the security-dev mailing list