Working ONLY with /dev/random in Java
Asked Answered
S

1

16

I have a HRNG that feeds /dev/random in Debian Wheezy. It's fast, so blocking will not be a problem. Now, in my Java code I want to ensure that I use the entropy in /dev/random and ONLY that entropy. I have no interest in using anything out of /dev/urandom.

I want to force Java's SecureRandom to ONLY get entropy from /dev/random. As I understand the implementation at present, it uses /dev/urandom when getBytes() is called, but /dev/random when generateSeed() is called. I'm at a loss understanding why.

As I understand it, the only reason to read from /dev/urandom is if you favour speed over security. I want the highest quality entropy possible. /dev/urandom will just not do.

So, how do I force SecureRandom to ONLY use /dev/random (supplied by a HRNG) and never touch anything from an inferior PRNG (like /dev/urandom)?

Thanks a mil.

Symbolize answered 17/5, 2014 at 16:28 Comment(11)
I added a code example below, please test it and see if it works.Repose
Maybe alias urandom to random?Fledge
@HotLicks: So that the whole process can't read from /dev/urandom anymore, even if it wants?Repose
@StackOverflowException - That was just a suggestion, intended to maybe trigger a different approach to the problem, not be a solution per se.Fledge
@HotLicks: Sure, my comment was not meant to discourage that solution. The easiest solutions can be the best, so if it works it's a good solution. The problem that hides in simply aliasing it is that we do not know if /dev/urandom shall not be used at all, maybe a combination is needed...Repose
@StackOverflowException - For the case when you don't control the code, calling mknod /dev/urandom 1 8 would certainly suffice to ensure that the HPRNG is always used. And when you do control the code, you get to choose which one is easiest!Aether
It's worth pointing out that if your HRNG is truly fast enough that it won't ever block, then it makes absolutely no difference if you read from /dev/random or /dev/urandom, since that's the only difference: 2uo.de/myths-about-urandomLeptophyllous
@BrendanLong If that were true, then why would /dev/random exist at all? There is a difference. /dev/urandom reuses the internal pool to produce more pseudo-random bits. This means that the output may have less entropy. In the case of a headless server, the reuse of the internal pool is more frequent, so the output is less entropic, so my keys are less secure. /dev/random blocks for fresh entropy. This blocking is a problem, but I don't believe in taking the easy and less secure way out (/dev/urandom). Instead I put a HRNG in place to ensure a constant supply of quality entropy.Symbolize
@Symbolize Read the article I linked to, and especially take a look at this picture. /dev/random and /dev/urandom work the same way, except that /dev/random blocks in some cases. You said that your HRNG is fast enough that /dev/random will never block, and if that's true, then /dev/random and /dev/urandom will be exactly the same. Beyond that, "entropy" is poorly defined and not important.Leptophyllous
@BrendanLong Correct me if I'm wrong, but there are 3 pools, a source, and then one for /dev/urandom and one for /dev/random. If I write data from my HRNG into /dev/random, how does that affect /dev/urandom? It's a different pool. As for entropy not being well defined, honestly, I'm not sure what you mean - I consider it clearly defined. As for not important, again, I'm not sure what you mean, as it is the backbone of any cryptographically secure system.Symbolize
@Symbolize You should really just read the article I linked to. They've already responded to everything you've said.Leptophyllous
R
21

This answer assumes you know what you're doing. In other cases, use of /dev/random should be minimized.

/dev/random acts like a normal file, therefore any program which can read any file can read from /dev/random. You probably know that cat /dev/random outputs random data directly from it, and if it does this fast enough, you might in fact want to use it. So, if everything else fails, you'll be always be able to directly read that file...

So, if you look at the source of SecureRandom, you discover that it uses SecureRandomSpi for the actual work. It turns out that NativePRNG.Blocking does what you want:

A NativePRNG-like class that uses /dev/random for both seed and random material. Note that it does not respect the egd properties, since we have no way of knowing what those qualities are. This is very similar to the outer NativePRNG class, minimizing any breakage to the serialization of the existing implementation. Since: 1.8

The problem might be the Since 1.8, which leaves you with the possibility to backport it to earlier platforms, if you can't use Java 8 yet. The sourcecode is available after all.

So, now let's put this in code:

We have to select the specific implementation to use. To find the exact name, we output all available services with the following line:

for (Provider p: Security.getProviders()) p.getServices().forEach(System.out::println);

We then search for Native in there, and we find the folllowing entry:

SUN: SecureRandom.NativePRNGBlocking -> sun.security.provider.NativePRNG$Blocking

This means we can instantiate the SecureRandom object like below to do what you want:

SecureRandom sr = SecureRandom.getInstance("NativePRNGBlocking", "SUN");

A simple test

byte[] b = new byte[10000];
sr.nextBytes(b);
System.out.println(Arrays.toString(b));

takes ages, I had to lower the amount of read bytes. If it works for you, congratulations, you're reading from /dev/random!

Notice though that this class is in the sun.security.provider package, which is not guaranteed to be available everywhere. For example, it will probably not work on Android. If this fine, then this solution will work, otherwise you should just directly read it as a file.

Don't read from /dev/random on Android. Please.

Repose answered 17/5, 2014 at 16:54 Comment(4)
@Symbolize Nvm, I do the upvote for you :D By the way, what's the problem with Java 8 you mentioned? Did they change SecureRandom?Cheryllches
@AlexeyMalev: They seem to have added the NativePRNG.Blocking in Java 8. Many people aren't able to use Java 8 yet, including all Android developers...Repose
@user3335193: You can't upvote, but if you want, you can accept the answer by clicking the green check-mark underneath the voting interface. (As the question-asker, only you have that mark.) This gives +15 to the answerer, and +2 to you, and informs the community that your problem is solved. Note that you can only accept one answer per question -- accepting one answer will "unaccept" any others -- so it should be the answer you find most helpful. Therefore, you might want to wait a while before accepting, to see if you get an even-more-helpful answer. (Totally up to you.)Landscapist
@ruakh: Because of the upvotes on this question, he can upvote now, as that privilige only requires a reputation of 15, but thanks for writing that paragraph. :)Repose

© 2022 - 2024 — McMap. All rights reserved.