Hello. Sorry to be the bearer of bad news, but this implementation is
broken in a subtle but important way:

When adding the data returned from rdrand to the system entropy pool,
using the RNDADDENTROPY ioctl on /dev/random, it sets the entropy count
equal to the buffer size. In other words, claiming that its data is 100%
entropy.

This is clearly wrong, as the rdrand instruction only gives access to a
deterministic pseudo-random number generator. It's seeded by a built-in
hardware source of true entropy, but the rdrand instruction doesn't give
access to the output of the entropy source, only to the output of PRNG.

The PRNG is reseeded often from this entropy source, so the output
contains plenty of entropy, but nowhere near 100% (or even 1%). Intel
states that you are guaranteed a reseed if you invoke the 64-bit rdrand
instruction more than 1022 times (http://software.intel.com/en-
us/articles/intel-digital-random-number-generator-drng-software-
implementation-guide). A seed value is 256 bits.  So in the worst case,
we are providing 256 bits of entropy per almost 8KB of rdrand output.
The problem is, when we pass it to the kernel, we claim that we provided
8KB of entropy:

(from rngd_linux.c):
    entropy.ent_count = size * 8;
    entropy.size = size;

The solution would be simple: per each ioctl(), make sure we've called
rdrand64 more than 1022 times, and set the ent_count to 256.

This can actually be done using command line options in the "official"
(git://git.kernel.org/pub/scm/utils/kernel/rng-tools/rng-tools.git) rng-
tools, but not the version in this Ubuntu package. They have a command
line option -H that lets you specify the "entropy per bit" as a floating
point, which we are missing. In conjunction with the random-step option
-s, the correct behavior can be coaxed out of it by using -H
0.0039062500 -s 8192. Pretty klugy, though.

I also found GPL code (I don't know the author) at
https://github.com/bjencks/rngd-rdrand which cleanly and correctly does
the right thing. It only supports rgrand, no other sources, so the whole
thing is about 100 lines of C. It isn't productionized (doesn't fork
into the background, doesn't have an init.d script, etc.) but I'm using
it on my system almost as-is, and it is still fast enough to generate
2048-bit GPG key pairs nearly instantaneously on my system. The only
change I made was to bump the number of rdrands per ioctl to 1024 from
1022, as the Intel docs linked above say *more* than 1022, not just
1022.

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/1084378

Title:
  [Feature] RDRAND enabling for rngd

To manage notifications about this bug go to:
https://bugs.launchpad.net/intel/+bug/1084378/+subscriptions

-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to