Bug #14773
closedSecureRandom.alphanumeric Uses Insecure Underlying Implementation
Description
I believe that the implementation of SecureRandom.alphanumeric
uses an underlying PRNG that is not the same as the one selected by the SecureRandom
module. This is because the alphanumeric
method uses the :choose
method (line 291 in 2.5.1) which in turn uses the :random_number
method (line 254,261).
The :random_number
method is defined in the Random::Formatter
module in random.c (The function is rand_random_number
(Line 1369 and associated on line 1647). At any rate, once it is in random.c, it ends up using the insecure PRNG built into random.c.
I have a patch, but probably not one that is production quality. It it pretty simple--it overrides the random_number
provided in Random::Formatter
to use the :bytes
method already defined.
module SecureRandom
def self.random_number max_range
b = SecureRandom.bytes 1
n = b.ord/256.0*max_range
n.to_i
end
end
At any rate, it may be a bad idea to extend SecureRandom
with Random::Formatter
in general, since it allows paths to use of the insecure underlying PRNG in random.c.
Updated by nobu (Nobuyoshi Nakada) over 6 years ago
- Status changed from Open to Rejected
You misread random.c.
When those methods are called on SecureRandom
, as it is not an instance of Random
but a Module
, trn_get_rnd(obj)
in rand_random_number()
returns NULL
.
Next, calling rand_random()
-> rand_int()
-> random_ulong_limited()
, and then obj_random_bytes()
-> rb_funcallv_public(obj, id_bytes, 1, &len)
as !rnd
.
Finally, it reaches SecureRandom.gen_random
in securerandom.rb.
If in doubt, you can try with breaking at SecureRandom.gen_random_urandom
(or a debug print).