Random numbers from /dev/urandom in Bash
In a GNU/Linux distributions, there are special files (/dev/random
and
/dev/urandom
) to access the kernel’s random number generator. But how
do we get random numbers from them in a bash script?
If we try to cat
them we get random things:
$ cat /dev/random
XB>7;Mq'\'$,dH՞ՈT=H}0]eS19Ѡ
Hd9)7ܢVO'y.ۧMW^C
Something a bit weirder happens with /dev/urandom
: it continues vomiting
characters really fast at you until you stop it with Ctrl + C
.
What’s the difference between /dev/random
and /dev/urandom
? Lets check the
manpage for random (4)
, as of Linux 5.6:
The random number generator gathers environmental noise from device driv‐
ers and other sources into an entropy pool. The generator also keeps an
estimate of the number of bits of noise in the entropy pool. From this
entropy pool, random numbers are created.
When read, the /dev/urandom device returns random bytes using a pseudoran‐
dom number generator seeded from the entropy pool. Reads from this device
do not block (i.e., the CPU is not yielded), but can incur an appreciable
delay when requesting large amounts of data.
The /dev/random device is a legacy interface which dates back to a time
where the cryptographic primitives used in the implementation of
/dev/urandom were not widely trusted. It will return random bytes only
within the estimated number of bits of fresh noise in the entropy pool,
blocking if necessary. /dev/random is suitable for applications that need
high quality randomness, and can afford indeterminate delays.
When the entropy pool is empty, reads from /dev/random will block until
additional environmental noise is gathered. (...)
From this, we get that:
- the Kernel maintains a pool of entropy from random things that happens in the computer.
- both special files use this entropy pool to seed a PRNG.
/dev/random
waits until there are enough randomness to output something./dev/urandom
is preferred.- both files gives us bytes.
And from the Kernel’s source we get that urandom
uses
ChaCha20 as CSPRNG.
1
We now need a tool to read a specific number of bytes from those files and
convert it to something human readable. And here comes od
, a Unix
command to display data in several formats.2 The default is octal, hence the
name od
: octal dump.
With this utility we can read N
bytes from a file and display it in a
specified format. For example, here’s the dump of `Hello World“:
$ echo Hello World | od
0000000 062510 066154 020157 067527 066162 005144
0000014
The first column is the offset, and then the octal representation of that line.
So, the second line of the output means: starting at the offset 0000014
we
have nothing, i.g. there are 14 (in octal, or 12 in decimal) characters in that
string.
It looks like od
does not know how to count. There are 11 chars in Hello World
! Lets see each char individually (-c
) in octal (-b
):
$ echo "Hello World" | od -cb
0000000 H e l l o W o r l d \n
110 145 154 154 157 040 127 157 162 154 144 012
0000014
Sweet, it counted the line ending as well.
od
can also read N
bytes from a source and display it in a specified
format. So, to read 4 bytes from /dev/urandom
, display it as an unsigned
integer without the offset column:
$ od -vAn -N4 -t u4 < /dev/urandom
402803061
And to use in your bash code:
for i in $(seq 1 10)
do
random=$(od -vAn -N4 -t u4 < /dev/urandom)
echo $random
done
With this code, those 32 bits (4 bytes) from urandom
are interpreted as an
integer. How do we get floats? If interested only in the range [0, 1)
: simply
divide by the greatest possible value, \( 2^{32} - 1\).
Footnotes: