
How to Generate Secure Random Numbers in Various Programming Languages - CiPHPerCoder
https://paragonie.com/blog/2016/05/how-generate-secure-random-numbers-in-various-programming-languages
======
sjclemmy
A few years ago I worked for a gift card manufacturer and I was tasked with
creating random PAN numbers for a gift card product for a large high street
retailer (sadly no longer with us). I read up on it and couldn't find any
decent guide as to how to produce CSPRNG - and to be fair, there was very
little information in 'layman' terms about what CS meant in this context. As I
couldn't be certain that any of the software routes available to me were
secure I ended up purchasing this
[http://www.protego.se/](http://www.protego.se/) to generate the random
numbers.

I am not convinced that random numbers were required for the security element
of the gift cards, but I don't believe there were any reports of any
fraudulent activity based on unknown numbers.

Developments in this arena over the last 10 years would have made my job a lot
easier!

~~~
koolba
> I read up on it and couldn't find any decent guide as to how to produce
> CSPRNG - and to be fair, there was very little information in 'layman' terms
> about what CS meant in this context.

When you say "produce CSPRNG" do you mean writing a generator or simply
generating numbers? Nobody[1] should be writing a CSPRNG and app developers
should be using language/OS functions (ex: /dev/urandom).

> As I couldn't be certain that any of the software routes available to me
> were secure I ended up purchasing this
> [http://www.protego.se/](http://www.protego.se/) to generate the random
> numbers.

Wow did you really look at that page and say, " _This is going to be easier
and more secure than using /dev/urandom?_". Reading the rest of the info on
the page,
[http://www.protego.se/trnsup.htm](http://www.protego.se/trnsup.htm), does not
give me a lot of confidence in the product. The explanation page of how it
works is just a bunch of scare info against using a software solution.

[1]: _Okay obviously someone has to do it but you all know what I mean..._

~~~
sjclemmy
I mean just generating the random numbers, not writing a generator. At the
time I only had access to Windows machines, there were no linux boxes on site
and nobody in the company (including me - at the time) knew enough about hack
it yourself linux boxes to know what to do, I'd never even heard of
/dev/random.

The functions available from microsoft were only PRNG and not
Cryptographically Secure (as far as I can remember). Even if they were
'Cryptographically Secure' not having a background in randomness theory makes
it pretty hard to work out what is actually needed.

So faced with uncertainty over using VB6 to produce random numbers and finding
a product that claims to produce truly random numbers I chose to mitigate the
risk by transferring it. If there had been a problem down the line related to
the nature of the randomness of the numbers then I would have had recourse to
the third party vendor that owned the risk.

So in the same way you suggest no-one should write a CSPRNG, I decided that
given my level of knowledge, the documentation available to me and the
uncertainty that created we shouldn't trust ourselves to produce random
numbers for a particular purpose. What if they weren't random enough? What if
someone worked out a way to predict the numbers of cards that had been loaded
with value but were still sat in a warehouse? Massive risk, mitigated for
£150. Now that's value.

~~~
koolba
When you put it against rolling your in VB6, sure it sounds much more
reasonable!

Curious how you interact with a USB device like that in VB6 ... Does it just
appear as a keyboard?

~~~
sjclemmy
Ha ha, no. It was CLI all the way. I generated like a few million numbers as a
text file and put those in a table and called them off.

~~~
koolba
Haha! So random.txt! In that case you could have generated it via /dev/urandom
on a laptop and copied it over :D

------
hamandcheese
Can anyone elaborate on why Ruby's SecureRandom shouldn't be used? I find this
to be rather surprising and discomforting.

~~~
tptacek
It defaults to the OpenSSL userland CSPRNG, if available, because Ruby's
maintainers believe (incorrectly) that urandom is unsafe for key generation.

~~~
brandur
The README of the gem that the article recommends ("sysrandom") provides a
good explanation [1].

And here is the contentious Ruby issue wherein the Ruby core developers insist
on cargo culting according to an outdated man page despite comprehensive
refutation from a number of experienced security engineers [2].

That said, the arguments against OpenSSL seem to be largely theoretical at
this point ("has been a source of vulnerabilities in Ruby ..."), so the
misgivings about `SecureRandom` may be slightly exaggerated.

[1]
[https://github.com/cryptosphere/sysrandom#why](https://github.com/cryptosphere/sysrandom#why)

[2] [https://bugs.ruby-lang.org/issues/9569](https://bugs.ruby-
lang.org/issues/9569)

~~~
Nokinside
Oh man.

There is huge undiscovered land of material for cross-cultural and comparative
research in communication in these developer forums. Ruby and Linux mailing
lists could provide material for number of really interesting studies in many
fields.

Ruby community has hint of Japanese culture: design aesthetics, simplicity,
importance of politeness, saving face and rigidity.

Linux community has hint of Finnish culture: practicality, "pig energy" and
"management by perkele" combined with 80's competitive hacker culture.

~~~
tptacek
This is a case where both the Ruby community _and_ the Linux community are
standing in the way of security.

~~~
Nokinside
What's wrong with random numbers in Linux?

~~~
tptacek
They have a /dev/random interface which (literally) randomly blocks,
disrupting programs, and a man page that instructs the Ruby community to use
/dev/random and not /dev/urandom.

~~~
Nokinside
/dev/random is the blocking pseudorandom number generator in Unix-like
operating systems and it provides only the entropy that can be obtained from
environmental noise. I don't see how it can work any other way.

What is the manpage we are discussing here? I think getrandom(2) and random(4)
are quite good.

~~~
KMag
> /dev/random is the blocking pseudorandom number generator in Unix-like
> operating systems

This is not the behavior on FreeBSD and OS X. On those systems, once a
sufficient amount of entropy is estimated to have been gathered since boot,
/dev/random will not block again.

Linux's /dev/random behavior (1) relies too heavily on accurate estimates of
entropy and (2) implies a simultaneous fundamental mistrust in the ability of
cryptographic methods to expand several hundred bits of entropy into a few
megabytes of data indistinguishable from random noise and yet simultaneous
belief in the strength of cryptographic algorithms for expanding maybe a
kilobit of long-term key material into terabytes of data indistinguishable
from random noise. (The rationale for blocking is to produce better long-term
keys.)

Linux's /dev/random rekeys its internal state at a fixed entropy estimate. If
state is compromised and the estimate is too optimistic, it will never recover
from state compromise. If the estimate is too pessimistic, state is left
vulnerable longer than necessary.

Bruce Schneier and Niels Ferguson's Fortuna for a design is more robust and
consistent. A series of entropy pools all collect entorpy at the same rate,
but are emptied at exponentially longer intervals. Eventually, one of the
pools used to rekey will have enough entropy to recover from state compromise,
and it doesn't rely on the dubious practice of entropy estimation. Now,
estimating how long recovering from state compromise will take requires
estimating entropy, but with a Fortuna construction we can prove that recovery
will eventually happen as long as entropy is actually being collected.

If you're using TLS with AES-GCM, a Fortuna construction built using AES has
an added advantage that an attack that recovers Fortuna state is almost
certainly directly applicable to your TLS setup. In other words, you're
depending on fewer algorithms, the failure of any one of which dooms you.

FreeBSD uses Fortuna for /dev/[u]random. OS X uses Fortuna's predecessor
Yarrow, which still has the weakness of relying on entropy estimation, but at
least it has two pools (one with a pessimistic rekey rate) instead of Linux's
single rekey rate.

~~~
tptacek
The LRNG is fine. It could be faster, and it could be simpler and more
coherent to facilitate formal analysis. But the underlying task that we want
an OS CSPRNG to do is not complicated.

I think it would be a bad idea to forklift out the LRNG in favor of an
entirely new design.

It's possible that all Linux really needs to do is fix the man page, and
perhaps do something in the kernel (rather than in OS distributions) to solve
seed-at-boot.

------
niftich
Some additional requests:

\- Rust (no out-of-the-box crypto lib AFAIK)

\- Erlang (ships-by-default 'crypto' uses openssl)

\- Java 7 and below are, unfortunately, still in common use, despite being
end-of-life. There is a config file to be edited, or a switch to be passed to
the java executable to switch the RNG source away from /dev/random, the pre-8
SecureRandom default.

\- Some obvious note about how client-side Javascript is a lost cause, in case
anybody's tempted

~~~
ilyanep
> Some obvious note about how client-side Javascript is a lost cause, in case
> anybody's tempted

Relevant (from 2011): [https://www.nccgroup.trust/us/about-us/newsroom-and-
events/b...](https://www.nccgroup.trust/us/about-us/newsroom-and-
events/blog/2011/august/javascript-cryptography-considered-harmful/)

~~~
eveningcoffee
Well, actually JavaScript now has secure random number generator. You can use
window.crypto.getRandomValues().

Edit: note that I did not say that other points in that article are
irrelevant.

------
billhathaway
Does Go's crypto/rand[0] package meet this criteria?

[0]
[https://golang.org/src/crypto/rand/rand_linux.go](https://golang.org/src/crypto/rand/rand_linux.go)

~~~
niftich
+1 to this question. If the rand_linux strategy linked above decides to fall
back to rand_unix, it can result in a userspace AES-based generator [1]
running on output from /dev/random

[1]
[https://golang.org/src/crypto/rand/rand_unix.go](https://golang.org/src/crypto/rand/rand_unix.go)

~~~
tptacek
Unless you're on Plan 9, this isn't a concern.

------
avodonosov
In Common Lisp:

    
    
        (ql:quickload :secure-random)
        (secure-random:number 100) => 73
        (secure-random:bytes 20 secure-random:*generator*) => <a simple array with 20 random bytes>
    
    

(This library requires OpenSSL)

~~~
tptacek
A big part of the point of this blog post is _avoiding_ the OpenSSL userland
CSPRNG, which has not proven to be consistently safe. Far better would be the
snippet of Common Lisp that reads random from getrandom(), and then
/dev/urandom.

~~~
zeveb
> Far better would be the snippet of Common Lisp that reads random from
> getrandom(), and then /dev/urandom.

Yup. Here's an example of the latter (I don't have getrandom(2) on my
machine):

    
    
        (defun random-bytes (len)
          (declare (type (integer 1) len))
          (with-open-file (rand "/dev/urandom" :element-type 'unsigned-byte)
            (let ((buf (make-array len :element-type 'unsigned-byte)))
              (read-sequence buf rand)
              buf)))
    

N.b.: I dashed this off quickly. Do not rely on it for security-sensitive
code. Do not bet your life on it.

------
Hello71
on the whole, redefining 'int' in Python is not a great idea:

    
    
        >>> int
        <type 'int'>
        >>> int('10')
        10
        >>> int = 10
        >>> int('10')
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        TypeError: 'int' object is not callable

~~~
0003
Really hurts the article's credibility to intersect cryptographic domain
knowledge with technical programming knowledge. That said, I did learn
something from it, but I'll be doing a bit more research...

------
hackcasual
> Other Unix-like (including OS X): /dev/urandom

Do other OSes ensure there's enough initial entropy to safely use urandom?

~~~
IshKebab
Maybe those implementations block until it is seeded?

~~~
sillysaurus3
urandom by definition doesn't block.

The only time you'd have to worry about this is during boot. Ideally, whatever
you're trying to do at boot time should be moved to post-boot time, when the
kernel has taken care of all the concerns for you.

I don't know what the answer is to "If you want to generate secure random
numbers during boot before urandom is seeded, how would you do it?" I assume
it's "Seed urandom, then use it."

~~~
heinrich5991
I believe it blocks on some BSDs during early boot, when not enough entropy
has been collected, maybe OpenBSD?

~~~
ben_bai
Not on OpenBSD. The bootloader supplies entropy, so that basically as soon as
the kernel starts booting, random numbers are available.

Edit: /dev/random on OpenBSD also does not block.

------
atheg33
Further advancement in secure random number generation across languages will
probably lead to more "don't roll your own crypto" reminder posts in the near
future.

But it's still a great feature to have in every programming language imho.

------
Nursie
\-- edit -- In case it's not clear I really, really agree with this article, I
was having a rant about people I've worked with who make things needlessly
complex, not the link, which is great advice!

Just use /dev/urandom

I can't believe how many crappy engineers I've encountered who are resistant
to this advice. The onpy coherent objection I've ever heard is that "It never
blocs therefore it can provide random numbers with insufficient entropy",
which has been adequately refuted many times now.

But still I encounter experienced, senior guys doing all sorts of Heath-
Robinson crap with reading tons of entropy from TPM chips, feeding it to
openssl or other systems as a seed and using those instead. It's completely
unnecessary adds complexity (which in turn decreases security) and just...

What's really frustrating is people being convinced that random numbers are
hard and therefore that they really need to do all this 'hard' stuff. I guess
it flatters their egos.

~~~
richardwhiuk
It's wrong to use during system startup as it may not have been seeded yet.

~~~
Nursie
That's true, but likely only true during the first ever boot due to entropy
recycling.

~~~
Dylan16807
Or the first boot after you clone the template VM, which could be any boot.

------
jrapdx3
FWIW in Tcl it's fairly easy to generate random numbers from /dev/urandom on
Unix-like systems[0].

It involves opening /dev/urandom, reading 8 bytes from the device, binary scan
of the returned value, converting from the hex format and scaling the result
to fall within a specified min to max range.

The tcllib has other PRNG procedures, and there's the "Random" package ISAAC
implementation. Whether output quality of any of these procedures is adequate
probably depends on the purpose.

[0] [http://tcl.wiki/29163](http://tcl.wiki/29163)

~~~
junke
Reading this story, I was curious about ISAAC, so I posted a link to its
webpage in another post
([https://news.ycombinator.com/item?id=12441451](https://news.ycombinator.com/item?id=12441451)),
hoping people would give their opinion on it. Do you have experience with
ISAAC?

~~~
jrapdx3
That's the same link provided in the Tcl wiki. I haven't actually used the
ISAAC generator since the urandom is considered reliable. However, urandom is
only available on Linux/BSD systems, on Windows alternatives are necessary.

From the comments on the ISAAC home page, the ISAAC and ISAAC-64 versions
would appear adequate for most uses, but a reader more experienced in CSPRNG
analysis might have more information.

------
leeter
The recommendation for windows is hopelessly out of date. On Vista and up
CryptGenRandom is exported directly from Advapi32. That said... just use the
CNG functions (BCryptGenRandom[1]), which is what both RtlGenRandom and
CryptGenRandom use under the covers. BCrypt.dll is going to get loaded either
way.

[1] [https://msdn.microsoft.com/en-
us/library/windows/desktop/aa3...](https://msdn.microsoft.com/en-
us/library/windows/desktop/aa375458\(v=vs.85\).aspx)

------
alrs
An example in Go:

[https://github.com/alrs/radseed](https://github.com/alrs/radseed)

------
steaminghacker
tangential question; does anyone know of a _cheap_ hardware random number
generator for PCs. thanks.

~~~
Sami_Lehtinen
Crappy (free, obsolete) webcam, fm-receiver, tv-receiver + sha512? - Define
cheap.

~~~
chrisseaton
I'm not normally a paranoid person but EM radiation seems like it's something
that it would be easy for someone outside your house in a van to manipulate.

~~~
matt_wulfeck
Discussions about random seed generators usually devolve into theoretical
issues about why <random idea> can be manipulated.

If you're really paranoid, just do this:

$ echo "<bash face against keyboard multiple times>" >> /dev/random

------
FrozenVoid
The best option imho is implementing a modern Xorshift variant in the
language, not depending on runtime/OS.
[http://xoroshiro.di.unimi.it/xoroshiro128plus.c](http://xoroshiro.di.unimi.it/xoroshiro128plus.c)

------
happy-go-lucky
In Python snippet of the blog post, urandom() was used without importing the
os module :)

~~~
CiPHPerCoder
Oops! How did I miss that? Thanks for letting me know.

Fixed, and a bunch of suggested additions are coming later today. :)

------
jonathanstrange
It might be a good idea to additionally check the interface for failure of the
PRNG, e.g. that not all random numbers returned are 0.

------
throwawayReply
I can't help but feel this sums up the difference between these two
ecosystems:

    
    
      Cryptographically Secure Randomness in .NET (C#)
      The generally accepted solution is to use System.Security.Cryptography.RNGCryptoServiceProvider
    
      Cryptographically Secure Randomness in Node.js
      Don't use crypto.randomBytes()
    

An unfair cherry picking perhaps, but an illustrative example.

------
gant
PHP: WordPress, according to Automattic:

[https://api.wordpress.org/secret-
key/1.1/salt](https://api.wordpress.org/secret-key/1.1/salt)

~~~
richardwhiuk
Not sure what your point is here?

~~~
CiPHPerCoder
As of WordPress 4.4.0, wp_rand() is fine.

[https://paragonie.com/blog/2015/10/coming-
wordpress-4-4-cspr...](https://paragonie.com/blog/2015/10/coming-
wordpress-4-4-csprng)

I had already suggested (to Dion Hulse) that this antipattern of pinging
wordpress.org to define the salts during setup be removed in favor of always
generating them locally.

I don't know if/when they'll implement that (no matter what benefits a
security fix might provide, WordPress always prioritizes "no BC breaks even on
0.0001% of the installed base" first), but if you're looking for a more secure
CMS I happen to be building one here:

[https://github.com/paragonie/airship](https://github.com/paragonie/airship)

------
eveningcoffee
As general rule, before you start using language provided secure random number
generator, you should at least informally verify the full chain of the
generator on multiple platforms.

------
mneemonic
I would love to see this explained. TY.

    
    
      import time, sys, random
      
      
      def diorandom(m, n):
        start = time.time()
        for x in range(0, n):
          r = m.randint(0, 2**255)
        elapsed = time.time() - start
        return elapsed
      
      def diorandint(n):
        start = time.time()
        for x in range(0, n):
          r = random.randint(0, 2**255)
        elapsed = time.time() - start
        return elapsed
      
      
      if __name__ == '__main__':
        m = random.SystemRandom()
        modo1 = diorandom(m, 100000)
        modo2 = diorandint(100000)
        print('100,000 iterations')
        print('SystemRandom().randint: {}'.format(modo1))
        print('random.randint: {}'.format(modo2))
    

I actually would know why you didn't simply encouraged random.randint.

~~~
koolba
> I actually would know why you didn't simply encouraged random.randint.

Because it's not secure. Read the big fat warning in pink:
[https://docs.python.org/2/library/random.html](https://docs.python.org/2/library/random.html)

