[前][次][番号順一覧][スレッド一覧]

ruby-changes:2181

From: ko1@a...
Date: 10 Oct 2007 23:37:56 +0900
Subject: [ruby-changes:2181] akr - Ruby:r13672 (ruby_1_8): * lib/securerandom.rb: new file.

akr	2007-10-10 23:37:42 +0900 (Wed, 10 Oct 2007)

  New Revision: 13672

  Added files:
    branches/ruby_1_8/lib/securerandom.rb
  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/NEWS
    branches/ruby_1_8/lib/cgi/session.rb

  Log:
    * lib/securerandom.rb: new file.
    
    * lib/cgi/session.rb (create_new_id): use securerandom if available.


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/cgi/session.rb?r1=13672&r2=13671
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=13672&r2=13671
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/securerandom.rb?revision=13672&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/NEWS?r1=13672&r2=13671

Index: ruby_1_8/NEWS
===================================================================
--- ruby_1_8/NEWS	(revision 13671)
+++ ruby_1_8/NEWS	(revision 13672)
@@ -9,6 +9,10 @@
 
 == Changes with Ruby 1.8.6
 
+=== New library
+
+* securerandom
+
 === Library updates (outstanding ones only)
 
 * openssl
Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 13671)
+++ ruby_1_8/ChangeLog	(revision 13672)
@@ -1,3 +1,9 @@
+Wed Oct 10 23:34:45 2007  Tanaka Akira  <akr@f...>
+
+	* lib/securerandom.rb: new file.
+
+	* lib/cgi/session.rb (create_new_id): use securerandom if available.
+
 Tue Oct  9 01:01:55 2007  Tanaka Akira  <akr@f...>
 
 	* re.c (rb_reg_s_union_m): Regexp.union accepts single
Index: ruby_1_8/lib/cgi/session.rb
===================================================================
--- ruby_1_8/lib/cgi/session.rb	(revision 13671)
+++ ruby_1_8/lib/cgi/session.rb	(revision 13672)
@@ -174,16 +174,22 @@
     # is used internally for automatically generated
     # session ids. 
     def create_new_id
-      require 'digest/md5'
-      md5 = Digest::MD5::new
-      now = Time::now
-      md5.update(now.to_s)
-      md5.update(String(now.usec))
-      md5.update(String(rand(0)))
-      md5.update(String($$))
-      md5.update('foobar')
+      require 'securerandom'
+      begin
+        session_id = SecureRandom.hex(16)
+      rescue NotImplementedError
+        require 'digest/md5'
+        md5 = Digest::MD5::new
+        now = Time::now
+        md5.update(now.to_s)
+        md5.update(String(now.usec))
+        md5.update(String(rand(0)))
+        md5.update(String($$))
+        md5.update('foobar')
+        session_id = md5.hexdigest
+      end
       @new_session = true
-      md5.hexdigest
+      session_id
     end
     private :create_new_id
 
Index: ruby_1_8/lib/securerandom.rb
===================================================================
--- ruby_1_8/lib/securerandom.rb	(revision 0)
+++ ruby_1_8/lib/securerandom.rb	(revision 13672)
@@ -0,0 +1,137 @@
+# = 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
+#
+# == 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 n is not specified, 16 is assumed.
+  # It may be larger in future.
+  #
+  # 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 n is not specified, 16 is assumed.
+  # It may be larger in future.
+  #
+  # 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 n is not specified, 16 is assumed.
+  # It may be larger in future.
+  #
+  # 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]
+      mask |= mask >> 1
+      mask |= mask >> 2
+      mask |= mask >> 4
+      begin
+        rnd = SecureRandom.random_bytes(bin.length)
+        rnd[0] = (rnd[0] & 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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]