
Insecurities in the Linux /dev/random - e1ven
https://www.schneier.com/blog/archives/2013/10/insecurities_in.html
======
tptacek
This is an interesting paper that was discussed widely on Twitter a few months
back. It includes a very useful breakdown of the Linux kernel CSPRNG starting
on page 17. The attacks the paper describes start on page 22. The front part
of the paper is dominated by a discussion of the theoretical modeling of
CSPRNGs, in part because the theoretical foundations for CSPRNGs and their
interactions with applications are not well documented.

The most important bit of information you probably want to know about this
paper is that it is modeling the security of a CSPRNG when its entropy inputs
are entirely controlled by attackers. For instance, one of the attacks
involves tricking the entropy estimator into believing it's seeding itself
with high-quality random data when that data in fact has no entropy.

This is not a realistic attack scenario for the vast majority (maybe all) of
applications.

Having said that, the Linux kernel CSPRNG doesn't (as far as I know) have a
particularly well formalized design. There are good CSPRNG designs out there;
for instance, the BSDs use Yarrow, and Ferguson followed that design up with
Fortuna, which dispenses with the need for entropy estimators altogether.

~~~
XorNot
Wouldn't this in fact be completely unrealistic? If attackers have full
control of entropy inputs, they can just hook up a very high quality
randomness source, but record every single bit before it gets to /dev/random.

Of course, why bother with that if you have that kind of access?

------
tytso
So I'm the maintainer for Linux's /dev/random driver. I've only had a chance
to look at the paper very quickly, and I will at it more closely when I have
more time, but what the authors of this paper seem to be worried about is not
even close to the top of my list in terms of things I'm worried about.

First of all, the paper is incorrect in some minor details; the most
significant error is its (untrue) claim that we stop gathering entropy when
the entropy estimate for a given entropy pool is "full". Before July 2012, we
went into a trickle mode where we only took in 1 in 096 values. Since then,
the main way that we gather entropy, which is via add_interrupt_randomness(),
has no such limit. This means that we will continue to collect entropy even if
the input pool is apparently "full".

This is critical, because _secondly_ their hypothetical attacks presume
certain input distributions which have an incorrect entropy estimate --- that
is, either zero actual entropy but a high entropy estimate, or a high entropy,
but a low entropy estimate. There has been no attempt by the paper's authors
to determine whether the entropy gathered by Linux meets either of their
hypothetical models, and in fact in the "Linux Pseudorandom Number Generator
Revisited"[1], the analysis showed that our entropy estimator was actually
pretty good, given the real-life inputs that we are able to obtain from an
actual running Linux system.

