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