![encryption-on-paper-with-key.jpg]()
First things first - what is a CSPRNG? The acronym stands for Cryptographically Secure Pseudo-Random Number Generator. It is an advanced relative of the PRNG - Pseudo-Random Number Generator. The critical difference between the two being the deterministic nature of the latter algorithm. Typically PRNG will start off from some seed value and then proceed, in a deterministic fashion, to produce "random-looking" bits. It is good enough for statistical experiments in math and physics, but not good enough for cryptography.
This disqualifies the use of Javascript's Math.random() or similar functions in security-sensitive contexts. In cryptocurrency space CSPRNGs are used to generate private keys. For instance, in the Bitcoin protocol, a private key is a 256-bit sequence (or 64 hexadecimal digits) - supposedly derived in a way that cannot be guessed by a malicious attacker. So, how do we get a CSPRNG-compliant random generator?
It turns out to be a pretty easy task on Linux. Open your favorite shell console and paste the following:
cat /dev/urandom | head -n 50 | od -x | cut -b 8-12,14-18 | xargs | sed 's/ //g' | cut -b 1-64
The output of this command should be a string of hex digits that looks something like this:
f421494c6a2f9671717eab46c2f6eccba853e7b11a90818fd8201811a6b8e9d4
Type it again, and you will get a completely different string. There is your private key!
So, let's look under the hood a bit, to see how it works and why it is secure.
/dev/urandom
is a file pointer to the non-blocking binary stream provided by the underlying Linux operating system. This stream serves as an "entropy pool" - a source of randomness formed by the various parts of the state of the operating system at any moment, including device configurations, memory, CPU, time since last reboot, etc. The idea is that it is impossible to reproduce deterministically because there is enough underlying randomness built in to the operating system processes. An attacker can observe thousands of calls to /dev/urandom
without getting any closer to guessing what the next output is going to be. Thus it possesses the critical characteristic of a true CSPRNG. Many higher level programming languages, most notable Java, use the underlying /dev/urandom
to seed their built in cryptographic functions, such as Java's SecureRandom class.
Since /dev/urandom
is a binary stream, calling cat
on it produced lots of gobbledygook on the screen, and in order to parse we first take a 50 line slice of it and run it through od
- octal dump - which can take binary stream and convert it to human readable formats, in our case - hexadecimal. The rest of the magic is about extracting fields from the output with cut
, converting multi-line output into a single line with xargs
, removing spaces with sed
, and, finally extracting a portion of the bytes we are interested in, again using cut
. Voila!