| Module | SecureRandom |
| In: |
lib/compat/securerandom.rb
|
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.
# 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.
# 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.
# 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.
# 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