summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-06-08 05:26:20 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-06-08 05:26:20 +0000
commit94fdd87fddb977ba4a9075a05476bc6fc294b746 (patch)
treeb0f325dbac3f42863e272d4abf46124d593fc3cf /lib
parent250a29cc6be6a40b828b399d230748d02572efda (diff)
* lib/secrand.rb: new file for secure random interface.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12475 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/secrand.rb66
1 files changed, 66 insertions, 0 deletions
diff --git a/lib/secrand.rb b/lib/secrand.rb
new file mode 100644
index 0000000000..8f7bbc6007
--- /dev/null
+++ b/lib/secrand.rb
@@ -0,0 +1,66 @@
+begin
+ require 'openssl'
+rescue LoadError
+end
+
+module SecRand
+ 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
+
+ def self.hex(n=nil)
+ random_bytes(n).unpack("H*")[0]
+ end
+
+ def self.base64(n=nil)
+ [random_bytes(n)].pack("m*").delete("\n")
+ end
+
+end
+
+def SecRand(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 = SecRand.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 = SecRand.random_bytes(8).unpack("Q")[0]
+ Math.ldexp(i64 >> (64-Float::MANT_DIG), -Float::MANT_DIG)
+ end
+end