[1] [http://eprint.iacr.org/2012/251.pdf](http://eprint.iacr.org/2012/251.pdf)

The main thing which I am much more worried about is that on various embedded
systems, which do not have a fine-grained clock, and which is reading from
flash which has a much more deterministic timing for their operations, is that
when userspace tries to generate long-term public keys immediately after the
machine is taken out of the box and plugged in, that there isn't a sufficient
amount of entropy, and since most userspace applications use /dev/urandom
since they don't want to block, that they end up with keys that aren't very
random. We had some really serious problems with this, which was written up in
the "Mining Your Ps and Qs: Detection of Widespread Weak Keys in Network
Devices"[2] paper, and the changes made in July 2012 were specifically
designed to address these worries.

[2]
[https://www.factorable.net/paper.html](https://www.factorable.net/paper.html)

However, it may be that on certain systems, in particular ARM and MIPS based
systems, where a long-term public key is generated very shortly after the
first power-on, that there's enough randomness that the techniques used in [2]
would not find any problems, but that might be not enough randomness to
prevent our friends in Fort Meade from being able to brute force guess the
possible public-private key pairs.

Speaking more generally, I'm a bit dubious about academic analysis which are
primarily worried about recovering from the exposure of the state of the
random pool. In practice, if the bad guy can grab the state of random pool,
they probably have enough privileged access that they can do much more
entertaining things, such as grabbing the user's passphrase or just grabbing
their long-term private key. Trying to preserve the amount of entropy in the
pool, and making sure that we can extract as much uncertainty from the system
as possible, are much higher priority things to worry about.

That's not to say that I might not make changes to /dev/random in reaction to
academic analysis; I've made changes in reaction to [2], and I have changes
queued for the next major kernel release up to make some changes to address
concerns raised in [1]. However, protection against artificially constructed
attacks is not the only thing which I am worried about. Things like making
sure we have adequate entropy collection on all platforms, especially embedded
ones, and adding some conservatism just in case SHA isn't a perfect random
function are some of the other things which I am trying to balance as we make
changes to /dev/random.

~~~
tptacek
Nit: the cold start entropy problem (specifically in the Linux kernel CSPRNG)
was published way before Heninger; Zvi Gutterman presented it at Black Hat in
2006. "P's and Q's" got a lot of publicity, but could some of that exposure
have been mitigated had earlier reports been acted on? (I seriously have no
idea and am just asking).

The term for the "academic analysis" of "recovering from exposure of state" is
"forward secrecy", and from what I can tell the whole of the crypto literature
that discusses CSPRNGs in any depth seems to be unified on the opinion that
forward secrecy is an important property for a CSPRNG to have.

(But that's a reaction to your comment, not your opinion of the paper, because
I agree that the attacks here don't seem very practical.)

What do you think of Ferguson's belief that entropy estimators are a flawed
design approach for CSPRNGs? FreeBSD uses Yarrow for this, which has two
benefits --- first, it loses the silly notion of a "urandom" that is somehow
marginally less secure than "random" but is in practice not actually less
secure, and second, it comes from a design that has a formal research track
record, that people can analyze from the paper and not solely by reversing
code.

(I sound snippy but am in fact thrilled that you took the time to comment, and
thank you).

~~~
tytso
Yes, I'm aware of the concept of forward secrecy, and the formalism around it.
Without intending to sound snippy myself, I think there is a tendency for
academicians (whose promotion/tenure prospects are directly related being able
to generate papers that get published in high impact journals) to be biased in
favor of those things for which formal models can be created. We saw that for
example in the academic focus on formal proof of correctness of programs,
which at this point is recognized as a blind alley, as opposed to a more
engineering approach of using tools like valgrind and lint and static program
analysis. So I am a bit unpersuaded regarding the academic focus on forward
secrecy. It's something that if we can add to a design, I'll certainly do it
--- and indeed there is a Yarrow-style "catastrophic reseeding" in the
/dev/random design.

We have been moving away from using entropy estimators in /dev/random,
actually. We still use it for certain entropy sources, most notably for the
keyboard and mouse inputs, where it is useful for filtering out event timings
caused by the user leaning on the key and triggering autorepeat. But these
days we have a "fast mix pool" (which is per-CPU) where we sample on every
single interrupt, and then down-mix from there to much larger entropy pool,
and the bulk of the entropy, especially on servers, comes from the fast mix
pool.

I tend to focus much more on engineering/social aspects; for example, the
fundamental cause of the failure found by the Mining Your P's and Q's paper
(as opposed to the hypothetical failures of things like the forward secrecy
papers), was people disabling the entropy collection in many/most device
drivers because they thought it was too slow for high speed devices, in
particular network devices. They made arguments that it was because an
adversary could monitor the packet arrival times on the Ethernet (which is not
true in a switched fabric anyway, and if the attacker is sitting at Fort
Meade, or even at AT&T's data center, they won't know about your local area
network), but that was just an excuse; the main reason was engineers who were
worried about performance.

So using a fancy "approved by academics" design which uses crypto hashing to
mix entropy into the mixing pools may be pointless, if downstream kernel
hackers disable the entropy collection "because it's too slow". We now have
something hard-wired into the main interrupt code path (it's now no longer
optional, so it can't be configured on or off on an individual device driver
basis), and I've gone through a lot of work to make it be extremely fast,
including using per-CPU pools, worrying about cache effects, etc. These are
concerns that I'm sure would never help a professor achieve tenure, but as a
practicing engineer, I've been painfully aware about how important these sorts
of concerns really are.

Don't get me wrong; I do read the papers from those academics who try to
analyze /dev/random, and I appreciate their attention. But I do come from a
someone different perspective than they do, and over the years I've learned
that it's not wise to blindly take the advice of every single bug report that
you get (and I consider papers to be simply formal bug reports :-) since
sometimes you can't satisfy every single user and every single bug report.

~~~
dlitz
Oh, cool! Have you considered making changes to the interface that's presented
to userspace? As a crypto library author, I have a few gripes about the
current interface:

1\. The distinction between /dev/random and /dev/urandom is silly. On a
machine that's been been collecting entropy for weeks, /dev/random will still
block after reading a few bytes. On the other hand, on an embedded device
that's just left the factory, /dev/urandom will happily return "random" bytes
that aren't. The result is that /dev/random is unusable for anyone except
cipherpunks, and /dev/urandom is unsafe on embedded devices.

2\. /dev/urandom is slow, so libraries (including mine) all end up shipping
their own PRNG implementations in userspace, where they're susceptible to
threading issues, having their entire state duplicated by fork(),
"//MD_Update(&m,buf,j)", etc. It's surprisingly difficult to do this correctly
in a user-space library, and I bet the NSA and others are having a lot of fun
at the expense of our users.

What I'd like is a single, fast, trustworthy /dev/?random device that is good
enough to obsolete user-space PRNGs entirely. This means it would have the
following properties:

1\. It blocks until the kernel decides that it can safely generate
cryptographically-strong random bytes (i.e. first boot), and never blocks
again unless something extraordinary happens (i.e. it's a VM guest that's just
been cloned, or something). The idea would be that it never produces output
that isn't cryptographically strong, but is otherwise reliable enough that
applications can behave as if it never blocks.

2\. It produces output so quickly that userspace programs never have an excuse
to use anything else. i.e. Its speed should be comparable to what you get
using AES-NI in counter mode (I know you don't like Fortuna's entropy pooling,
but its output-side PRNG is exactly what you'd want here.) Ideally, this could
be fast enough that developers wouldn't even need to distinguish between
"random numbers" and "cryptographically-strong random numbers"\---just use it
everywhere, even if you might otherwise use Mersenne Twister.

TL;DR - I want a faster, reliable, trust-inspiring /dev/?random that obsoletes
all user-space CSPRNGs and possibly all user-space PRNGs.

I've been tempted to write something like this myself, but from my casual
reading of the lkml archives, it hasn't been clear whether you were actually
interested in RNG patches like this. Are you?

~~~
tytso
Why do you need so much random numbers such that /dev/urandom is too slow for
you?

There are plenty of uses of randomness. Let's look at some of them:

1\. Monte Carlo Simulations

2\. Wiping disk files that might contain sensitive information.

3\. Padding in crypto applications

4\. Initialization Vectors (IV's)

5\. Session keys / D-H key agreement

6\. Long-term keys for users

7\. Country-level TLD keys for things like DNSSEC

These uses have been rank ordered roughly in order of cryptographic strength
that might required. Very often, I've found that people who are complaining
about the speed of /dev/urandom are using it for something that it wasn't
designed for; for example, "dd if=/dev/urandom of=/dev/hda" to wipe a disk.

And similarly, for people who insist that there is no good
difference/distinction between /dev/urandom and /dev/random, they are only
thinking of their use case, and/or they aren't considering that there might be
a difference between generating a long-term public key for GPG (which today
tends to use /dev/random for this purpose, and I think rightly so), and
generating a one-time session key when encrypting a message using GPG. Since
you only do the first once, a bit more inconvenience might be tolerated by the
user. (Today this takes about ten minutes on a laptop, and part of the reason
for this is that Chrome is positively profligate with how it uses randomness,
including a 32k read from /dev/urandom[!] at startup, and this is draining the
entropy available for /dev/random, which slows it down significantly. I have a
change pending upstream which time-limits the amount of entropy that can be
drawn from the input pool to the nonblocking pool to protect our entropy from
abusive users of /dev/urandom, and I have on my todo list tracking down some
chrome developers to figure out what the heck they are doing with all of their
demands on /dev/urandom.)

The reality is that strong random numbers is a precious resource, and you
can't use it willy-nilly. Furthermore, the strength of random numbers is a
continuum; it is not a binary "strong" vs. "not strong" distinction. I'm sure
it would be very convenient for userspace programmers to be able to assume
that randomness is always freely available, and that it only comes in two
flavors, "insecure" and "secure", but that's not the way the world works.

Even in the case of hardware random number generators, there are tradeoffs.
This is why future Intel processors will be making a distinction between
RDRAND (for which you can't assume that two 128 bit RDRAND outputs, when put
together, will give you 256 bits of entropy), and RDSEED (which does have this
guarantee). And of course, there is also the tradeoff between the auditability
of /dev/random and the non-auditability of something which is locked in a
complex piece of Silicon.

TL;DR. I'd like to have a Personal Gulfstream Jet, and enough money that it's
not a big deal to consider a $12 million dollar home in La Jolla to be
teardwon fodder. But sometimes reality intrudes on your dreams/fantasies....

~~~
tptacek
This is a great comment, but I disagree with it.

The hierarchy of secrets you've come up with sounds useful, but in practice:

* An attack based on entropy on a CSPRNG that ran months or even days ago, barring blatant flaws like zero cold start entropy, isn't realistic†. And, if you're paranoid about your "long term keys", generate them on a different machine than the one on which you serve up disk-wiping entropy. That's what you're supposed to do anyways. But I'm a little concerned that such a suggestion dignifies an unrealistic risk.

* Meanwhile, the notion that "lesser" secrets, like IV and padding, can deal with less randomness doesn't seem to bear empirical scrutiny. The attacks that have tended to matter against cryptosystems in the last few years have, with the exception of the P's and Q's zero-cold-start-entropy issue, not targeted long-term secrets, but rather have hinged on details like padding (random padding in the OAEP/PKCS#1 case, I guess; most crypto padding is deterministic).

* The mentality of "long term secrets" and "short term crypto parameters" that you laid out already missed a doozy: DSA and ECDSA nonces, which people who think like your comment did thought of as "undemanding", but for which it turns out that just being able to predict _a couple of bits_ of that parameter can get you with a few thousand samples all the way back to private keys.

I think you'd be better off, cryptographically and from a software design
perspective, with a single CSPRNG that was suitable for all cryptographic use
cases, and, if users are paranoid, have them tap a physically different CSPRNG
for their "long term keys" \--- which they need to do anyways on the
presumption that the systems that they use routinely are also probably owned
up.

Also, I have to again point out that the Linux CSPRNG design doesn't handle
_any_ of these cases well. Its /dev/random is unusable by demanding
applications in steady state, with the possible (terrible) workaround of
reimplementing CSPRNGs seeded from small amounts of /dev/random data in
userspace (and all the attendant flaws); its /dev/urandom is unsafe at cold
start. _Something 's_ gotta give in that design: it's doing extra work
internally and inflicting extra work on developers, all for a worse result
than FreeBSD.

† _Re: realism: it 's always easy to argue "attacks always get better, we
should account for every attack, realistic or not". But engineering is about
tradeoffs, and here the tradeoff Linux is making is to service an attack
unknown to the literature that is likely precluded by the basic design of a
modern refreshing CSPRNG, and doing so at the expense of protecting against
very realistic attacks that have been discovered in the wild; it doesn't help
that Linux (in general) seems to respond to that point by suggesting that
userland devs should have done a better job._

 _Oh, dubiously-informed CSPRNG opinions; I sure do have them._

~~~
tytso
It's true that many of the attacks (such as BEAST) rely on attacks related to
the IV. However, look at underlying mechanism of that attack; it requires that
the attacker be able to predict the entire IV (which it can do since it can
use the CBC residue from the previous packet). If the attacker can predict 64
out of the 128 bits of an IV used for AES, that's less of a disaster than if
the attacker can predict 64 out of the 128 bits for an AES key. So there is a
difference, although I might agree with you that relying on application
developers to understand these distinctions might be unrealistic.

You're right that for DSA nonces, even a partial failure of the RNG is a
disaster; to me, that's more of an indictment of DSA as being really extremely
fragile.

I agree that making /dev/urandom to be as secure as is possible, as quickly as
possible after a cold start, is a good thing, and indeed most of my efforts
have been focused in that area. I'm not convinced the FreeBSD approach is a
panacea, since that presumes FreeBSD's entropy estimator is sufficiently
accurate. And I'll note that even with the Fortuna design, which completely
gives up on the entropy estimator, it's still subject to the cold start
problem --- you just don't know when Fortuna has accumulated enough entropy
such that it is secure. In that regard, it's no better than Linux's
/dev/random approach.

I'm not opposed to some adding a cold-start block to /dev/urandom, and
ultimately, I might go there just because it's easier than making
recommendations that userspace wait until the last possible moment to lazily
generate keying materials. However, it's a bit of a bandaid, so I'm more
interested in trying to collect as much entropy as possible right after boot,
to narrow the window after a cold start.

FreeBSD's approach certainly won't help with the criticism leveled by the
"/dev/random is not robust" paper, since it assumes that fundamentally the
entropy estimator is broken. But if it's broken, then FreeBSD Yarrow will also
not be robust in the face of the cold start problem. So it's certainly not
going to help people who are going to kvetch about entropy estimators being
hopeless.

------
buo
From the abstract: "A pseudo-random number generator (PRNG) is a deterministic
algorithm that produces numbers whose distribution is indistinguishable from
uniform."

I think this is incorrect, since it would imply that a program that produces
the sequence 1,2,1,2,1,2,1.... is a PRNG.

~~~
mcherm
No, your sequence IS distinguishable from a uniform sequence. At least it is
if I understand what you mean by "...".

If you mean that it generates 1,2,1,2,1,2,1 and then after that generates a
mix of different values that include all possible values in approximately
equal frequency, then you may have a fairly good PRNG. If you mean that it
produces 1,2,1,2,1,2,1 and then after that it continues to alternate between 2
and 1, then this is easily distinguished from uniform.

~~~
pmelendez
>"No, your sequence IS distinguishable from a uniform sequence." No, it is not
distinguishable. The definition according to wikipedia: The _discrete uniform
distribution_ is a symmetric probability distribution whereby a finite number
of values are equally likely to be observed; every one of n values has equal
probability 1/n.

So the distribution is indeed uniform but it fails in being random.

~~~
buo
The point is that, in the context of the paper, you are supposed to group
consecutive sequence elements and find their distribution.

Consider the sequence 1,2,1,2,1,2,1.... When you take elements one at a time,
you have a uniform distribution, but the sequence is clearly not random.
However, when you take elements two at a time, you have; 12,12,12,12... In
this case, the distribution is not uniform, which indicates non-randomness.

The paper's definition implies that you're grouping the sequence elements like
this and, for all groupings, you find uniform distributions. This is of course
common knowledge to experts, and is made clear in the body of the paper.

~~~
betterunix
Actually, it is more general than that. _Any_ polynomial time algorithm that
takes as input a sequence and which has access to a unbounded source of
uniform random numbers (i.e. a "true" random number generator) should output a
_1_ when given a uniform random sequence with "nearly" the same probability as
when given the output of a PRNG ("nearly" here means within a negligible
amount e.g. the algorithm might just try to guess the PRNG seed). In other
words,

    
    
      Pr[A(prng(seed, n))] - Pr[A(uniform(n))] < 1/negl(n)
    

Where for all polynomial functions _p(n)_ , there exists an _N_ such that for
all _n > N_, _1 /p(n) > 1/negl(n)_; _uniform(n)_ is an _n_ element long
uniform random sequence, and _prng(seed, n)_ is the first _n_ elements of the
output of the PRNG for a (uniform) random seed. This is a common definition in
cryptography and a variant is mentioned further down in the paper in Section
2.

