15

I have read plenty about the distinction between /dev/random and /dev/urandom. I understand that the prevailing advice is to use /dev/urandom. The explanation - that 256 bits of 'proper' randomness is all you need for almost any cryptographic application - makes sense to me.
A couple of helpful sources:
- https://pthree.org/2014/07/21/the-linux-random-number-generator/
- http://www.2uo.de/myths-about-urandom/

The state of a virtual machine (VM) or live CD right after first boot is sometimes identified as an unusual edge case to this guideline, as /dev/urandom may not have been properly seeded.

In context of all the other possible uses of /dev/urandom, I can see that this is an edge case. However, given that you are using a VM for the first time, it seems plausible that one of the first things you might want to do is call on /dev/urandom, e.g. to generate SSH keys.

So, if you assume the worst about your VM (e.g. that it was cloned, or that after a reboot the newly seeded randoms are no good), what could you do to make sure that /dev/urandom is good to go?

The laziest thing to do seems to be to let the VM just sit running for a little while, until random events have re-seeded the input pool. The awkward part is that an idle VM does this quite slowly.

I wanted to test how long it takes for this to happen, and I tried to do so as follows:

This command pulls 32 bytes/256 bits from the pool (and displays in hex)
head -c 32 </dev/random | xxd -p

Once the input pool's entropy count has gone to minimal levels (visible with cat /proc/sys/kernel/random/entropy_avail), the command above will block until new random events enter the input pool. That suggests to me that if we run the above command repeatedly, time it, and write the results to a file called randomtest it will indicate how long it takes to refill the input pool.

I tried writing a one-line command which does so:
for n in {1..10}; do (/usr/bin/time -f "%E Real" sh -c 'printf "%-10s" $(head -c 32 </dev/random | xxd -p)' 2>&1) >> randomtest; done

More readably:

for n in {1..10};
do (/usr/bin/time -f "%E Real" sh -c \
    'printf "%-10s" $(head -c 32 </dev/random | xxd -p)' 2>&1) \
    >> randomtest; 
done

I know that starting processes (even the cat command above) draws down the input pool, so this will provide a conservative estimate. For what it's worth, I let the above command run on an inactive VM, and the time between fresh 32-byte sequences was a steady 15-20 minutes each.

My questions:

  • Does the output of this command successfully test what I think it does?
  • Is there a much simpler way to test the same thing?
  • Is there a different/better 'lazy' way to refresh the input pool and re-seed /dev/urandom than letting the VM sit idle?
6

I'm not an expert on the nuances between urandom and random but based on your description it would seem your test is correctly approximating the time to refill the input pool. I'm not aware of any tools that do this kind of testing.

There is a better way to reseed urandom to prevent stale state affecting the quality of the random data though, and that's to write random data in urandom.

This can be done on cloud providers using cloud-init and on VMs at boot time by running some instance metadata through a hash function and writing it to urandom. This could also be part of a configuration management solution using Chef, Ansible, Puppet, etc and pull a random seed from your local machine.

Note that this doesn't increase the overall entropy count, it just sets a fresher seed. From man 4 random

Writing to /dev/random or /dev/urandom will update the entropy pool with the data written, but this will not result in a higher entropy count. This means that it will impact the contents read from both files, but it will not make reads from /dev/random faster.

  • Thanks for the pointer to cloud-init. Could you clarify what you meant by running instance metadata through a hash function and writing to urandom? [I assume this means you need a random input to the hash function, but isn't that the very thing that's lacking?] – SauceCode Mar 27 '16 at 22:31
  • In my view, the enemy is known state. In a low entropy system with known state a hash function's output of known input might be able to be determined. Instance metadata should contain information like an externally generated random instance id, a time stamp, a base image id, etc. Because this data isn't available before boot time and difficult to predict, the theory is that is should provide sufficient hashing fodder to avoid known state. Here's a good write up about using cloud instance metadata to seed urandom: blog.dustinkirkland.com/2012/10/… – Matt Surabian Mar 29 '16 at 0:00
1

If you do not have a hardware rng you can give vm's entropy by running haveged as a daemon on the host.

I use it in my Alpine Linux install scripts to provide enough entropy to create a luks filesystem on a brand new installation.

0

This does not answer any of your question. It merely addresses some of your statements.

I have read plenty about the distinction between /dev/random and /dev/urandom. I understand that the prevailing advice is to use /dev/urandom...

/dev/random should not be used. According to Theodore Ts'o on the Linux Kernel Crypto mailing list, /dev/random has been considered deprecated for about a decade. From Re: [RFC PATCH v12 3/4] Linux Random Number Generator:

Practically no one uses /dev/random. It's essentially a deprecated interface; the primary interfaces that have been recommended for well over a decade is /dev/urandom, and now, getrandom(2). We only need 384 bits of randomness every 5 minutes to reseed the CRNG, and that's plenty even given the very conservative entropy estimation currently being used.

This was deliberate. I care a lot more that we get the initial boot-time CRNG initialization right on ARM32 and MIPS embedded devices, far, far, more than I care about making plenty of information-theoretic entropy available at /dev/random on an x86 system...


The state of a virtual machine (VM) or live CD right after first boot is sometimes identified as an unusual edge case to this guideline, as /dev/urandom may not have been properly seeded...

Modern Linux operating systems use hardware based generator to collect some entropy. For example, on x86, rdrand (or is it rdseed) is used for some bits. The generator is not the only source, but it helps at a crucial time.

systemd has kind of been a problem for a long time. It extracts entropy before the /dev/urandom is ready. And attempting to block /dev/urandom results in a hung system because systemd hangs. Also see why getrandom blocking does not work with /dev/urandom and Issue 4167, systemd reads from urandom before initialization.

You might also want to read some of Stephan Mueller's analysis on the Linux RNGs. He's a Linux Crypto regular, too.


... if you assume the worst about your VM (e.g. that it was cloned, or that after a reboot the newly seeded randoms are no good), what could you do to make sure that /dev/urandom is good to go?

These are called rollback attacks.

The only remediations I am aware of is hedging. Recall you should reseed the prng before extracting entropy when available. When hedging, you use the other party's entropy and mix it with your own. So, say, in TLS, you you take the other party's random and mix it into your prng. Since the attacker does not control the other party you will produce a different stream even if the vm is reset.

Also see:


How long to re-seed /dev/urandom in a virtual machine?

Install an entropy gathering daemon like haveged. It continuously gathers entropy and will handle things for you.

An entropy gathering daemon is a must on Debian. Every version of Debian I have tested - from ARM through MIPS and x86 - suffers entropy depletion. And that includes derivatives like Armbian and Ubuntu. You must install the rng-tools package because it is not installed by default.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.