2014-11-08 20:31:05 -05:00
|
|
|
# -*- coding: us-ascii -*-
|
2015-11-10 06:48:14 -05:00
|
|
|
# frozen_string_literal: true
|
2013-05-20 07:37:04 -04:00
|
|
|
|
2021-12-05 07:53:35 -05:00
|
|
|
require 'random/formatter'
|
|
|
|
|
2013-05-20 07:37:04 -04:00
|
|
|
# == Secure random number generator interface.
|
2007-06-09 21:42:51 -04:00
|
|
|
#
|
2015-01-02 01:36:00 -05:00
|
|
|
# This library is an interface to secure random number generators which are
|
|
|
|
# suitable for generating session keys in HTTP cookies, etc.
|
2007-06-09 21:42:51 -04:00
|
|
|
#
|
2014-01-31 16:12:49 -05:00
|
|
|
# You can use this library in your application by requiring it:
|
|
|
|
#
|
|
|
|
# require 'securerandom'
|
|
|
|
#
|
2015-01-02 01:36:00 -05:00
|
|
|
# It supports the following secure random number generators:
|
2007-06-09 21:42:51 -04:00
|
|
|
#
|
|
|
|
# * openssl
|
|
|
|
# * /dev/urandom
|
2008-01-06 04:11:34 -05:00
|
|
|
# * Win32
|
2007-06-09 21:42:51 -04:00
|
|
|
#
|
2019-01-20 10:06:11 -05:00
|
|
|
# SecureRandom is extended by the Random::Formatter module which
|
|
|
|
# defines the following methods:
|
2018-12-27 07:42:45 -05:00
|
|
|
#
|
|
|
|
# * alphanumeric
|
|
|
|
# * base64
|
|
|
|
# * choose
|
|
|
|
# * gen_random
|
|
|
|
# * hex
|
|
|
|
# * rand
|
|
|
|
# * random_bytes
|
|
|
|
# * random_number
|
|
|
|
# * urlsafe_base64
|
|
|
|
# * uuid
|
|
|
|
#
|
|
|
|
# These methods are usable as class methods of SecureRandom such as
|
2021-08-24 06:24:58 -04:00
|
|
|
# +SecureRandom.hex+.
|
2018-12-27 07:42:45 -05:00
|
|
|
#
|
2021-12-05 07:53:35 -05:00
|
|
|
# If a secure random number generator is not available,
|
|
|
|
# +NotImplementedError+ is raised.
|
2015-01-02 01:36:00 -05:00
|
|
|
|
2007-06-09 21:42:51 -04:00
|
|
|
module SecureRandom
|
2017-01-20 03:00:00 -05:00
|
|
|
class << self
|
|
|
|
def bytes(n)
|
|
|
|
return gen_random(n)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def gen_random_openssl(n)
|
2013-07-11 00:01:47 -04:00
|
|
|
@pid = 0 unless defined?(@pid)
|
2011-06-13 05:36:48 -04:00
|
|
|
pid = $$
|
2013-07-11 00:01:47 -04:00
|
|
|
unless @pid == pid
|
2013-08-31 01:07:56 -04:00
|
|
|
now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
2016-03-04 08:39:46 -05:00
|
|
|
OpenSSL::Random.random_add([now, @pid, pid].join(""), 0.0)
|
2017-02-24 06:33:06 -05:00
|
|
|
seed = Random.urandom(16)
|
2015-11-30 15:29:22 -05:00
|
|
|
if (seed)
|
|
|
|
OpenSSL::Random.random_add(seed, 16)
|
|
|
|
end
|
2011-06-13 05:36:48 -04:00
|
|
|
@pid = pid
|
|
|
|
end
|
2007-06-09 21:42:51 -04:00
|
|
|
return OpenSSL::Random.random_bytes(n)
|
|
|
|
end
|
2017-01-20 03:00:00 -05:00
|
|
|
|
|
|
|
def gen_random_urandom(n)
|
|
|
|
ret = Random.urandom(n)
|
2015-02-13 22:01:36 -05:00
|
|
|
unless ret
|
|
|
|
raise NotImplementedError, "No random device"
|
2008-01-06 04:11:34 -05:00
|
|
|
end
|
2015-02-13 22:01:36 -05:00
|
|
|
unless ret.length == n
|
|
|
|
raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
|
|
|
|
end
|
|
|
|
ret
|
2014-11-08 22:16:24 -05:00
|
|
|
end
|
2020-09-04 20:32:31 -04:00
|
|
|
|
2022-02-16 00:15:11 -05:00
|
|
|
begin
|
|
|
|
# Check if Random.urandom is available
|
|
|
|
Random.urandom(1)
|
|
|
|
alias gen_random gen_random_urandom
|
|
|
|
rescue RuntimeError
|
2020-09-04 20:32:31 -04:00
|
|
|
begin
|
|
|
|
require 'openssl'
|
|
|
|
rescue NoMethodError
|
|
|
|
raise NotImplementedError, "No random device"
|
|
|
|
else
|
|
|
|
alias gen_random gen_random_openssl
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
public :gen_random
|
2007-06-09 21:42:51 -04:00
|
|
|
end
|
2015-02-13 22:02:32 -05:00
|
|
|
end
|
2007-06-09 21:42:51 -04:00
|
|
|
|
2015-02-13 22:02:32 -05:00
|
|
|
SecureRandom.extend(Random::Formatter)
|