From: xkernigh@... Date: 2016-05-09T04:57:23+00:00 Subject: [ruby-core:75411] [Ruby trunk Bug#9569] SecureRandom should try /dev/urandom first Issue #9569 has been updated by George Koehler. I made myself a benchmark: https://gist.github.com/kernigh/d169895a700c6511d08511c005a28d88 RAND_bytes() from OpenSSL seems to be faster than /dev/urandom on my computer. I'm running OpenBSD, and OpenSSL is really LibreSSL. At first it seems that /dev/urandom is just as fast as RAND_bytes(): ~~~ $ ruby -v ruby 2.4.0dev (2016-05-05 trunk 54913) [x86_64-openbsd5.9] $ ruby benchrand.rb user system total real Random::DEFAULT 0.410000 0.190000 0.600000 ( 0.597455) /dev/urandom 0.000000 1.340000 1.340000 ( 1.395878) arc4random_buf 1.210000 0.160000 1.370000 ( 1.373183) RAND_bytes 1.160000 0.260000 1.420000 ( 1.508660) gnutls_rnd NONCE 0.810000 0.180000 0.990000 ( 0.988610) gnutls_rnd RANDOM 1.940000 0.210000 2.150000 ( 2.147149) gnutls_rnd KEY 2.010000 0.140000 2.150000 ( 2.147888) PK11_GenerateRandom 4.030000 0.230000 4.260000 ( 4.266837) ~~~ But if I run two instances in parallel on my dual-core machine: ~~~ $ for i in 1 2; do xterm -hold -e ruby benchrand.rb& done ~~~ then /dev/urandom is suddenly much slower: ~~~ user system total real Random::DEFAULT 0.450000 0.250000 0.700000 ( 0.706498) /dev/urandom 0.000000 2.470000 2.470000 ( 2.549602) arc4random_buf 1.260000 0.530000 1.790000 ( 1.838425) RAND_bytes 1.210000 0.470000 1.680000 ( 1.795881) gnutls_rnd NONCE 0.840000 0.450000 1.290000 ( 1.335806) gnutls_rnd RANDOM 1.960000 0.430000 2.390000 ( 2.440970) gnutls_rnd KEY 1.960000 0.440000 2.400000 ( 2.434435) PK11_GenerateRandom 4.070000 0.410000 4.480000 ( 4.535968) ~~~ Seems that /dev/urandom on OpenBSD doesn't scale to multiple cores. So switching from RAND_bytes() to /dev/urandom would be bad idea. The other generators scale better: they are arc4random_buf() from libc, RAND_bytes() from LibreSSL, gnutls_rnd() from GnuTLS, and PK11_GenerateRandom() from NSS. In OpenBSD, RAND_bytes() seems to call arc4random_buf(), so their times are similar. I know that RAND_bytes() is different between OpenSSL and LibreSSL, and arc4random_buf() is different in other BSDs. My benchmark is for 256 MB of random data. Real programs might not need so much randomness. PK11_GenerateRandom() imposes a limit of 65536 bytes per call, but this seems enough for NSS users like Firefox. So my benchmark might not be realistic. Ruby has been avoiding /dev/urandom if possible. Ruby trunk works as Delan Azabani wrote in #9569-29, with one addition: as of a few days ago, fill_random_bytes_syscall() now tries arc4random_buf() first. So SecureRandom tries in order RAND_bytes(), arc4random_buf(), CryptGenRandom(), getrandom() before /dev/urandom. ---------------------------------------- Bug #9569: SecureRandom should try /dev/urandom first https://bugs.ruby-lang.org/issues/9569#change-58534 * Author: Corey Csuhta * Status: Rejected * Priority: Normal * Assignee: ruby-core * ruby -v: * Backport: ---------------------------------------- Right now, `SecureRandom.random_bytes` tries to detect an OpenSSL to use before it tries to detect `/dev/urandom`. I think it should be the other way around. In both cases, you just need random bytes to unpack, so SecureRandom could skip the middleman (and [second point of failure](http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/)) and just talk to `/dev/urandom` directly if it's available. Is this a case of just re-ordering the two code chunks so that `/dev/urandom` is tried first? Relevant lines: https://github.com/ruby/ruby/blob/trunk/lib/securerandom.rb#L59-L90 -- https://bugs.ruby-lang.org/ Unsubscribe: