diff options
author | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-01-20 08:00:00 +0000 |
---|---|---|
committer | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2017-01-20 08:00:00 +0000 |
commit | abae70d6ed63054d7d01bd6cd80c1b5b98b93ba3 (patch) | |
tree | 3de590fcf8f22217987675fbc5eea399597c8fca /lib/securerandom.rb | |
parent | e95eb9584ac85b728734d77e07fa27f23c91f38d (diff) |
SecureRandom should try /dev/urandom first [Bug #9569]
* random.c (InitVM_Random): rename Random.raw_seed to
Random.urandom. A quick search seems there are no practical use
of this method than securerandom.rb so I think it's OK to rename
but if there are users of it, this hunk is subject to revert.
* test/ruby/test_rand.rb (TestRand#test_urandom): test for it.
* lib/securerandom.rb (SecureRandom.gen_random): Prefer OS-
provided CSPRNG if available. Otherwise falls back to OpenSSL.
Current preference is:
1. CSPRNG routine that the OS has; one of
- getrandom(2),
- arc4random(3), or
- CryptGenRandom()
2. /dev/urandom device
3. OpenSSL's RAND_bytes(3)
If none of above random number generators are available, you
cannot use this module. An exception is raised that case.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57384 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/securerandom.rb')
-rw-r--r-- | lib/securerandom.rb | 57 |
1 files changed, 44 insertions, 13 deletions
diff --git a/lib/securerandom.rb b/lib/securerandom.rb index 9201c9337a..3f8845ea38 100644 --- a/lib/securerandom.rb +++ b/lib/securerandom.rb @@ -1,9 +1,5 @@ # -*- coding: us-ascii -*- # frozen_string_literal: true -begin - require 'openssl' -rescue LoadError -end # == Secure random number generator interface. # @@ -48,8 +44,47 @@ end # module SecureRandom - if defined?(OpenSSL::Random) && /mswin|mingw/ !~ RUBY_PLATFORM - def self.gen_random(n) + @rng_chooser = Mutex.new # :nodoc: + + class << self + def bytes(n) + return gen_random(n) + end + + def gen_random(n) + ret = Random.urandom(n) + if ret.nil? + begin + require 'openssl' + rescue NoMethodError + raise NotImplementedError, "No random device" + else + @rng_chooser.synchronize do + class << self + remove_method :gen_random + alias gen_random gen_random_openssl + end + end + return gen_random(n) + end + elsif ret.length != n + raise NotImplementedError, \ + "Unexpected partial read from random device: " \ + "only #{ret.length} for #{n} bytes" + else + @rng_chooser.synchronize do + class << self + remove_method :gen_random + alias gen_random gen_random_urandom + end + end + return gen_random(n) + end + end + + private + + def gen_random_openssl(n) @pid = 0 unless defined?(@pid) pid = $$ unless @pid == pid @@ -63,9 +98,9 @@ module SecureRandom end return OpenSSL::Random.random_bytes(n) end - else - def self.gen_random(n) - ret = Random.raw_seed(n) + + def gen_random_urandom(n) + ret = Random.urandom(n) unless ret raise NotImplementedError, "No random device" end @@ -75,10 +110,6 @@ module SecureRandom ret end end - - class << self - alias bytes gen_random - end end module Random::Formatter |