unsigned char x[xbytes];
randombytes(x,xbytes);
Link with `-lrandombytes`.
### DESCRIPTION
`randombytes` sets `x[0]`, `x[1]`, ..., `x[xbytes-1]` to random bytes of
data.
Randomness APIs vary in three major ways. `randombytes` is designed in
each way to simplify callers:
* Like `RAND_bytes`, `randombytes` automatically generates separate
randomness for any number of bytes in any number of calls in any
number of threads in any number of programs. For comparison, some
randomness APIs (e.g., `random`) recycle randomness from one program
to another unless the program does extra work to set a separate
"seed", and can recycle randomness across multiple threads unless the
program does further work.
* Like `getrandom` and `getentropy` and `RAND_bytes`, `randombytes` aims
for the stringent goal of ensuring that no feasible computation will
ever be able to tell the difference between the output bytes and true
randomness. The caller can treat each returned byte as the result of 8
fresh coin flips. For comparison, some randomness APIs (e.g.,
`random`) do not aim for this goal and do not view detectable patterns
as a bug, as long as _most_ applications do not notice the patterns.
* Like `random`, `randombytes` always succeeds. Any necessary resources
(e.g., opening a file descriptor for `/dev/urandom`, on systems that
need this) are allocated at program startup, rather than being
deferred until the first `randombytes` call; also, dynamic failure
cases such as EINTR are handled inside `randombytes`. For comparison,
some randomness APIs (e.g., `getrandom` and `getentropy` and
`RAND_bytes`) can return error codes to be handled by the caller.
There are some programs that try to close all file descriptors. These
programs must limit their library use to libraries that promise not to
keep file descriptors open. In particular, these programs must not use
`randombytes` (which keeps a file descriptor open on some systems) or
other libraries calling `randombytes`.
### LINK DETAILS
Currently `-lrandombytes` is a frontend symbolic link to either
`-lrandombytes-kernel` or `-lrandombytes-openssl` as a backend library.
To simplify system-wide replacement of the backend library, typical
applications should dynamically link to `-lrandombytes` rather than to
`-lrandombytes-kernel` or `-lrandombytes-openssl`.
Applications that link statically to `-lrandombytes` also need
`-lcrypto` if `-lrandombytes` is `-lrandombytes-openssl`.
Currently `randombytes` is a macro, where the function actually linked
is `randombytes_internal_void_voidstar_longlong`.
### HISTORY
The `randombytes` API was introduced in 2008 as part of the
[SUPERCOP](https://bench.cr.yp.to)
benchmarking framework for cryptographic software.
Similar previous APIs include `RAND_bytes` and `arc4random_buf`, but
`RAND_bytes` was allowed to return failures and `arc4random_buf` was
using the broken RC4 stream cipher.
### SEE ALSO
**getrandom**(2), **getentropy**(2), **rand**(3), **random**(3),
**arc4random**(3), **urandom**(4)
librandombytes-20240318/doc/download.md 0000644 0000000 0000000 00000002377 14575707635 016425 0 ustar root root To download and unpack the latest version of librandombytes:
wget -m https://randombytes.cr.yp.to/librandombytes-latest-version.txt
version=$(cat randombytes.cr.yp.to/librandombytes-latest-version.txt)
wget -m https://randombytes.cr.yp.to/librandombytes-$version.tar.gz
tar -xzf randombytes.cr.yp.to/librandombytes-$version.tar.gz
cd librandombytes-$version
Then [install](install.html).
### Archives and changelog (reverse chronological)
[`librandombytes-20240318.tar.gz`](librandombytes-20240318.tar.gz) [browse](librandombytes-20240318.html)
More work on port to MacOS X, handling differences in shared-library naming.
Add `randombytes-info` manual page.
[`librandombytes-20230919.tar.gz`](librandombytes-20230919.tar.gz) [browse](librandombytes-20230919.html)
Port to MacOS X, fixing use of `getentropy`.
Thanks to Jan Mojzis.
[`librandombytes-20230905.tar.gz`](librandombytes-20230905.tar.gz) [browse](librandombytes-20230905.html)
Split [`license.md`](license.html) out of [`readme.md`](index.html),
and add further SPDX options.
Tweak CSS for better legibility.
Copy various `./configure` improvements from libmceliece and lib25519.
[`librandombytes-20230126.tar.gz`](librandombytes-20230126.tar.gz) [browse](librandombytes-20230126.html)
librandombytes-20240318/doc/html/ 0000755 0000000 0000000 00000000000 14575707635 015227 5 ustar root root librandombytes-20240318/doc/html/api.html 0000444 0000000 0000000 00000013721 14575707635 016670 0 ustar root root
librandombytes: API
librandombytes
NAME
randombytes - fill a buffer with random data
SYNOPSIS
#include <randombytes.h>
unsigned char x[xbytes];
randombytes(x,xbytes);
Link with -lrandombytes
.
DESCRIPTION
randombytes
sets x[0]
, x[1]
, ..., x[xbytes-1]
to random bytes of
data.
Randomness APIs vary in three major ways. randombytes
is designed in
each way to simplify callers:
-
Like RAND_bytes
, randombytes
automatically generates separate
randomness for any number of bytes in any number of calls in any
number of threads in any number of programs. For comparison, some
randomness APIs (e.g., random
) recycle randomness from one program
to another unless the program does extra work to set a separate
"seed", and can recycle randomness across multiple threads unless the
program does further work.
-
Like getrandom
and getentropy
and RAND_bytes
, randombytes
aims
for the stringent goal of ensuring that no feasible computation will
ever be able to tell the difference between the output bytes and true
randomness. The caller can treat each returned byte as the result of 8
fresh coin flips. For comparison, some randomness APIs (e.g.,
random
) do not aim for this goal and do not view detectable patterns
as a bug, as long as most applications do not notice the patterns.
-
Like random
, randombytes
always succeeds. Any necessary resources
(e.g., opening a file descriptor for /dev/urandom
, on systems that
need this) are allocated at program startup, rather than being
deferred until the first randombytes
call; also, dynamic failure
cases such as EINTR are handled inside randombytes
. For comparison,
some randomness APIs (e.g., getrandom
and getentropy
and
RAND_bytes
) can return error codes to be handled by the caller.
There are some programs that try to close all file descriptors. These
programs must limit their library use to libraries that promise not to
keep file descriptors open. In particular, these programs must not use
randombytes
(which keeps a file descriptor open on some systems) or
other libraries calling randombytes
.
LINK DETAILS
Currently -lrandombytes
is a frontend symbolic link to either
-lrandombytes-kernel
or -lrandombytes-openssl
as a backend library.
To simplify system-wide replacement of the backend library, typical
applications should dynamically link to -lrandombytes
rather than to
-lrandombytes-kernel
or -lrandombytes-openssl
.
Applications that link statically to -lrandombytes
also need
-lcrypto
if -lrandombytes
is -lrandombytes-openssl
.
Currently randombytes
is a macro, where the function actually linked
is randombytes_internal_void_voidstar_longlong
.
HISTORY
The randombytes
API was introduced in 2008 as part of the
SUPERCOP
benchmarking framework for cryptographic software.
Similar previous APIs include RAND_bytes
and arc4random_buf
, but
RAND_bytes
was allowed to return failures and arc4random_buf
was
using the broken RC4 stream cipher.
SEE ALSO
getrandom(2), getentropy(2), rand(3), random(3),
arc4random(3), urandom(4)
Version:
This is version 2023.09.04 of the "API" web page.
librandombytes-20240318/doc/html/download.html 0000444 0000000 0000000 00000007334 14575707635 017731 0 ustar root root
librandombytes: Download
librandombytes
To download and unpack the latest version of librandombytes:
wget -m https://randombytes.cr.yp.to/librandombytes-latest-version.txt
version=$(cat randombytes.cr.yp.to/librandombytes-latest-version.txt)
wget -m https://randombytes.cr.yp.to/librandombytes-$version.tar.gz
tar -xzf randombytes.cr.yp.to/librandombytes-$version.tar.gz
cd librandombytes-$version
Then install.
Archives and changelog (reverse chronological)
librandombytes-20240318.tar.gz
browse
More work on port to MacOS X, handling differences in shared-library naming.
Add randombytes-info
manual page.
librandombytes-20230919.tar.gz
browse
Port to MacOS X, fixing use of getentropy
.
Thanks to Jan Mojzis.
librandombytes-20230905.tar.gz
browse
Split license.md
out of readme.md
,
and add further SPDX options.
Tweak CSS for better legibility.
Copy various ./configure
improvements from libmceliece and lib25519.
librandombytes-20230126.tar.gz
browse
Version:
This is version 2024.03.18 of the "Download" web page.
librandombytes-20240318/doc/html/index.html 0000444 0000000 0000000 00000013721 14575707635 017226 0 ustar root root
librandombytes: Intro
librandombytes
librandombytes provides a simple API for applications generating fresh
randomness: include <randombytes.h>
, call randombytes(x,xbytes)
whenever desired to generate fresh random bytes x[0]
, x[1]
, ...,
x[xbytes-1]
, and link with -lrandombytes
.
Random bytes are often used directly in applications. Random bytes are
also the foundation of more complicated random objects, such as random
integers in a limited interval, random floating-point numbers from a
(nearly) normal distribution, and random keys used in public-key
cryptosystems. librandombytes is dedicated to obtaining fresh random
bytes in the first place, and leaves it to higher-level libraries to
convert those bytes into other types of random objects.
librandombytes aims for the following stringent randomness goal: no
feasible computation will ever be able to tell the difference between
the output bytes and true randomness (independent uniformly distributed
random bytes). This makes the randombytes()
output suitable for use
in applications ranging from simulations to cryptography.
Most alternative sources of randomness (such as rand()
and random()
in C, and mt19937_64
in C++) consider detectable deviations from true
randomness to be acceptable as long as most applications do not notice
the deviations. These sources are not permitted inside librandombytes;
the randombytes()
caller is entitled to expect that the output comes
from sources that are designed for the right goal.
Internally, librandombytes is an abstraction layer for a choice of two
libraries, where each library provides the same randombytes
interface
but the libraries choose two different sources of randomness:
-
librandombytes-kernel
reads random bytes provided by the OS kernel
via mechanisms such as getrandom()
. These mechanisms are typically
advertised as providing RNG security features that are harder to
provide in user space, such as hypervisor integration.
-
librandombytes-openssl
uses OpenSSL's RAND_bytes
to generate
random bytes. This mechanism is typically advertised as providing
speed that is difficult to achieve without a per-process RNG.
The idea is that the OS can install librandombytes-kernel
by default,
but the sysadmin can install librandombytes-openssl
to transparently
switch all of the randombytes()
applications to RAND_bytes
(for
example, via Debian's /etc/alternatives
mechanism) if profiling
shows that this switch is important for overall system performance.
Making this choice centrally means that applications are free to simply
call randombytes()
-
without worrying about evaluating performance,
-
without worrying about how to balance performance concerns with
competing concerns, and
-
without worrying that these performance evaluations will be rendered
obsolete by speed improvements: for example, by
ongoing work to accelerate
getrandom()
, or by the increasing deployment of
fast-key-erasure RNGs.
Another virtue of having a randombytes()
abstraction layer is that
test frameworks can substitute a deterministic seeded randombytes()
providing known pseudorandom bytes for reproducible tests. Of course,
the randombytes()
provided by these test frameworks must be kept
separate from the fresh randombytes()
used for deployment.
Version:
This is version 2023.09.04 of the "Intro" web page.
librandombytes-20240318/doc/html/install.html 0000444 0000000 0000000 00000013313 14575707635 017562 0 ustar root root
librandombytes: Install
librandombytes
Prerequisites: python3
; gcc
and/or clang
; OpenSSL. Currently
tested only under Linux, but porting to other systems shouldn't be
difficult.
For sysadmins
To install in /usr/local/{include,lib,bin}
:
./configure && make -j8 install
If you're running an old Linux system and see that the randombytes-info
output says randombytes source kernel-devurandom
(this will happen on
Linux kernels before 3.17), add the lines
dd count=1 bs=64 if=/dev/random of=/dev/urandom status=none \
&& findmnt -t tmpfs -T /var/run >/dev/null \
&& touch /var/run/urandom-ready &
to your boot scripts to improve librandombytes startup time. On new
Linux systems, randombytes-info
should instead say kernel-getrandom
and startup time should be fine in any case, unaffected by these lines.
If you're running a Linux virtual machine (old or new) and see startup
delays, you probably need the host to provide virtio-rng
.
For developers with an unprivileged account
Typically you'll already have
export LD_LIBRARY_PATH="$HOME/lib"
export LIBRARY_PATH="$HOME/lib"
export CPATH="$HOME/include"
export PATH="$HOME/bin:$PATH"
in $HOME/.profile
. To install in $HOME/{include,lib,bin}
:
./configure --prefix=$HOME && make -j8 install
For distributors creating a package
Run
./configure --prefix=/usr && make -j8
and then follow your usual packaging procedures for the
build/0/package
files:
build/0/package/man/man3/randombytes.3
build/0/package/man/man1/randombytes-info.1
build/0/package/include/randombytes.h
build/0/package/lib/librandombytes*
build/0/package/bin/randombytes-info
Note that librandombytes-kernel
and librandombytes-openssl
are
alternative implementations of the same librandombytes API. There are
default symlinks to librandombytes-kernel
, but you should allow the
sysadmin to change these symlinks to librandombytes-openssl
by simply
installing a librandombytes-openssl
package. The OpenSSL dependency is
for librandombytes-openssl
; the rest of librandombytes is independent
of OpenSSL.
More options
You can run
./configure --host=amd64
to override ./configure
's guess of the architecture that it should
compile for. However, cross-compilers aren't yet selected automatically.
Inside the build
directory, 0
is symlinked to amd64
for
--host=amd64
. Running make clean
removes build/amd64
. Re-running
./configure
automatically starts with make clean
.
A subsequent ./configure --host=arm64
will create build/arm64
and
symlink 0 -> arm64
, without touching an existing build/amd64
.
Compilers tried are listed in compilers/default
. Each compiler
includes -fPIC
to create a shared library and -fwrapv
to switch to a
slightly less dangerous version of C; also, -fvisibility=hidden
is
added automatically to hide non-public symbols in the library. The first
compiler that seems to work is used to compile everything.
Version:
This is version 2024.03.18 of the "Install" web page.
librandombytes-20240318/doc/html/license.html 0000444 0000000 0000000 00000005132 14575707635 017536 0 ustar root root
librandombytes: License
librandombytes
librandombytes is hereby placed into the public domain.
SPDX-License-Identifier:
LicenseRef-PD-hp
OR
CC0-1.0
OR
0BSD
OR
MIT-0
OR
MIT
Version:
This is version 2023.09.04 of the "License" web page.
librandombytes-20240318/doc/html/security.html 0000444 0000000 0000000 00000047106 14575707635 017772 0 ustar root root
librandombytes: Security
librandombytes
The standard security goal for a random-number generator (RNG) is that
no feasible computation can distinguish the RNG output from true
randomness, i.e., from a uniform random string of the same length. This
allows applications to treat the RNG output as true randomness.
Beyond merely asking for indistinguishability, some applications ask for
"forward secrecy". This means that the RNG output is indistinguishable
from true randomness for an attacker who sees the subsequent state of
the entire device, including the internal state of the RNG.
A typical explanation of the importance of forward secrecy is as
follows: "A rogue country's spy agency has intercepted ciphertexts that
a whistleblower has sent to a journalist. Agents then grab the
whistleblower's computer while the computer is unlocked, take it away
for analysis, and see that the whistleblower deleted the messages after
sending them. Can the agency use the computer's current RNG state to
reconstruct old keys and decrypt the ciphertexts?"
Sometimes there are also requests for "backward secrecy". A strict
interpretation of backward secrecy says that an attacker who sees the
state of the entire device cannot distinguish the next RNG output from
uniform. A weaker variant is for secrecy to eventually be restored
after a compromise. Either way, backward secrecy is advertised as
providing "self-healing", "post-compromise security", etc. Beware that
this assumes a questionable concept of compromise as a one-time event
rather than a naturally persistent state; meanwhile the complications of
trying to achieve "post-compromise security" have a long history of
distracting attention from the more fundamental task of preventing
compromises in the first place.
Whether or not backward secrecy is desired, there are many ways for RNGs
to fail to provide forward secrecy, or to fail to even reach the
standard security goal. For example:
-
After source code for the RC4 stream cipher was posted anonymously in
1994, RC4 was rapidly shown to flunk the standard definition of cipher
security. Before and after this, RC4 was pushed by NSA (which had set
up special procedures
to allow RC4 export licenses) and by the RSA company. RC4 remained in
wide use for two decades for TLS encryption and for RNGs.
-
Around 2005, NSA paid the RSA company
$10 million
to use Dual EC as the default RNG in RSA's BSAFE library. Dual EC
was an RNG designed to be
predictable by NSA.
-
Newer RNGs have often turned out to be feasible to distinguish from
uniform. Common contributing factors include inadequate attention to
security (which is hard to measure) and much more attention to
performance (which is much easier to measure). For example, a
2020 attack
uses just 257 CPU cycles to recover the secret "seed" and secret
"increment" of the "PCG64" RNG.
-
Many RNG constructions advertised as "provably secure" constructions
based on well-studied cryptographic primitives turn out to provide
much lower security levels than desired. For example, AES-256-CTR, the
usual "provably secure" way to use AES-256 as a stream cipher and RNG,
provably flunks a simple collision test after 268 bytes of output.
This is not a sharp cutoff: one needs a much smaller limit on the
output length to avoid having this attack succeed with probability
measurably above 0.
-
Even after the removal of Dual EC, NIST's "SP 800-90" RNG standard
remains unnecessarily complicated and unnecessarily difficult to
analyze. A partial analysis in 2018 showed that SP 800-90A
failed to provide
some of its claimed forward-secrecy properties. Also, because of
performance problems in how NIST handles short outputs, applications
are encouraged to add their own larger output buffers, typically
compromising forward secrecy.
Furthermore, RNG security can be compromised by implementation failures.
For example:
-
The AES design encourages implementors to use "T-table"
implementations on many platforms, exposing secret keys to
cache-timing attacks.
-
If a virtual machine generates RNG output (perhaps used for a nonce
sent to an attacker) and is then restored from a snapshot, many types
of RNGs will generate the same RNG output again (perhaps then used for
a secret key). This recycling compromises the security of various
applications that would otherwise be safe.
-
Similarly, many types of RNGs will produce identical results in parent
and child processes after fork()
, again compromising security of
various applications that would otherwise be safe.
-
In 2006, the Debian OS distribution incorrectly removed essential
lines of code from the OpenSSL RNG, producing easily breakable keys in
various cryptographic applications. Other Debian-based distributions,
such as Ubuntu, copied the change.
The Debian error was publicly discovered and corrected in 2008. A
review
showed that the error was triggered by warnings from a code-analysis
tool that did not understand what was going on in the RNG code.
-
In 2012, two
independent
papers
showed that a noticeable percentage of RSA public keys available on
the Internet were factorable because two keys had factors in common.
The second paper observed vulnerable keys from Linux, FreeBSD, and
Windows, and gave a convincing explanation of how randomness would
repeat on embedded Linux systems:
-
The Linux kernel accumulated entropy very slowly on small devices.
-
Keys were generated by the device on first boot, starting very
early in the boot process.
-
/dev/urandom
, the source of randomness, returned data without
waiting for 256 bits of entropy to be collected.
Another available mechanism, /dev/random
, waited for entropy but
was justifably avoided by many applications. This mechanism had the
serious misfeature of also waiting for further entropy for every
subsequent call; slow entropy collection thus turned /dev/random
into a problematic
bottleneck.
-
In 2018, a Linux kernel bug was
discovered
that would result in /dev/random
not waiting long enough for
entropy to be collected.
RNG failures are often used as motivation for the development of further
RNGs, but if this process is not carefully managed then it increases the
load on reviewers and encourages further security problems.
librandombytes does not provide a new RNG; it is a wrapper around
existing RNGs. It does not wrap every available RNG; it limits the
number of options to simplify review. It takes the maximally centralized
option, the OS kernel's RNG, by default; it provides one backup option,
the OpenSSL RNG, just in case this is critical for system performance.
Usage of the OS kernel's RNG has an imperfect track record, as
illustrated by the papers from 2012 cited above. This is concerning.
However, there are reasons to believe that risks have been reduced:
-
There is increasing adoption of OpenBSD's approach of provisioning
all devices with initial randomness at installation time, for
example by having a computer generate initial randomness for a
device that it is flashing or for a new virtual-machine image.
-
There is increasing usage of mechanisms to quickly collect entropy,
even on small devices. This serves as a backup if initial randomness
fails, and can rescue forward secrecy when flash does not adequately
erase randomness that was stored for the next boot. Also, people
trying to achieve backward secrecy require these mechanisms.
-
There is increasing usage of mechanisms for virtual machines to
collect entropy from the host machine, such as virtio-rng
.
-
It is increasingly common for CPUs to include RNG hardware, although
this hardware is inherently difficult to audit and
easy to sabotage.
A BIOS bug
removed all entropy from the RNG on AMD CPUs after suspend/resume;
the bug wasn't addressed for five years.
-
There is increasing availability of getrandom
and/or getentropy
.
These functions wait for initial entropy to be collected (without the
/dev/random
misfeature of also waiting for further entropy for every
subsequent call). This avoids security problems in the disaster
scenario of initial randomness failing and entropy collection being
slow. Some history:
-
2014: getentropy
was introduced in OpenBSD 5.6, and getrandom
was introduced (as a variant of getentropy
) in Linux kernel 3.17.
-
2015: getentropy
and getrandom
were added to
Solaris 11.3.
-
2017: getentropy
and getrandom
were added to
glibc 2.25,
with getentropy
provided as a wrapper around getrandom
on
Linux systems.
-
2018: getentropy
and getrandom
were added to
FreeBSD 12.0.
FreeBSD already changed /dev/urandom
in 2000
to wait for initial entropy to be collected, already bringing the
same benefit without requiring applications to adopt a new
interface. For OpenBSD, randomness was always available from
installation time, so /dev/urandom
never had a reason to wait.
(But getrandom
and getentropy
have separate advantages of not
relying on opening a file; this simplifies chroot
setups and
avoids various failure cases.)
-
There is increasing convergence upon the ChaCha20 stream cipher as
the foundation of random-number generation.
ChaCha20 is a 2008 variant of the 2005 Salsa20 stream cipher, and is
one of just two ciphers in TLS 1.3. ChaCha20 is stronger against
known attacks than the other TLS 1.3 cipher, AES-256-CTR; recall
that AES-256-CTR flunks a feasible collision test. ChaCha20 also
does not have AES's problem of encouraging variable-time software.
Regarding possible attack improvements, the challenge of breaking
scaled-down versions of Salsa20 and ChaCha20 has attracted 20 attacks
from 43 cryptanalysts.
With the published techniques, ChaCha6 is feasible to break by a
large-scale attack, and ChaCha7 is subject to an attack faster than
brute force. (For comparison, even if the aforementioned collision
failure is ignored, 6 out of the 14 rounds of AES-256 are breakable
by a feasible attack, and 8 out of the 14 rounds of AES-256 are
subject to an attack faster than brute force.) The long-term
security of ChaCha8 is unclear, but the recommended ChaCha20 has
very low risk.
-
There is increasing convergence upon a simple, efficient, easily
analyzed mechanism to provide forward secrecy given a strong stream
cipher: fast-key-erasure RNGs.
Examples of these RNGs include
-
2013: Nick Mathewson's libottery,
which says it is "based on a construction described in XXX, as
summarized by DJB";
-
2013: OpenBSD's
arc4random
update,
with credit to libottery, replacing previous use of RC4;
-
2018: FreeBSD's
arc4random
update,
with credit to libottery and OpenBSD; and
-
2022: Linux's
RNG updates.
A 2005 paper by
Barak and Halevi
analyzes the following special case of fast-key-erasure RNGs: an
m-bit key is used to generate 2m bits of stream-cipher output, split
into m bits of RNG output and m bits to overwrite the key. A general
fast-key-erasure RNG obtains the same security properties at much
higher speed by generating more output from each key: e.g., 768
bytes of output from a 32-byte key.
librandombytes-kernel
uses getrandom
if it finds it, otherwise
getentropy
if it finds it, otherwise /dev/urandom
. In the case of
/dev/urandom
, librandombytes-kernel
waits at program startup for
/dev/random
to become readable; however, it skips this if the file
/var/run/urandom-ready
exists (or if /dev/random
does not exist).
The idea is that system administrators of Linux systems too old to have
getrandom
can run
dd count=1 bs=64 if=/dev/random of=/dev/urandom status=none \
&& findmnt -t tmpfs -T /var/run >/dev/null \
&& touch /var/run/urandom-ready &
from boot scripts so that librandombytes-kernel
doesn't wait after
initial per-boot entropy collection. Note that systems where /var/run
is a persistent directory (rather than tmpfs
), cleared by boot
scripts, should not create /var/run/urandom-ready
, since
librandombytes-kernel
might be running earlier in the boot process.
There are various other ways that one can imagine /dev/urandom
being
read too early on old Linux systems (and not so old, as in the 2018
Linux bug mentioned above); librandombytes-kernel
tries to reduce
risks but does not make guarantees. Provisioning systems with initial
randomness is recommended in all cases. There are also many other
security reasons to recommend retiring old Linux systems if they cannot
be upgraded.
librandombytes-openssl
, which simply calls OpenSSL's RAND_bytes
,
raises more security concerns:
-
OpenSSL's RAND_bytes
maintains an RNG state in user space,
evidently because of a belief that this produces an important
speedup. With its current defaults, OpenSSL can take an hour before
it reseeds the user RNG state from the OS. This means that whatever
entropy-injection mechanisms are in the OS RNG, for example to
protect virtual machines, can leave OpenSSL unprotected for an hour.
-
OpenSSL's default RNG,
starting in 2017,
is a NIST RNG, specifically CTR-DRBG built on top of AES. A
2019 attack
showed that OpenSSL in FIPS mode was using T-table implementations
of AES and was leaking RNG secrets to a timing attack. Even with a
constant-time AES implementation, the security level of this RNG is
not clear from the existing literature.
-
When OpenSSL first seeds its RNG from /dev/urandom
on
pre-getrandom
Linux systems, it waits (starting with OpenSSL
1.1.1d in 2019) for /dev/random
to become readable, and then
creates shared memory segment 114. It skips the /dev/random
wait
if shared memory segment 114 exists already. This does not have the
same security properties as checking for existence of a file that
can be created only by root: if any account on the same system is
running code from an attacker then the attacker can create shared
memory segment 114, disabling the /dev/random
test for all OpenSSL
instances on the same system.
These OpenSSL issues are not obviously showstoppers. For systems where
using the OS RNG is a performance problem, OpenSSL's RNG seems to be a
reasonable backup plan. Of course, it would be possible to patch OpenSSL
to use a fast-key-erasure RNG on top of ChaCha20, to use a safer
/dev/random
test (which could also be handled as a wrapper around
OpenSSL), and to reseed more frequently.
Version:
This is version 2023.09.04 of the "Security" web page.
librandombytes-20240318/doc/install.md 0000644 0000000 0000000 00000005626 14575707635 016264 0 ustar root root Prerequisites: `python3`; `gcc` and/or `clang`; OpenSSL. Currently
tested only under Linux, but porting to other systems shouldn't be
difficult.
### For sysadmins
To install in `/usr/local/{include,lib,bin}`:
./configure && make -j8 install
If you're running an old Linux system and see that the `randombytes-info`
output says `randombytes source kernel-devurandom` (this will happen on
Linux kernels before 3.17), add the lines
dd count=1 bs=64 if=/dev/random of=/dev/urandom status=none \
&& findmnt -t tmpfs -T /var/run >/dev/null \
&& touch /var/run/urandom-ready &
to your boot scripts to improve librandombytes startup time. On new
Linux systems, `randombytes-info` should instead say `kernel-getrandom`
and startup time should be fine in any case, unaffected by these lines.
If you're running a Linux virtual machine (old or new) and see startup
delays, you probably need the host to provide `virtio-rng`.
### For developers with an unprivileged account
Typically you'll already have
export LD_LIBRARY_PATH="$HOME/lib"
export LIBRARY_PATH="$HOME/lib"
export CPATH="$HOME/include"
export PATH="$HOME/bin:$PATH"
in `$HOME/.profile`. To install in `$HOME/{include,lib,bin}`:
./configure --prefix=$HOME && make -j8 install
### For distributors creating a package
Run
./configure --prefix=/usr && make -j8
and then follow your usual packaging procedures for the
`build/0/package` files:
build/0/package/man/man3/randombytes.3
build/0/package/man/man1/randombytes-info.1
build/0/package/include/randombytes.h
build/0/package/lib/librandombytes*
build/0/package/bin/randombytes-info
Note that `librandombytes-kernel` and `librandombytes-openssl` are
alternative implementations of the same librandombytes API. There are
default symlinks to `librandombytes-kernel`, but you should allow the
sysadmin to change these symlinks to `librandombytes-openssl` by simply
installing a `librandombytes-openssl` package. The OpenSSL dependency is
for `librandombytes-openssl`; the rest of librandombytes is independent
of OpenSSL.
### More options
You can run
./configure --host=amd64
to override `./configure`'s guess of the architecture that it should
compile for. However, cross-compilers aren't yet selected automatically.
Inside the `build` directory, `0` is symlinked to `amd64` for
`--host=amd64`. Running `make clean` removes `build/amd64`. Re-running
`./configure` automatically starts with `make clean`.
A subsequent `./configure --host=arm64` will create `build/arm64` and
symlink `0 -> arm64`, without touching an existing `build/amd64`.
Compilers tried are listed in `compilers/default`. Each compiler
includes `-fPIC` to create a shared library and `-fwrapv` to switch to a
slightly less dangerous version of C; also, `-fvisibility=hidden` is
added automatically to hide non-public symbols in the library. The first
compiler that seems to work is used to compile everything.
librandombytes-20240318/doc/license.md 0000644 0000000 0000000 00000000534 14575707635 016231 0 ustar root root librandombytes is hereby placed into the public domain.
[SPDX-License-Identifier](https://spdx.dev/ids/):
[LicenseRef-PD-hp](https://cr.yp.to/spdx.html)
OR
[CC0-1.0](https://spdx.org/licenses/CC0-1.0.html)
OR
[0BSD](https://spdx.org/licenses/0BSD.html)
OR
[MIT-0](https://spdx.org/licenses/MIT-0.html)
OR
[MIT](https://spdx.org/licenses/MIT.html)
librandombytes-20240318/doc/man/ 0000755 0000000 0000000 00000000000 14575707635 015036 5 ustar root root librandombytes-20240318/doc/man/randombytes-info.1 0000644 0000000 0000000 00000001603 14575707635 020400 0 ustar root root .\" Automatically generated by Pandoc 2.17.1.1
.\"
.\" Define V font for inline verbatim, using C font in formats
.\" that render this, and otherwise B font.
.ie "\f[CB]x\f[]"x" \{\
. ftr V B
. ftr VI BI
. ftr VB B
. ftr VBI BI
.\}
.el \{\
. ftr V CR
. ftr VI CI
. ftr VB CB
. ftr VBI CBI
.\}
.TH "randombytes-info" "1" "" "" ""
.hy
.SS NAME
.PP
randombytes-info - report information about random-number generator
.SS SYNOPSIS
.IP
.nf
\f[C]
randombytes-info
\f[R]
.fi
.SS DESCRIPTION
.PP
\f[V]randombytes-info\f[R] prints human-readable information about the
RNG selected by \f[V]randombytes()\f[R].
.PP
The format is subject to change but currently includes a
\f[V]randombytes source\f[R] line, \f[V]randombytes test_fork\f[R] lines
(which should show different random-looking data for \f[V]x\f[R] and
\f[V]y\f[R]), and \f[V]randombytes timing\f[R] lines.
.SS SEE ALSO
.PP
\f[B]randombytes\f[R](3)
librandombytes-20240318/doc/man/randombytes.3 0000644 0000000 0000000 00000007500 14575707635 017453 0 ustar root root .\" Automatically generated by Pandoc 2.17.1.1
.\"
.\" Define V font for inline verbatim, using C font in formats
.\" that render this, and otherwise B font.
.ie "\f[CB]x\f[]"x" \{\
. ftr V B
. ftr VI BI
. ftr VB B
. ftr VBI BI
.\}
.el \{\
. ftr V CR
. ftr VI CI
. ftr VB CB
. ftr VBI CBI
.\}
.TH "randombytes" "3" "" "" ""
.hy
.SS NAME
.PP
randombytes - fill a buffer with random data
.SS SYNOPSIS
.IP
.nf
\f[C]
#include
unsigned char x[xbytes];
randombytes(x,xbytes);
\f[R]
.fi
.PP
Link with \f[V]-lrandombytes\f[R].
.SS DESCRIPTION
.PP
\f[V]randombytes\f[R] sets \f[V]x[0]\f[R], \f[V]x[1]\f[R], \&...,
\f[V]x[xbytes-1]\f[R] to random bytes of data.
.PP
Randomness APIs vary in three major ways.
\f[V]randombytes\f[R] is designed in each way to simplify callers:
.IP \[bu] 2
Like \f[V]RAND_bytes\f[R], \f[V]randombytes\f[R] automatically generates
separate randomness for any number of bytes in any number of calls in
any number of threads in any number of programs.
For comparison, some randomness APIs (e.g., \f[V]random\f[R]) recycle
randomness from one program to another unless the program does extra
work to set a separate \[lq]seed\[rq], and can recycle randomness across
multiple threads unless the program does further work.
.IP \[bu] 2
Like \f[V]getrandom\f[R] and \f[V]getentropy\f[R] and
\f[V]RAND_bytes\f[R], \f[V]randombytes\f[R] aims for the stringent goal
of ensuring that no feasible computation will ever be able to tell the
difference between the output bytes and true randomness.
The caller can treat each returned byte as the result of 8 fresh coin
flips.
For comparison, some randomness APIs (e.g., \f[V]random\f[R]) do not aim
for this goal and do not view detectable patterns as a bug, as long as
\f[I]most\f[R] applications do not notice the patterns.
.IP \[bu] 2
Like \f[V]random\f[R], \f[V]randombytes\f[R] always succeeds.
Any necessary resources (e.g., opening a file descriptor for
\f[V]/dev/urandom\f[R], on systems that need this) are allocated at
program startup, rather than being deferred until the first
\f[V]randombytes\f[R] call; also, dynamic failure cases such as EINTR
are handled inside \f[V]randombytes\f[R].
For comparison, some randomness APIs (e.g., \f[V]getrandom\f[R] and
\f[V]getentropy\f[R] and \f[V]RAND_bytes\f[R]) can return error codes to
be handled by the caller.
.PP
There are some programs that try to close all file descriptors.
These programs must limit their library use to libraries that promise
not to keep file descriptors open.
In particular, these programs must not use \f[V]randombytes\f[R] (which
keeps a file descriptor open on some systems) or other libraries calling
\f[V]randombytes\f[R].
.SS LINK DETAILS
.PP
Currently \f[V]-lrandombytes\f[R] is a frontend symbolic link to either
\f[V]-lrandombytes-kernel\f[R] or \f[V]-lrandombytes-openssl\f[R] as a
backend library.
To simplify system-wide replacement of the backend library, typical
applications should dynamically link to \f[V]-lrandombytes\f[R] rather
than to \f[V]-lrandombytes-kernel\f[R] or
\f[V]-lrandombytes-openssl\f[R].
.PP
Applications that link statically to \f[V]-lrandombytes\f[R] also need
\f[V]-lcrypto\f[R] if \f[V]-lrandombytes\f[R] is
\f[V]-lrandombytes-openssl\f[R].
.PP
Currently \f[V]randombytes\f[R] is a macro, where the function actually
linked is \f[V]randombytes_internal_void_voidstar_longlong\f[R].
.SS HISTORY
.PP
The \f[V]randombytes\f[R] API was introduced in 2008 as part of the
SUPERCOP (https://bench.cr.yp.to) benchmarking framework for
cryptographic software.
.PP
Similar previous APIs include \f[V]RAND_bytes\f[R] and
\f[V]arc4random_buf\f[R], but \f[V]RAND_bytes\f[R] was allowed to return
failures and \f[V]arc4random_buf\f[R] was using the broken RC4 stream
cipher.
.SS SEE ALSO
.PP
\f[B]getrandom\f[R](2), \f[B]getentropy\f[R](2), \f[B]rand\f[R](3),
\f[B]random\f[R](3), \f[B]arc4random\f[R](3), \f[B]urandom\f[R](4)
librandombytes-20240318/doc/randombytes-info.md 0000644 0000000 0000000 00000000734 14575707635 020071 0 ustar root root ### NAME
randombytes-info - report information about random-number generator
### SYNOPSIS
randombytes-info
### DESCRIPTION
`randombytes-info`
prints human-readable information
about the RNG selected by `randombytes()`.
The format is subject to change
but currently includes
a `randombytes source` line,
`randombytes test_fork` lines
(which should show different random-looking data for `x` and `y`),
and `randombytes timing` lines.
### SEE ALSO
**randombytes**(3)
librandombytes-20240318/doc/readme.md 0000644 0000000 0000000 00000006470 14575707635 016051 0 ustar root root librandombytes provides a simple API for applications generating fresh
randomness: include ``, call `randombytes(x,xbytes)`
whenever desired to generate fresh random bytes `x[0]`, `x[1]`, ...,
`x[xbytes-1]`, and link with `-lrandombytes`.
Random bytes are often used directly in applications. Random bytes are
also the foundation of more complicated random objects, such as random
integers in a limited interval, random floating-point numbers from a
(nearly) normal distribution, and random keys used in public-key
cryptosystems. librandombytes is dedicated to obtaining fresh random
bytes in the first place, and leaves it to higher-level libraries to
convert those bytes into other types of random objects.
librandombytes aims for the following stringent randomness goal: no
feasible computation will ever be able to tell the difference between
the output bytes and true randomness (independent uniformly distributed
random bytes). This makes the `randombytes()` output suitable for use
in applications ranging from simulations to cryptography.
Most alternative sources of randomness (such as `rand()` and `random()`
in C, and `mt19937_64` in C++) consider detectable deviations from true
randomness to be acceptable as long as _most_ applications do not notice
the deviations. These sources are not permitted inside librandombytes;
the `randombytes()` caller is entitled to expect that the output comes
from sources that are designed for the right goal.
Internally, librandombytes is an abstraction layer for a choice of two
libraries, where each library provides the same `randombytes` interface
but the libraries choose two different sources of randomness:
* `librandombytes-kernel` reads random bytes provided by the OS kernel
via mechanisms such as `getrandom()`. These mechanisms are typically
advertised as providing RNG security features that are harder to
provide in user space, such as hypervisor integration.
* `librandombytes-openssl` uses OpenSSL's `RAND_bytes` to generate
random bytes. This mechanism is typically advertised as providing
speed that is difficult to achieve without a per-process RNG.
The idea is that the OS can install `librandombytes-kernel` by default,
but the sysadmin can install `librandombytes-openssl` to transparently
switch all of the `randombytes()` applications to `RAND_bytes` (for
example, via Debian's `/etc/alternatives` mechanism) _if_ profiling
shows that this switch is important for overall system performance.
Making this choice centrally means that applications are free to simply
call `randombytes()`
* without worrying about evaluating performance,
* without worrying about how to balance performance concerns with
competing concerns, and
* without worrying that these performance evaluations will be rendered
obsolete by speed improvements: for example, by
[ongoing work](https://lkml.org/lkml/2023/1/1/87) to accelerate
`getrandom()`, or by the increasing deployment of
[fast-key-erasure RNGs](https://blog.cr.yp.to/20170723-random.html).
Another virtue of having a `randombytes()` abstraction layer is that
test frameworks can substitute a deterministic seeded `randombytes()`
providing _known_ pseudorandom bytes for reproducible tests. Of course,
the `randombytes()` provided by these test frameworks must be kept
separate from the fresh `randombytes()` used for deployment.
librandombytes-20240318/doc/security.md 0000644 0000000 0000000 00000040205 14575707635 016455 0 ustar root root The standard security goal for a random-number generator (RNG) is that
no feasible computation can distinguish the RNG output from true
randomness, i.e., from a uniform random string of the same length. This
allows applications to treat the RNG output as true randomness.
Beyond merely asking for indistinguishability, some applications ask for
"forward secrecy". This means that the RNG output is indistinguishable
from true randomness for an attacker who sees the subsequent state of
the entire device, including the internal state of the RNG.
A typical explanation of the importance of forward secrecy is as
follows: "A rogue country's spy agency has intercepted ciphertexts that
a whistleblower has sent to a journalist. Agents then grab the
whistleblower's computer while the computer is unlocked, take it away
for analysis, and see that the whistleblower deleted the messages after
sending them. Can the agency use the computer's current RNG state to
reconstruct old keys and decrypt the ciphertexts?"
Sometimes there are also requests for "backward secrecy". A strict
interpretation of backward secrecy says that an attacker who sees the
state of the entire device cannot distinguish the _next_ RNG output from
uniform. A weaker variant is for secrecy to _eventually_ be restored
after a compromise. Either way, backward secrecy is advertised as
providing "self-healing", "post-compromise security", etc. Beware that
this assumes a questionable concept of compromise as a one-time event
rather than a naturally persistent state; meanwhile the complications of
trying to achieve "post-compromise security" have a long history of
distracting attention from the more fundamental task of preventing
compromises in the first place.
Whether or not backward secrecy is desired, there are many ways for RNGs
to fail to provide forward secrecy, or to fail to even reach the
standard security goal. For example:
* After source code for the RC4 stream cipher was posted anonymously in
1994, RC4 was rapidly shown to flunk the standard definition of cipher
security. Before and after this, RC4 was pushed by NSA (which had set
up [special procedures](https://cr.yp.to/export/dtn/V3N4_10_92.pdf)
to allow RC4 export licenses) and by the RSA company. RC4 remained in
wide use for two decades for TLS encryption and for RNGs.
* Around 2005, NSA paid the RSA company
[$10 million](https://www.reuters.com/article/us-usa-security-rsa-idUSBRE9BJ1C220131220)
to use Dual EC as the default RNG in RSA's BSAFE library. Dual EC
was an RNG designed to be
[predictable by NSA](https://projectbullrun.org/dual-ec/index.html).
* Newer RNGs have often turned out to be feasible to distinguish from
uniform. Common contributing factors include inadequate attention to
security (which is hard to measure) and much more attention to
performance (which is much easier to measure). For example, a
[2020 attack](https://tosc.iacr.org/index.php/ToSC/article/view/8700)
uses just 2^57^ CPU cycles to recover the secret "seed" and secret
"increment" of the "PCG64" RNG.
* Many RNG constructions advertised as "provably secure" constructions
based on well-studied cryptographic primitives turn out to provide
much lower security levels than desired. For example, AES-256-CTR, the
usual "provably secure" way to use AES-256 as a stream cipher and RNG,
provably flunks a simple collision test after 2^68^ bytes of output.
This is not a sharp cutoff: one needs a much smaller limit on the
output length to avoid having this attack succeed with probability
measurably above 0.
* Even after the removal of Dual EC, NIST's "SP 800-90" RNG standard
remains unnecessarily complicated and unnecessarily difficult to
analyze. A partial analysis in 2018 showed that SP 800-90A
[failed to provide](https://eprint.iacr.org/2018/349)
some of its claimed forward-secrecy properties. Also, because of
performance problems in how NIST handles short outputs, applications
are encouraged to add their own larger output buffers, typically
compromising forward secrecy.
Furthermore, RNG security can be compromised by implementation failures.
For example:
* The AES design encourages implementors to use "T-table"
implementations on many platforms, exposing secret keys to
[cache-timing attacks](https://cr.yp.to/papers.html#cachetiming).
* If a virtual machine generates RNG output (perhaps used for a nonce
sent to an attacker) and is then restored from a snapshot, many types
of RNGs will generate the same RNG output again (perhaps then used for
a secret key). This recycling compromises the security of various
applications that would otherwise be safe.
* Similarly, many types of RNGs will produce identical results in parent
and child processes after `fork()`, again compromising security of
various applications that would otherwise be safe.
* In 2006, the Debian OS distribution incorrectly removed essential
lines of code from the OpenSSL RNG, producing easily breakable keys in
various cryptographic applications. Other Debian-based distributions,
such as Ubuntu, copied the change.
The Debian error was publicly discovered and corrected in 2008. A
[review](https://fahrplan.events.ccc.de/congress/2008/Fahrplan/events/2995.en.html)
showed that the error was triggered by warnings from a code-analysis
tool that did not understand what was going on in the RNG code.
* In 2012, two
[independent](https://eprint.iacr.org/2012/064)
[papers](https://factorable.net/)
showed that a noticeable percentage of RSA public keys available on
the Internet were factorable because two keys had factors in common.
The second paper observed vulnerable keys from Linux, FreeBSD, and
Windows, and gave a convincing explanation of how randomness would
repeat on embedded Linux systems:
* The Linux kernel accumulated entropy very slowly on small devices.
* Keys were generated by the device on first boot, starting very
early in the boot process.
* `/dev/urandom`, the source of randomness, returned data without
waiting for 256 bits of entropy to be collected.
Another available mechanism, `/dev/random`, waited for entropy but
was justifably avoided by many applications. This mechanism had the
serious misfeature of also waiting for further entropy for every
subsequent call; slow entropy collection thus turned `/dev/random`
into a [problematic](https://github.com/openssl/openssl/issues/9078)
bottleneck.
* In 2018, a Linux kernel bug was
[discovered](https://lkml.org/lkml/2018/4/12/711)
that would result in `/dev/random` not waiting long enough for
entropy to be collected.
RNG failures are often used as motivation for the development of further
RNGs, but if this process is not carefully managed then it increases the
load on reviewers and encourages further security problems.
librandombytes does not provide a new RNG; it is a wrapper around
existing RNGs. It does not wrap every available RNG; it limits the
number of options to simplify review. It takes the maximally centralized
option, the OS kernel's RNG, by default; it provides one backup option,
the OpenSSL RNG, just in case this is critical for system performance.
Usage of the OS kernel's RNG has an imperfect track record, as
illustrated by the papers from 2012 cited above. This is concerning.
However, there are reasons to believe that risks have been reduced:
* There is increasing adoption of OpenBSD's approach of provisioning
all devices with initial randomness at installation time, for
example by having a computer generate initial randomness for a
device that it is flashing or for a new virtual-machine image.
* There is increasing usage of mechanisms to quickly collect entropy,
even on small devices. This serves as a backup if initial randomness
fails, and can rescue forward secrecy when flash does not adequately
erase randomness that was stored for the next boot. Also, people
trying to achieve backward secrecy require these mechanisms.
* There is increasing usage of mechanisms for virtual machines to
collect entropy from the host machine, such as `virtio-rng`.
* It is increasingly common for CPUs to include RNG hardware, although
this hardware is inherently difficult to audit and
[easy to sabotage](https://www.iacr.org/archive/ches2013/80860203/80860203.pdf).
A [BIOS bug](https://lore.kernel.org/all/776cb5c2d33e7fd0d2893904724c0e52b394f24a.1565817448.git.thomas.lendacky@amd.com/T/#u)
removed all entropy from the RNG on AMD CPUs after suspend/resume;
the bug wasn't addressed for five years.
* There is increasing availability of `getrandom` and/or `getentropy`.
These functions wait for initial entropy to be collected (without the
`/dev/random` misfeature of also waiting for further entropy for every
subsequent call). This avoids security problems in the disaster
scenario of initial randomness failing and entropy collection being
slow. Some history:
* 2014: `getentropy` was introduced in OpenBSD 5.6, and `getrandom`
was introduced (as a variant of `getentropy`) in Linux kernel 3.17.
* 2015: `getentropy` and `getrandom` were added to
[Solaris 11.3](https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2).
* 2017: `getentropy` and `getrandom` were added to
[glibc 2.25](https://sourceware.org/legacy-ml/libc-alpha/2017-02/msg00079.html),
with `getentropy` provided as a wrapper around `getrandom` on
Linux systems.
* 2018: `getentropy` and `getrandom` were added to
[FreeBSD 12.0](https://www.freebsd.org/releases/12.0R/relnotes/).
FreeBSD already changed `/dev/urandom`
[in 2000](https://papers.freebsd.org/2017/vbsdcon/gurney-A_Deep_Dive_into_FreeBSDs_Kernel_RNG.files/gurney-A_Deep_Dive_into_FreeBSDs_Kernel_RNG.pdf)
to wait for initial entropy to be collected, already bringing the
same benefit without requiring applications to adopt a new
interface. For OpenBSD, randomness was always available from
installation time, so `/dev/urandom` never had a reason to wait.
(But `getrandom` and `getentropy` have separate advantages of not
relying on opening a file; this simplifies `chroot` setups and
avoids various failure cases.)
* There is increasing convergence upon the ChaCha20 stream cipher as
the foundation of random-number generation.
ChaCha20 is a 2008 variant of the 2005 Salsa20 stream cipher, and is
one of just two ciphers in TLS 1.3. ChaCha20 is stronger against
known attacks than the other TLS 1.3 cipher, AES-256-CTR; recall
that AES-256-CTR flunks a feasible collision test. ChaCha20 also
does not have AES's problem of encouraging variable-time software.
Regarding possible attack improvements, the challenge of breaking
scaled-down versions of Salsa20 and ChaCha20 has attracted 20 attacks
from [43 cryptanalysts](https://cr.yp.to/snuffle.html#security).
With the published techniques, ChaCha6 is feasible to break by a
large-scale attack, and ChaCha7 is subject to an attack faster than
brute force. (For comparison, even if the aforementioned collision
failure is ignored, 6 out of the 14 rounds of AES-256 are breakable
by a feasible attack, and 8 out of the 14 rounds of AES-256 are
subject to an attack faster than brute force.) The long-term
security of ChaCha8 is unclear, but the recommended ChaCha20 has
very low risk.
* There is increasing convergence upon a simple, efficient, easily
analyzed mechanism to provide forward secrecy given a strong stream
cipher: [fast-key-erasure RNGs](https://blog.cr.yp.to/20170723-random.html).
Examples of these RNGs include
* 2013: Nick Mathewson's [libottery](https://github.com/nmathewson/libottery),
which says it is "based on a construction described in XXX, as
summarized by DJB";
* 2013: OpenBSD's
[`arc4random` update](https://github.com/openbsd/src/commit/90c1fad70a3483c2c72c3c90acf438a5f235c776),
with credit to libottery, replacing previous use of RC4;
* 2018: FreeBSD's
[`arc4random` update](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=182610),
with credit to libottery and OpenBSD; and
* 2022: Linux's
[RNG updates](https://www.zx2c4.com/projects/linux-rng-5.17-5.18/inside-linux-kernel-rng-presentation-sept-13-2022.pdf).
A 2005 paper by
[Barak and Halevi](https://eprint.iacr.org/2005/029)
analyzes the following special case of fast-key-erasure RNGs: an
m-bit key is used to generate 2m bits of stream-cipher output, split
into m bits of RNG output and m bits to overwrite the key. A general
fast-key-erasure RNG obtains the same security properties at much
higher speed by generating more output from each key: e.g., 768
bytes of output from a 32-byte key.
`librandombytes-kernel` uses `getrandom` if it finds it, otherwise
`getentropy` if it finds it, otherwise `/dev/urandom`. In the case of
`/dev/urandom`, `librandombytes-kernel` waits at program startup for
`/dev/random` to become readable; however, it skips this if the file
`/var/run/urandom-ready` exists (or if `/dev/random` does not exist).
The idea is that system administrators of Linux systems too old to have
`getrandom` can run
dd count=1 bs=64 if=/dev/random of=/dev/urandom status=none \
&& findmnt -t tmpfs -T /var/run >/dev/null \
&& touch /var/run/urandom-ready &
from boot scripts so that `librandombytes-kernel` doesn't wait after
initial per-boot entropy collection. Note that systems where `/var/run`
is a persistent directory (rather than `tmpfs`), cleared by boot
scripts, should not create `/var/run/urandom-ready`, since
`librandombytes-kernel` might be running earlier in the boot process.
There are various other ways that one can imagine `/dev/urandom` being
read too early on old Linux systems (and not so old, as in the 2018
Linux bug mentioned above); `librandombytes-kernel` tries to reduce
risks but does not make guarantees. Provisioning systems with initial
randomness is recommended in all cases. There are also many other
security reasons to recommend retiring old Linux systems if they cannot
be upgraded.
`librandombytes-openssl`, which simply calls OpenSSL's `RAND_bytes`,
raises more security concerns:
* OpenSSL's `RAND_bytes` maintains an RNG state in user space,
evidently because of a belief that this produces an important
speedup. With its current defaults, OpenSSL can take an hour before
it reseeds the user RNG state from the OS. This means that whatever
entropy-injection mechanisms are in the OS RNG, for example to
protect virtual machines, can leave OpenSSL unprotected for an hour.
* OpenSSL's default RNG,
starting in [2017](https://www.openssl.org/blog/blog/2017/08/12/random/),
is a NIST RNG, specifically CTR-DRBG built on top of AES. A
[2019 attack](https://eprint.iacr.org/2019/996)
showed that OpenSSL in FIPS mode was using T-table implementations
of AES and was leaking RNG secrets to a timing attack. Even with a
constant-time AES implementation, the security level of this RNG is
not clear from the existing literature.
* When OpenSSL first seeds its RNG from `/dev/urandom` on
pre-`getrandom` Linux systems, it waits (starting with OpenSSL
1.1.1d in 2019) for `/dev/random` to become readable, and then
creates shared memory segment 114. It skips the `/dev/random` wait
if shared memory segment 114 exists already. This does not have the
same security properties as checking for existence of a file that
can be created only by root: if _any_ account on the same system is
running code from an attacker then the attacker can create shared
memory segment 114, disabling the `/dev/random` test for all OpenSSL
instances on the same system.
These OpenSSL issues are not obviously showstoppers. For systems where
using the OS RNG is a performance problem, OpenSSL's RNG seems to be a
reasonable backup plan. Of course, it would be possible to patch OpenSSL
to use a fast-key-erasure RNG on top of ChaCha20, to use a safer
`/dev/random` test (which could also be handled as a wrapper around
OpenSSL), and to reseed more frequently.
librandombytes-20240318/include/ 0000755 0000000 0000000 00000000000 14575707635 015141 5 ustar root root librandombytes-20240318/include/randombytes.h 0000644 0000000 0000000 00000000743 14575707635 017645 0 ustar root root // version 20230126
// public domain
// djb
// public API: randombytes()
#ifndef randombytes_h
#define randombytes_h
#define randombytes randombytes_internal_void_voidstar_longlong
#define randombytes_source randombytes_internal_source
#ifdef __cplusplus
extern "C" {
#endif
extern void randombytes(void *,long long) __attribute__((visibility("default")));
extern const char *randombytes_source(void) __attribute__((visibility("default")));
#ifdef __cplusplus
}
#endif
#endif
librandombytes-20240318/kernel/ 0000755 0000000 0000000 00000000000 14575707635 014776 5 ustar root root librandombytes-20240318/kernel/devurandom_wrapper.c 0000644 0000000 0000000 00000002576 14575707635 021060 0 ustar root root // version 20230126
// public domain
// djb
#include
#include
#include
#include
#include
#include
#include "devurandom_wrapper.h"
static void wait_for_random(void)
{
int random_fd;
struct pollfd p;
if (access("/var/run/urandom-ready",F_OK) == 0)
return;
for (;;) {
errno = 0;
random_fd = open("/dev/random",O_RDONLY);
if (random_fd >= 0) break;
if (errno == ENOENT) return;
sleep(1);
}
for (;;) {
p.fd = random_fd;
p.events = POLLIN;
p.revents = 0;
errno = 0;
if (poll(&p,1,0) == 1) break;
if (errno != EINTR) sleep(1); // e.g., ENOMEM
}
close(random_fd);
}
static int urandom_fd = -1;
int devurandom_wrapper_ready(void)
{
wait_for_random();
for (;;) {
errno = 0;
urandom_fd = open("/dev/urandom",O_RDONLY);
if (urandom_fd >= 0) break;
if (errno == ENOENT) return 0;
sleep(1);
}
fcntl(urandom_fd,F_SETFD,1);
// O_CLOEXEC is better but limits portability and is not necessary here:
// librandombytes runs *_ready only in static constructors
return 1;
}
void devurandom_wrapper(void *x,long long xbytes)
{
while (xbytes > 0) {
int todo = 1048576;
if (xbytes < 1048576) todo = xbytes;
todo = read(urandom_fd,x,todo);
if (todo < 1) {
sleep(1);
continue;
}
x += todo;
xbytes -= todo;
}
}
librandombytes-20240318/kernel/devurandom_wrapper.h 0000644 0000000 0000000 00000000570 14575707635 021055 0 ustar root root #ifndef devurandom_wrapper_h
#define devurandom_wrapper_h
#define devurandom_wrapper_ready randombytes_internal_devurandom_wrapper_ready
#define devurandom_wrapper randombytes_internal_devurandom_wrapper
#ifdef __cplusplus
extern "C" {
#endif
extern int devurandom_wrapper_ready(void);
extern void devurandom_wrapper(void *,long long);
#ifdef __cplusplus
}
#endif
#endif
librandombytes-20240318/kernel/getentropy_wrapper.c 0000644 0000000 0000000 00000002346 14575707635 021107 0 ustar root root // version 20230919
// public domain
// djb
// 20230919: fixing main getentropy() call; tnx jan mojzis
#include
// automatic-alternatives 2
#ifdef getentropy_wrapper_2
#include "getentropy_wrapper.h"
int getentropy_wrapper_ready(void)
{
return 0;
}
void getentropy_wrapper(void *x,long long xbytes)
{
for (;;) pause();
}
#else
#include
#include
#include "getentropy_wrapper.h"
static int getentropy_wrapper_ready_core(void)
{
char ch;
int r;
for (;;) {
errno = 0;
r = getentropy(&ch,1);
if (r == 0) return 1;
if (r == -1 && errno == ENOSYS) return 0;
if (r == -1 && errno == EPERM) return 0;
if (r == -1 && errno == EIO) return 0;
}
}
int getentropy_wrapper_ready(void)
{
struct sigaction old_sigsys;
int result;
sigaction(SIGSYS,0,&old_sigsys);
signal(SIGSYS,SIG_IGN);
result = getentropy_wrapper_ready_core();
sigaction(SIGSYS,&old_sigsys,0);
return result;
}
void getentropy_wrapper(void *x,long long xbytes)
{
while (xbytes > 0) {
// getentropy fails for >256 bytes
int todo = 256;
if (xbytes < 256) todo = xbytes;
if (getentropy(x,todo) != 0) {
sleep(1);
continue;
}
x += todo;
xbytes -= todo;
}
}
#endif
librandombytes-20240318/kernel/getentropy_wrapper.h 0000644 0000000 0000000 00000000570 14575707635 021111 0 ustar root root #ifndef getentropy_wrapper_h
#define getentropy_wrapper_h
#define getentropy_wrapper_ready randombytes_internal_getentropy_wrapper_ready
#define getentropy_wrapper randombytes_internal_getentropy_wrapper
#ifdef __cplusplus
extern "C" {
#endif
extern int getentropy_wrapper_ready(void);
extern void getentropy_wrapper(void *,long long);
#ifdef __cplusplus
}
#endif
#endif
librandombytes-20240318/kernel/getrandom_wrapper.c 0000644 0000000 0000000 00000003210 14575707635 020656 0 ustar root root // version 20230126
// public domain
// djb
// planned long-term cleanup:
// once all systems support getrandom() via sys/random.h,
// get rid of the other options and the SIGSYS handling
#include
// automatic-alternatives 5
#ifdef getrandom_wrapper_5
#include "getrandom_wrapper.h"
int getrandom_wrapper_ready(void)
{
return 0;
}
void getrandom_wrapper(void *x,long long xbytes)
{
for (;;) pause();
}
#else
#include
#include
#ifdef getrandom_wrapper_1
#include
#endif
#ifdef getrandom_wrapper_2
#include
#endif
#ifdef getrandom_wrapper_3
#include
#define getrandom(a,b,c) syscall(SYS_getrandom,a,b,c)
#endif
#ifdef getrandom_wrapper_4
#include
#define getrandom(a,b,c) syscall(__NR_getrandom,a,b,c)
#endif
#include "getrandom_wrapper.h"
static int getrandom_wrapper_ready_core(void)
{
char ch;
int r;
for (;;) {
errno = 0;
r = getrandom(&ch,1,0);
if (r == 1) return 1;
if (r == -1 && errno == ENOSYS) return 0;
if (r == -1 && errno == EPERM) return 0; // QNAP bug
if (r == -1 && errno == EINVAL) return 0;
}
}
int getrandom_wrapper_ready(void)
{
struct sigaction old_sigsys;
int result;
sigaction(SIGSYS,0,&old_sigsys);
signal(SIGSYS,SIG_IGN);
result = getrandom_wrapper_ready_core();
sigaction(SIGSYS,&old_sigsys,0);
return result;
}
void getrandom_wrapper(void *x,long long xbytes)
{
while (xbytes > 0) {
int todo = 1048576;
if (xbytes < 1048576) todo = xbytes;
todo = getrandom(x,todo,0);
if (todo < 1) {
sleep(1);
continue;
}
x += todo;
xbytes -= todo;
}
}
#endif
librandombytes-20240318/kernel/getrandom_wrapper.h 0000644 0000000 0000000 00000000560 14575707635 020670 0 ustar root root #ifndef getrandom_wrapper_h
#define getrandom_wrapper_h
#define getrandom_wrapper_ready randombytes_internal_getrandom_wrapper_ready
#define getrandom_wrapper randombytes_internal_getrandom_wrapper
#ifdef __cplusplus
extern "C" {
#endif
extern int getrandom_wrapper_ready(void);
extern void getrandom_wrapper(void *,long long);
#ifdef __cplusplus
}
#endif
#endif
librandombytes-20240318/kernel/randombytes.c 0000644 0000000 0000000 00000002213 14575707635 017467 0 ustar root root // version 20230126
// public domain
// djb
// automatic-alternatives 1 getrandom_wrapper.o getentropy_wrapper.o devurandom_wrapper.o
#include
#include "getrandom_wrapper.h"
#include "getentropy_wrapper.h"
#include "devurandom_wrapper.h"
#include "randombytes.h"
static enum {
use_nothing,
use_getrandom,
use_getentropy,
use_devurandom
} use = use_nothing;
__attribute__((constructor))
static void startup(void)
{
if (getrandom_wrapper_ready()) { use = use_getrandom; return; }
if (getentropy_wrapper_ready()) { use = use_getentropy; return; }
if (devurandom_wrapper_ready()) { use = use_devurandom; return; }
}
void randombytes(void *x,long long xbytes)
{
if (use == use_getrandom) { getrandom_wrapper(x,xbytes); return; }
if (use == use_getentropy) { getentropy_wrapper(x,xbytes); return; }
if (use == use_devurandom) { devurandom_wrapper(x,xbytes); return; }
for (;;) pause();
}
const char *randombytes_source(void)
{
if (use == use_getrandom) return "kernel-getrandom";
if (use == use_getentropy) return "kernel-getentropy";
if (use == use_devurandom) return "kernel-devurandom";
return "kernel-nothing";
}
librandombytes-20240318/openssl/ 0000755 0000000 0000000 00000000000 14575707635 015201 5 ustar root root librandombytes-20240318/openssl/randombytes.c 0000644 0000000 0000000 00000001204 14575707635 017671 0 ustar root root // version 20230126
// public domain
// djb
// automatic-alternatives 1 -lcrypto
#include
#include
#include "randombytes.h"
__attribute__((constructor))
static void startup(void)
{
unsigned char x;
while (RAND_bytes(&x,1) != 1)
sleep(1);
}
void randombytes(void *x,long long xbytes)
{
while (xbytes > 0) {
// RAND_bytes takes int length
// assume int is at least 32 bits
int todo = 1048576;
if (xbytes < 1048576) todo = xbytes;
while (RAND_bytes(x,todo) != 1)
sleep(1);
x += todo;
xbytes -= todo;
}
}
const char *randombytes_source(void)
{
return "openssl";
}
librandombytes-20240318/project/ 0000755 0000000 0000000 00000000000 14575707635 015164 5 ustar root root librandombytes-20240318/project/library 0000644 0000000 0000000 00000000014 14575707635 016546 0 ustar root root randombytes
librandombytes-20240318/scripts-build/ 0000755 0000000 0000000 00000000000 14575707635 016302 5 ustar root root librandombytes-20240318/scripts-build/compilealternatives 0000755 0000000 0000000 00000001552 14575707635 022305 0 ustar root root #!/bin/sh
dir="$1"; shift
base="$1"; shift
alternatives="$1"; shift
try=1
(
echo 'int main()'
echo '{'
echo ' return 0;'
echo '}'
) > "$dir/alternatives-$base.c"
scripts/cdcompile "$dir" -fvisibility=hidden -c "alternatives-$base.c"
while [ "$try" -le "$alternatives" ]
do
basetry=${base}_$try
echo "trying $dir $basetry ..."
echo ' ' scripts/cdcompile "$dir" -fvisibility=hidden -I ../include -D "$basetry" -c "$base.c" \
&& scripts/cdcompile "$dir" -fvisibility=hidden -I ../include -D "$basetry" -c "$base.c" \
&& echo ' ' scripts/cdcompile "$dir" -fvisibility=hidden -o "alternatives-$base" "alternatives-$base.o" "$base.o" "$@" \
&& scripts/cdcompile "$dir" -fvisibility=hidden -o "alternatives-$base" "alternatives-$base.o" "$base.o" "$@" \
&& echo "success $dir $basetry" \
&& break
rm -f "$dir/$base.o"
try=`expr "$try" + 1`
done
librandombytes-20240318/scripts-build/compiledefault 0000755 0000000 0000000 00000000213 14575707635 021221 0 ustar root root #!/bin/sh
dir="$1"; shift
base="$1"; shift
ext="$1"; shift
scripts/cdcompile "$dir" \
-fvisibility=hidden \
"$@" \
-c "$base.$ext"
librandombytes-20240318/scripts-build/install 0000755 0000000 0000000 00000001355 14575707635 017702 0 ustar root root #!/usr/bin/env python3
import os
import sys
import shutil
import tempfile
prefix = sys.argv[1]
dirs = 'man/man1','man/man3','lib','include','bin'
install = {}
os.umask(0o22)
for target in dirs:
install[target] = '%s/%s'%(prefix,target)
os.makedirs(install[target],exist_ok=True)
os.umask(0o77)
for target in dirs:
with tempfile.TemporaryDirectory(dir=install[target]) as t:
for fn in sorted(os.listdir('package/'+target)):
try:
shutil.copy2('package/%s/%s' % (target,fn),'%s/%s' % (t,fn),follow_symlinks=False)
except TypeError: # XXX: old python3; should copy symlinks manually
shutil.copy2('package/%s/%s' % (target,fn),'%s/%s' % (t,fn))
os.rename('%s/%s' % (t,fn),'%s/%s' % (install[target],fn))
librandombytes-20240318/scripts-build/sharedlib 0000755 0000000 0000000 00000000355 14575707635 020170 0 ustar root root #!/bin/sh
lib="$1"
shift
so1=`cat scripts/sharedlib-so1`
soname=`cat scripts/sharedlib-soname`
scripts/cdcompile . -shared \
-Wl,-"$soname","$lib"."$so1" \
-o package/lib/"$lib"."$so1" \
"$@"
chmod 644 package/lib/"$lib"."$so1"
librandombytes-20240318/scripts-build/staticlib 0000755 0000000 0000000 00000000226 14575707635 020206 0 ustar root root #!/bin/sh
lib="$1"
shift
rm -f package/lib/"$lib".a
ar cr package/lib/"$lib".a "$@"
ranlib package/lib/"$lib".a || :
chmod 644 package/lib/"$lib".a
librandombytes-20240318/version 0000644 0000000 0000000 00000000011 14575707635 015116 0 ustar root root 20240318