Edit: The obviousness was blinding so I missed it. OpenSSL already offers an interface to its own internal PRNG, which is seeded with the machine's /dev/urandom
, but then extends it with its own crypto. Just do this:
openssl rand 10000000
to produce 10 millions of pseudo-random bytes. On my laptop, this appears to be about 3 times faster than /dev/urandom
, i.e. 11 MByte/s or so. If this is not fast enough for you, read on.
Original response:
It really depends on the involved hardware and context. Since you are talking about a bash script, /dev/urandom
and OpenSSL, I suppose that:
- You use Linux.
- You want to produce a big file full of pseudorandom bytes.
- You want a solution which is a scripted assembly of existing, "normal" packages, not a programmatic solution.
Indeed, if you could write your own C code, your best options would be either AES encryption in CTR mode with the AES-NI instructions (on recent PC which offer these instruction), or a dedicated stream cipher (e.g. one of these). On a 2.4 GHz Core2 CPU, I could get 700 MByte/s of pseudorandom bytes out of Sosemanuk. I hereafter suppose that you are limited to scripts.
Using OpenSSL encryption is not a bad idea, but there are details:
- Randomizing the length of each chunk is a useless complication.
- There is no need to go to AES-256; AES-128 is already fine. AES-256 is 40% slower than AES-128, and adds no practical improvement in security.
- When encrypting a long sequence of zeros with CBC, you are actually running the block cipher in OFB mode (encrypt a block, encrypt it again, and again, and again). This is reasonable as long as you remain below the 2n/2 limit, meaning that with AES (128-bit blocks) you don't use a chunk longer than 264 16-byte blocks, i.e. 250 millions of terabytes. Chances are that you won't reach it anyway. In that sense, the "reseeding" is not really needed.
- When you "reseed" (if you decide to maintain this feature, which is not necessary), use
/dev/urandom
, not /dev/random
. /dev/urandom
is fine for cryptography (the OS boot scripts ensure that the internal PRNG is properly seeded), despite the misguided paranoid qualms of the /dev/random
implementation. On the other hand, /dev/random
may block, and thus be really slow (nothing is slower than a blocked process).
- Beware of strings.
bash
uses character strings; /dev/random
and /dev/urandom
return bytes, including bytes of value 0. This may result in an artificially truncated key, and lowered security. This is bad. Instead, you should encode the bytes in hexadecimal and the the -K
and -iv
command-line arguments with openssl
.
- OpenSSL may add a header which begins with 8 fixed bytes (thus totally non-random). It does not do so if you use
-K
and -iv
.
- OpenSSL will also use some padding so you will get an extra 16-byte block at the end (this is not a problem; the padding is on the cleartext, and encryption "randomizes" it).
This leads to the following script:
#!/bin/sh
key=$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | md5sum | cut -d' ' -f1)
iv=$(dd if=/dev/urandom bs=16 count=1 2>/dev/null | md5sum | cut -d' ' -f1)
dd if=/dev/zero bs=65536 count=8192 2>/dev/null | openssl aes-128-cbc -K $key -iv $iv
When invoked, this script outputs a sequence of exactly 536870928 pseudorandom bytes, which are fit for cryptographic purposes. Feel free to modify the bs
and count
parameters, but remember that dd
will allocate a RAM buffer of size bs
, so you usually want to keep bs
small, but not too small to avoid too many roundtrips into the kernel (8192 to 65536 are usually good values).
I use MD5 here only for the convenience of the bytes-to-hexadecimal conversion (the known shortcomings of MD5 have no influence whatsoever on the security in this case).
This script should work on any decent Linux installation. It uses only packages which should be there by default. On my not-very-powerful laptop, this script produces pseudorandom bytes at the rate of 73 MBytes per second, which is not bad and probably enough for your purposes (if that is not enough, then you will probably have other issues with I/O bottlenecks).
x * x | 5
.