зеркало из https://github.com/github/ruby.git
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
This commit is contained in:
Родитель
e95eb9584a
Коммит
abae70d6ed
|
@ -1,9 +1,5 @@
|
||||||
# -*- coding: us-ascii -*-
|
# -*- coding: us-ascii -*-
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
begin
|
|
||||||
require 'openssl'
|
|
||||||
rescue LoadError
|
|
||||||
end
|
|
||||||
|
|
||||||
# == Secure random number generator interface.
|
# == Secure random number generator interface.
|
||||||
#
|
#
|
||||||
|
@ -48,8 +44,47 @@ end
|
||||||
#
|
#
|
||||||
|
|
||||||
module SecureRandom
|
module SecureRandom
|
||||||
if defined?(OpenSSL::Random) && /mswin|mingw/ !~ RUBY_PLATFORM
|
@rng_chooser = Mutex.new # :nodoc:
|
||||||
def self.gen_random(n)
|
|
||||||
|
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 = 0 unless defined?(@pid)
|
||||||
pid = $$
|
pid = $$
|
||||||
unless @pid == pid
|
unless @pid == pid
|
||||||
|
@ -63,9 +98,9 @@ module SecureRandom
|
||||||
end
|
end
|
||||||
return OpenSSL::Random.random_bytes(n)
|
return OpenSSL::Random.random_bytes(n)
|
||||||
end
|
end
|
||||||
else
|
|
||||||
def self.gen_random(n)
|
def gen_random_urandom(n)
|
||||||
ret = Random.raw_seed(n)
|
ret = Random.urandom(n)
|
||||||
unless ret
|
unless ret
|
||||||
raise NotImplementedError, "No random device"
|
raise NotImplementedError, "No random device"
|
||||||
end
|
end
|
||||||
|
@ -75,10 +110,6 @@ module SecureRandom
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
|
||||||
alias bytes gen_random
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Random::Formatter
|
module Random::Formatter
|
||||||
|
|
15
random.c
15
random.c
|
@ -603,11 +603,18 @@ random_seed(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq: Random.raw_seed(size) -> string
|
* call-seq: Random.urandom(size) -> string
|
||||||
*
|
*
|
||||||
* Returns a raw seed string, using platform providing features.
|
* Returns a string, using platform providing features.
|
||||||
|
* Returned value expected to be a cryptographically secure
|
||||||
|
* pseudo-random number in binary form.
|
||||||
*
|
*
|
||||||
* Random.raw_seed(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
|
* In 2017, Linux manpage random(7) writes that "no cryptographic
|
||||||
|
* primitive available today can hope to promise more than 256 bits of
|
||||||
|
* security". So it might be questionable to pass size > 32 to this
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* Random.urandom(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
random_raw_seed(VALUE self, VALUE size)
|
random_raw_seed(VALUE self, VALUE size)
|
||||||
|
@ -1616,7 +1623,7 @@ InitVM_Random(void)
|
||||||
rb_define_singleton_method(rb_cRandom, "srand", rb_f_srand, -1);
|
rb_define_singleton_method(rb_cRandom, "srand", rb_f_srand, -1);
|
||||||
rb_define_singleton_method(rb_cRandom, "rand", random_s_rand, -1);
|
rb_define_singleton_method(rb_cRandom, "rand", random_s_rand, -1);
|
||||||
rb_define_singleton_method(rb_cRandom, "new_seed", random_seed, 0);
|
rb_define_singleton_method(rb_cRandom, "new_seed", random_seed, 0);
|
||||||
rb_define_singleton_method(rb_cRandom, "raw_seed", random_raw_seed, 1);
|
rb_define_singleton_method(rb_cRandom, "urandom", random_raw_seed, 1);
|
||||||
rb_define_private_method(CLASS_OF(rb_cRandom), "state", random_s_state, 0);
|
rb_define_private_method(CLASS_OF(rb_cRandom), "state", random_s_state, 0);
|
||||||
rb_define_private_method(CLASS_OF(rb_cRandom), "left", random_s_left, 0);
|
rb_define_private_method(CLASS_OF(rb_cRandom), "left", random_s_left, 0);
|
||||||
|
|
||||||
|
|
|
@ -550,9 +550,9 @@ END
|
||||||
End
|
End
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_raw_seed
|
def test_urandom
|
||||||
[0, 1, 100].each do |size|
|
[0, 1, 100].each do |size|
|
||||||
v = Random.raw_seed(size)
|
v = Random.urandom(size)
|
||||||
assert_kind_of(String, v)
|
assert_kind_of(String, v)
|
||||||
assert_equal(size, v.bytesize)
|
assert_equal(size, v.bytesize)
|
||||||
end
|
end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче