random_bytes(n=nil)
public
# File lib/securerandom.rb, line 50
def self.random_bytes(n=nil)
n = n ? n.to_int : 16
if defined? OpenSSL::Random
@pid = 0 unless defined?(@pid)
pid = $$
unless @pid == pid
now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
ary = [now, @pid, pid]
OpenSSL::Random.random_add(ary.join("").to_s, 0.0)
@pid = pid
end
return OpenSSL::Random.random_bytes(n)
end
if !defined?(@has_urandom) || @has_urandom
flags = File::RDONLY
flags |= File::NONBLOCK if defined? File::NONBLOCK
flags |= File::NOCTTY if defined? File::NOCTTY
begin
File.open("/dev/urandom", flags) {|f|
unless f.stat.chardev?
raise Errno::ENOENT
end
@has_urandom = true
ret = f.read(n)
unless ret.length == n
raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
end
return ret
}
rescue Errno::ENOENT
@has_urandom = false
end
end
unless defined?(@has_win32)
begin
require 'Win32API'
crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
@crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'VIP', 'L')
hProvStr = " " * DL::SIZEOF_VOIDP
prov_rsa_full = 1
crypt_verifycontext = 0xF0000000
if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
end
type = DL::SIZEOF_VOIDP == DL::SIZEOF_LONG_LONG ? 'q' : 'l'
@hProv, = hProvStr.unpack(type)
@has_win32 = true
rescue LoadError
@has_win32 = false
end
end
if @has_win32
bytes = " ".force_encoding("ASCII-8BIT") * n
if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
end
return bytes
end
raise NotImplementedError, "No random device"
end