-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* lib/securerandom.rb: renamed from lib/secrand.rb.
suggested by NaHi. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12499 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
- Loading branch information
Showing
3 changed files
with
136 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,9 @@ | ||
2007-06-08 Tanaka Akira <[email protected]> | ||
Sun Jun 10 10:42:04 2007 Tanaka Akira <[email protected]> | ||
|
||
* lib/securerandom.rb: renamed from lib/secrand.rb. | ||
suggested by NaHi. | ||
|
||
Sat Jun 8 06:40:05 2007 Tanaka Akira <[email protected]> | ||
|
||
* lib/secrand.rb: rename SecRand() to SecRand.random_number. | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# = Secure random number generator interface. | ||
# | ||
# This library is a interface for secure random number generator which is | ||
# suitable for HTTP cookies, nonces, etc. | ||
# | ||
# It supports following secure random number generators. | ||
# | ||
# * openssl | ||
# * /dev/urandom | ||
# | ||
# == 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" | ||
# ... | ||
|
||
begin | ||
require 'openssl' | ||
rescue LoadError | ||
end | ||
|
||
module SecureRandom | ||
# SecureRandom.random_bytes generates a random binary string. | ||
# | ||
# The argument n specifies the length of the result string. | ||
# | ||
# If secure random number generator is not available, | ||
# NotImplementedError is raised. | ||
def self.random_bytes(n=nil) | ||
n ||= 16 | ||
if defined? OpenSSL::Random | ||
return OpenSSL::Random.random_bytes(n) | ||
end | ||
if !defined?(@has_urandom) || @has_urandom | ||
@has_urandom = false | ||
flags = File::RDONLY | ||
flags |= File::NONBLOCK if defined? File::NONBLOCK | ||
flags |= File::NOCTTY if defined? File::NOCTTY | ||
flags |= File::NOFOLLOW if defined? File::NOFOLLOW | ||
begin | ||
File.open("/dev/urandom", flags) {|f| | ||
unless f.stat.chardev? | ||
raise Errno::ENOENT | ||
end | ||
@has_urandom = true | ||
ret = f.readpartial(n) | ||
if ret.length != n | ||
raise NotImplementedError, "Unexpected partial read from random device" | ||
end | ||
return ret | ||
} | ||
rescue Errno::ENOENT | ||
raise NotImplementedError, "No random device" | ||
end | ||
end | ||
raise NotImplementedError, "No random device" | ||
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 secure random number generator is not available, | ||
# NotImplementedError is raised. | ||
def self.hex(n=nil) | ||
random_bytes(n).unpack("H*")[0] | ||
end | ||
|
||
# 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 secure random number generator is not available, | ||
# NotImplementedError is raised. | ||
def self.base64(n=nil) | ||
[random_bytes(n)].pack("m*").delete("\n") | ||
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. | ||
def self.random_number(n=0) | ||
if 0 < n | ||
hex = n.to_s(16) | ||
hex = '0' + hex if (hex.length & 1) == 1 | ||
bin = [hex].pack("H*") | ||
mask = bin[0].ord | ||
mask |= mask >> 1 | ||
mask |= mask >> 2 | ||
mask |= mask >> 4 | ||
begin | ||
rnd = SecureRandom.random_bytes(bin.length) | ||
rnd[0] = (rnd[0].ord & mask).chr | ||
end until rnd < bin | ||
rnd.unpack("H*")[0].hex | ||
else | ||
# assumption: Float::MANT_DIG <= 64 | ||
i64 = SecureRandom.random_bytes(8).unpack("Q")[0] | ||
Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG) | ||
end | ||
end | ||
end |