Module SecureRandom
In: lib/compat/securerandom.rb
SecureRandom dot/f_0.png

Methods

Public Class methods

SecureRandom.base64 generates a random base64 string.

The argument n specifies the length of the random length. The length of the result string is about 4/3 of n.

If n is not specified, 16 is assumed. It may be larger in future.

If secure random number generator is not available, NotImplementedError is raised.

[Source]

     # File lib/compat/securerandom.rb, line 145
145:     def self.base64(n=nil)
146:       [random_bytes(n)].pack("m*").delete("\n")
147:     end

SecureRandom.hex generates a random hex string.

The argument n specifies the length of the random length. The length of the result string is twice of n.

If n is not specified, 16 is assumed. It may be larger in future.

If secure random number generator is not available, NotImplementedError is raised.

[Source]

     # File lib/compat/securerandom.rb, line 131
131:     def self.hex(n=nil)
132:       random_bytes(n).unpack("H*")[0]
133:     end

SecureRandom.random_bytes generates a random binary string.

The argument n specifies the length of the result string.

If n is not specified, 16 is assumed. It may be larger in future.

If secure random number generator is not available, NotImplementedError is raised.

[Source]

     # File lib/compat/securerandom.rb, line 52
 52:     def self.random_bytes(n=nil)
 53:       n ||= 16
 54: 
 55:       if defined? OpenSSL::Random
 56:         return OpenSSL::Random.random_bytes(n)
 57:       end
 58: 
 59:       if !defined?(@has_urandom) || @has_urandom
 60:         flags = File::RDONLY
 61:         flags |= File::NONBLOCK if defined? File::NONBLOCK
 62:         flags |= File::NOCTTY if defined? File::NOCTTY
 63:         flags |= File::NOFOLLOW if defined? File::NOFOLLOW
 64:         begin
 65:           File.open("/dev/urandom", flags) {|f|
 66:             unless f.stat.chardev?
 67:               raise Errno::ENOENT
 68:             end
 69:             @has_urandom = true
 70:             ret = f.readpartial(n)
 71:             if ret.length != n
 72:               raise NotImplementedError,
 73:                 "Unexpected partial read from random device"
 74:             end
 75:             return ret
 76:           }
 77:         rescue Errno::ENOENT
 78:           @has_urandom = false
 79:         end
 80:       end
 81: 
 82:       if !defined?(@has_win32)
 83:         begin
 84:           require 'Win32API'
 85: 
 86:           crypt_acquire_context = Win32API.new(
 87:             "advapi32", "CryptAcquireContext", 'PPPII', 'L'
 88:           )
 89:           @crypt_gen_random = Win32API.new(
 90:             "advapi32", "CryptGenRandom", 'LIP', 'L'
 91:           )
 92: 
 93:           hProvStr = " " * 4
 94:           prov_rsa_full = 1
 95:           crypt_verifycontext = 0xF0000000
 96: 
 97:           if crypt_acquire_context.call(
 98:               hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
 99:             raise SystemCallError,
100:               "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
101:           end
102:           @hProv, = hProvStr.unpack('L')
103: 
104:           @has_win32 = true
105:         rescue LoadError
106:           @has_win32 = false
107:         end
108:       end
109:       if @has_win32
110:         bytes = " " * n
111:         if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
112:           raise SystemCallError,
113:             "CryptGenRandom failed: #{lastWin32ErrorMessage}"
114:         end
115:         return bytes
116:       end
117: 
118:       raise NotImplementedError, "No random device"
119:     end

SecureRandom.random_number generates a random number.

If an positive integer is given as n, SecureRandom.random_number returns an integer: 0 <= SecureRandom.random_number(n) < n.

If 0 is given or an argument is not given, SecureRandom.random_number returns an float: 0.0 <= SecureRandom.random_number() < 1.0.

[Source]

     # File lib/compat/securerandom.rb, line 158
158:     def self.random_number(n=0)
159:       if 0 < n
160:         hex = n.to_s(16)
161:         hex = '0' + hex if (hex.length & 1) == 1
162:         bin = [hex].pack("H*")
163:         first = bin[0..0]
164:         mask = first.respond_to?(:ord) ? first.ord : first.sum(8)
165:         mask |= mask >> 1
166:         mask |= mask >> 2
167:         mask |= mask >> 4
168:         begin
169:           rnd = SecureRandom.random_bytes(bin.length)
170:           first = rnd[0..0]
171:           ordinal = first.respond_to?(:ord) ? first.ord : first.sum(8)
172:           rnd[0..0] = (ordinal & mask).chr
173:         end until rnd < bin
174:         rnd.unpack("H*")[0].hex
175:       else
176:         # assumption: Float::MANT_DIG <= 64
177:         i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
178:         Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
179:       end
180:     end

[Validate]