What is the quickest way to generate lots of random data on the command line? Usually when I had to wipe hard-drives I would simply use dd
to copy from /dev/urandom
over the device. However, `/dev/urandom is quite slow and wiping hard-disks can take a long time that way. So, I decided to benchmark a few methods to generate long random streams that are usable in such scenarios.
The benchmark is based on the dd
command. For example:
$ dd if=/dev/urandom of=/dev/null bs=4k count=1M
This command will copy a 4GB of random bytes from /dev/urandom
over /dev/null
. This is probably the simplest method to create a large stream of random bytes, and as it turns out, also the slowest.
The second construct I tried is to use OpenSSL to create a stream of random data which I can read with dd
and then write to the target. For example the following would use AES-128 with a random key:
$ openssl rand -hex 32 | openssl enc -aes-128-ctr -in /dev/zero -pass stdin -nosalt | dd if=/dev/stdin of=/dev/null bs=4k count=1M
Let’s breakup this command: openssl rand -hex 32
will generate a random encryption key to be used by the AES encryption. openssl enc -aes-128-ctr -in /dev/zero -pass stdin -nosalt
does the actual encryption. It reads the (random) key from stdin
and then uses it to encrypt /dev/zero
using AES-128 in counter mode. As /dev/zero
in an endless stream of zeros, it will simply output an endless stream of (pseudo-)random data. We can also repeat the same command only swapping aes-128-ctr
with aes-256-ctr
. For most (all?) usage scenarios it doesn’t provided any added security benefits but does have a (small) performance penalty.
Apart from AES, which is a block cipher, we can also try to use actual stream ciphers like the old rc4
and the modern chacha20
.
Additionally, many new CPUs come with AES-NI extension which speeds up AES operations considerably. We can repeat the benchmark while disabling AES-NI to see how the different methods will perform if used a CPU that doesn’t support AES-NI.
Finally, I’ve repeated the test with /dev/zero
as input, just to have an upper-limit in terms of performance to compare against.
AES-NI | No AES-NI | |
/dev/zero | 0.42609 | |
/dev/urandom | 18.8967 | |
chacha20 | 2.69306 | 3.79217 |
aes-128-ctr | 2.04106 | 14.9022 |
aes-256-ctr | 2.24756 | 18.9014 |
rc4 | 7.77392 |
Conclusions
The results clearly show that you should avoid /dev/urandom
. It’s simply not suitable for this task and doesn’t perform well. The various methods of using OpenSSL perform much better. The best performance is achieved by the two AES variants, with aes-128-ctr
being the fastest. However, if AES-NI is not supported by the CPU, AES takes a huge performance hit, and is even slower than the (not-so-)good and old RC4. However, ChaCha20 (a modern stream cipher) performs within 30% of AES if AES-NI is available, but if AES-NI is not supported ChaCha20 outperforms the AES variants. So, unless you know AES-NI is supported ChaCha20 is the safe choice.