Module ActiveSupport::SecureRandom
In: vendor/rails/activesupport/lib/active_support/secure_random.rb

Secure random number generator interface.

This library is an interface for secure random number generator which is suitable for generating session key in HTTP cookies, etc.

It supports following secure random number generators.

  • openssl
  • /dev/urandom
  • Win32

Note: This module is based on the SecureRandom library from Ruby 1.9, revision 18786, August 23 2008. It‘s 100% interface-compatible with Ruby 1.9‘s SecureRandom library.

Example

 # random hexadecimal string.
 p SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
 p SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
 p SecureRandom.hex(11) #=> "6aca1b5c58e4863e6b81b8"
 p SecureRandom.hex(12) #=> "94b2fff3e7fd9b9c391a2306"
 p SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
 ...

 # random base64 string.
 p SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
 p SecureRandom.base64(10) #=> "9b0nsevdwNuM/w=="
 p SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
 p SecureRandom.base64(11) #=> "l7XEiFja+8EKEtY="
 p SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
 p SecureRandom.base64(13) #=> "vKLJ0tXBHqQOuIcSIg=="
 ...

 # random binary string.
 p SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
 p SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
 ...

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 vendor/rails/activesupport/lib/active_support/secure_random.rb, line 149
149:       def self.base64(n=nil)
150:         [random_bytes(n)].pack("m*").delete("\n")
151:       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 vendor/rails/activesupport/lib/active_support/secure_random.rb, line 135
135:       def self.hex(n=nil)
136:         random_bytes(n).unpack("H*")[0]
137:       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 vendor/rails/activesupport/lib/active_support/secure_random.rb, line 64
 64:       def self.random_bytes(n=nil)
 65:         n ||= 16
 66: 
 67:         if defined? OpenSSL::Random
 68:           return OpenSSL::Random.random_bytes(n)
 69:         end
 70: 
 71:         if !defined?(@has_urandom) || @has_urandom
 72:           flags = File::RDONLY
 73:           flags |= File::NONBLOCK if defined? File::NONBLOCK
 74:           flags |= File::NOCTTY if defined? File::NOCTTY
 75:           flags |= File::NOFOLLOW if defined? File::NOFOLLOW
 76:           begin
 77:             File.open("/dev/urandom", flags) {|f|
 78:               unless f.stat.chardev?
 79:                 raise Errno::ENOENT
 80:               end
 81:               @has_urandom = true
 82:               ret = f.readpartial(n)
 83:               if ret.length != n
 84:                 raise NotImplementedError, "Unexpected partial read from random device"
 85:               end
 86:               return ret
 87:             }
 88:           rescue Errno::ENOENT
 89:             @has_urandom = false
 90:           end
 91:         end
 92: 
 93:         if !defined?(@has_win32)
 94:           begin
 95:             require 'Win32API'
 96: 
 97:             crypt_acquire_context = Win32API.new("advapi32", "CryptAcquireContext", 'PPPII', 'L')
 98:             @crypt_gen_random = Win32API.new("advapi32", "CryptGenRandom", 'LIP', 'L')
 99: 
100:             hProvStr = " " * 4
101:             prov_rsa_full = 1
102:             crypt_verifycontext = 0xF0000000
103: 
104:             if crypt_acquire_context.call(hProvStr, nil, nil, prov_rsa_full, crypt_verifycontext) == 0
105:               raise SystemCallError, "CryptAcquireContext failed: #{lastWin32ErrorMessage}"
106:             end
107:             @hProv, = hProvStr.unpack('L')
108: 
109:             @has_win32 = true
110:           rescue LoadError
111:             @has_win32 = false
112:           end
113:         end
114:         if @has_win32
115:           bytes = " " * n
116:           if @crypt_gen_random.call(@hProv, bytes.size, bytes) == 0
117:             raise SystemCallError, "CryptGenRandom failed: #{lastWin32ErrorMessage}"
118:           end
119:           return bytes
120:         end
121: 
122:         raise NotImplementedError, "No random device"
123:       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 vendor/rails/activesupport/lib/active_support/secure_random.rb, line 162
162:       def self.random_number(n=0)
163:         if 0 < n
164:           hex = n.to_s(16)
165:           hex = '0' + hex if (hex.length & 1) == 1
166:           bin = [hex].pack("H*")
167:           mask = bin[0]
168:           mask |= mask >> 1
169:           mask |= mask >> 2
170:           mask |= mask >> 4
171:           begin
172:             rnd = SecureRandom.random_bytes(bin.length)
173:             rnd[0] = rnd[0] & mask
174:           end until rnd < bin
175:           rnd.unpack("H*")[0].hex
176:         else
177:           # assumption: Float::MANT_DIG <= 64
178:           i64 = SecureRandom.random_bytes(8).unpack("Q")[0]
179:           Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
180:         end
181:       end

[Validate]