Wednesday, February 24, 2021

CSPRNG: A Linux One-Liner


What is a CSPRNG?  

A CSPRNG is a Cryptographically Secure Pseudo Random Number Generator.  It is the cousin of the RNG, or Random Number Generator that we used decades ago.

In the past, rand and seed were used together to generate pseudo random numbers.  When a constant seed is provided (e.g., the number 125), the random numbers generated by rand are well-defined.  

These two functions actually complement each other well in fuzz-testing applications, since the sequence of randomness can be reproduced between invocations of the tool.

However, there's a problem: these functions are not viable for creating key material.  In cryptography, well-formed randomness is required.  As such, rand and seed are not candidates for generating key material.  What is needed is a source of randomness that mimics the real world: such as the path a leaf takes when falling to the ground.

In the cryptography discipline, CSPRNGs are used to generate private and public key material, such as those used for certificates, secure shell sessions, and cryptocurrency. 

Can I generate my own CSPRNG on Linux, using a shell?

Yes.  It turns that on Linux, it's a very easy task.

Every (or almost every) recent Linux implementation generates random data that can be accessed through /dev/random, /dev/arandom, and /dev/urandom.  There are differences between these implementations that you should be aware of when selecting them for any variety of solutions.  See here for more information: /dev/random vs /dev/urandom and are they secure?

For this example, we will use /dev/urandom.

The easiest method of obtaining random data is via cat.  We'll follow that by extracting a set number of bits, reformatting the data, and delivering a string of hexadecimal digits. 

The One-Liner:

cat /dev/urandom | head -c 2048| od -x | cut -b 8-40 | xargs | sed 's/ //g' | head -c 32

In this script, we grab 2048 characters of data (16384 bits), convert them to hexadecimal using od, and then grab the hex digits using cut, while removing the line-feeds.  We remove the spaces created by od, and then select a string of 32 bytes, which is 256 bits (32 x 8 == 256).

If you want a bit more sophistication, then here's a full script:

#   =================================================================
#   File    :
#   Function:   Generate a cryptographically secure random number
#   Who     :   David Means <>
#   =================================================================

function doHelp()
    echo "Generate a cryptographically secure random number"
    echo "Usage: $(basename $0) {bits}"
    echo "Example: $(basename $0) 128"

if [ $# -eq 0 ] ; then

bitCheck=$(($1 % 8))

if [ $bitCheck -eq 0 ]; then
    bytes=$(($1 / 8))
     cat /dev/urandom | head -c 2048 | od -x | cut -b 8-40 | xargs | sed 's/ //g' | head -c ${bytes}
    echo "$1 not divisable by 8"