Version 17 of Cryptographically secure random numbers using /dev/urandom

Updated 2012-02-15 05:22:51 by potrzebie

Cryptographically secure random numbers are important any time your random numbers are being used in what is meant to be a secure application; for example when generating passwords and cryptographic keys. Tcl's rand is not cryptographically secure. However, Tcllib does offer rc4, a stream cipher that is at its core a pseudo-random number generator. There is also the Random package which uses the ISAAC algorithm; which is considered secure.

These aren't bad solutions, but if you are in a modern Linux based environment your kernel should have support for /dev/random and /dev/urandom. The /dev/random kernel module polls the running system to gather entropy used to generate what are considered true random numbers. The only other true random numbers available to most Tcl applications is, however this service transmits your numbers in the clear which in most instances requiring security is unacceptable.

/dev/random is powerful and mature, and so it only makes sense to take advantage of when available. The counterpart to /dev/random is /dev/urandom, which stands for "unblocked" random. /dev/random is "blocked" meaning when the pool of available entropy is exhausted you must wait until additional entropy is gathered to get new random data. /dev/urandom does not block, and instead will reuse the entropy pool. While this decreases the quality of the randomness over time, it is still considered a cryptographically secure PRNG. What follows is the example of a function that can generate a 64 bit unsigned integer within a range, using /dev/urandom. Note that /dev/random and /dev/urandom are simply treated as files.

proc randInt { min max } {
    set randDev [open /dev/urandom rb]
    set random [read $randDev 8]
    binary scan $random H16 random
    set random [expr {([scan $random %x] % (($max-$min) + 1) + $min)}]
    close $randDev
    return $random

RLE - 2011-12-23 19:55:58 Changed open above to open /dev/urandom in BINARY mode. /dev/urandom returns random binary data and reading from the channel in cooked mode would slightly reduce the available entropy.

bodangly - 2011-12-23 19:55:58

Good catch RLE, I noticed a slight irregularity in the distribution previously and was trying to figure it out. BINARY told me it required permissions to be set so I changed the above code to use "rb" instead. Edit: Whoops. =\ Wiped out the page, led me to rewrite things a bit more succinctly and update the function to accept both a min and max.

nem 2011-12-24: Won't the use of % (mod) also skew the distribution?

RLE (2011-12-24): Try it with "[open /dev/urandom {RDONLY BINARY}]". I left out the "RDONLY" in my last edit. Note also that there is no need to brace quote the constant filename unless the filename contains spaces or characters that are special to the Tcl parser. The name "/dev/urandom" contains nothing special and no spaces.

DKF (2011-12-24): Rewrote to use scan to convert hex to a number, which is more efficient than reparsing an expression. (I don't know whether urandom is of good enough quality that the difference between / and % would matter; I've always used division for this sort of thing myself.)

potrzebie - 2012-02-15 05:22:51

Not sure, but maybe you should do "fconfigure $randDev -buffering none" or the interpreter may read lots of potentially wasted data.