When using random numbers in Bash, the question of random entropy will sooner or later come up. This article will help you understand what entropy is, how it can be modified and optimized in Bash, and how it will affect random number generation.
In this tutorial you will learn:
- How to generate random entropy in Bash
- How to pre-seed the random number generator in Bash
- Examples demonstrating random entropy generation in Bash
Software requirements and conventions used
Category | Requirements, Conventions or Software Version Used |
---|---|
System | Linux Distribution-independent |
Software | Bash command line, Linux based system |
Conventions | # – requires linux-commands to be executed with root privileges either directly as a root user or by use of sudo command$ – requires linux-commands to be executed as a regular non-privileged user |
Example 1: Random, or not so random?
We can easily generate a random number in Bash:
$ echo $RANDOM 13
However, whilst this number looks random, it is in fact not, or at best pseudo-random. This is because a computer can in and by itself never be truly random, and the random number generator in Bash is pre-seeded with a value, which determines all subsequent calls of the $RANDOM
variable/function.
Let’s pre-seed the random number generator in a few different ways. We’ll start off by pre-seeding the random generator with seed ‘1’ by setting RANDOM
to 1
:
$ echo $RANDOM 25552 $ RANDOM=1 $ echo $RANDOM 16807 $ RANDOM=1 $ echo $RANDOM 16807 $ echo $RANDOM 15089 $ RANDOM=1 $ echo $RANDOM 16807 $ echo $RANDOM 15089 $ RANDOM=a $ echo $RANDOM 20034
Note that the 16807
and secondary-call 15089
results remain the same while the random generator was pre-seeded with 1
. It changes when pre-seeded with a
.
Whilst the $RANDOM
variable in Bash will always yield a random number generated by the Bash random number generator, it is also a variable which, when set, pre-seeds the random generator. The challenge is that if the seed is the same, the outcome (and sequence!) will also be the same, as you can see from studying the above example.
How the random generator is initialized in your system may depend on the Linux or Unix operating system in use, hardware used, and configuration settings. Let’s immediately agree it is not a very secure way to generate a true/real random number, hence the terms pseudo-random and pseudo-randomness. That said, much can be done to make it (much) better.
Example 2: Our own random entropy generator
The only input which is available to the random generator is basically the seed as passed to RANDOM=
. So how can we come up with a truly random seed to seed the random generator, and create real random entropy (entropy: the quality of lack of predictability)? Random entropy is important, especially in the field of computer security.
Think about this question; how can you provide (to Bash) the most random input to use as a seed for random entropy generation?
I believe I have found a solution in the following code:
$ date +%s%N 1593785871313595555 # |--------| < Selected part indicated $ date +%s%N | cut -b10-19 4418322030 $ date +%s%N | cut -b10-19 4914627208 $ date +%s%N | cut -b10-19 5282934388 $ date +%s%N | cut -b10-19 5635463163 $ date +%s%N | cut -b10-19 5967700148 $ date +%s%N | cut -b10-19 6322917009 $ RANDOM=$(date +%s%N | cut -b10-19) $ echo $RANDOM 16349 $ RANDOM=$(date +%s%N | cut -b10-19) $ echo $RANDOM 9713
The final 9713
result is almost truly random.
date +%s%N
is a combination of %s
which is the seconds since 1970-01-01 00:00:00 UTC – quite a unique number, but still something which could potentially be re-calculated. And %N
is nanoseconds. Then we slice the input to grab only the last 10 digits.
This means we are passing the second (last 0-9
digit) + the full exact nanosecond 000000000-999999999
to the random generator as a seed. This would be as good as impossible to reconstruct, unless you capture the value generated before assigning it. Almost truly random.
This also means you can get a semi-random number of x digits by simply selecting the most granular part of the microsecond:
date +%s%N | cut -b19-19 date +%s%N | cut -b18-19 date +%s%N | cut -b17-19
The first command will produce 1 digit, the second 2 digits etc.
However, the longer your cut
slice becomes (by increasing the cut
length), the less pseudo-random the number will be, especially once you slice into the seconds part. You could also leave off the %s
, and reduce the cut size to have a less intensive system call. Whilst it may not matter for a single call of $RANDOM
, it would matter if it was called hundreds of thousands of times.
Conclusion
In this article, we saw how to generate random entropy, in a reasonably random way. Whilst no random entropy generator is perfect (and therefore any random number resulting from it), we came close by calling on nanosecond time. We also saw how pre-seeding the random generator entropy variable with a specific seed will subsequently yield the same outcomes whenever a random number is generated using the $RANDOM
variable.
Update your scripts with our random entropy initializer, or let us know if you discovered a better one in the comments below. Who else is interested in better entropy?!
Enjoy!