Project

General

Profile

Misc #17319

Rename Random.urandom to os_random and document random data sources

Added by zofrex (James Sanderson) 3 months ago. Updated 2 months ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
[ruby-core:100788]

Description

SecureRandom gets randomness from Random.urandom, which is a confusing name because urandom only uses /dev/urandom in some circumstances. On reading the secure_random.rb code this morning I got very confused how it was supporting "win32" for example, because it appears to only use openssl and /dev/urandom.

I have renamed urandom to os_random. With this change, it is much more obvious from reading secure_random.rb what is happening, in my opinion.

I have also added urandom as an alias to os_random so this is not a breaking change. I am not 100% sure I documented this alias correctly.

I have also updated the documentation for os_random (was urandom), SecureRandom, and random_raw_seed to reflect that there are multiple potential sources for random data, not just urandom, openssl, and win32.


Related issues

Related to Ruby master - Bug #9569: SecureRandom should try /dev/urandom firstClosedActions

Updated by shyouhei (Shyouhei Urabe) 3 months ago

+1 for doc update. Naming wise, ruby is rather POSIX-centric. For instance it has IO.select which works on Windows as well.

Updated by shyouhei (Shyouhei Urabe) 3 months ago

Also until very recently (until version 5.6), Linux kernel has had distinct /dev/random and /dev/urandom. Some people argued the difference between those two are important. If we rename the method to os_random, that loses information about the randomness source. This doesn't sound very well.

Updated by zofrex (James Sanderson) 3 months ago

I hear what you're saying about communicating that it is not coming from /dev/random. It's hard to communicate all of that in a method name, because it will be a different source on different OSes or OS versions.

If we rename the method to os_random, that loses information about the randomness source

Only a very small amount of information, I think, because this method almost never uses /dev/urandom in practice. getrandom() was added to Linux in 3.17, in 2014, so very few people will be falling back on /dev/urandom.

I am not attached to to the name os_random, it was just the best I could come up with at the time. Perhaps more could be communicated about the source with something like os_best_random, to imply Ruby is using the best available source of random data the OS provides? Or maybe os_nonblocking_random, to communicate that it is using a non-blocking source? (I know that /dev/random and /dev/urandom are the same on Linux now but I think some other OSes still have a blocking source available)

Updated by nobu (Nobuyoshi Nakada) 3 months ago

How about Random.raw_seed(size)?

Updated by zofrex (James Sanderson) 3 months ago

I don't think raw_seed is name that does a good job of communicating what this method does and what it can be used for. I know this method is used to seed the OpenSSL random number generator, but its functionality is more broad than that.

I think that people reading "raw_seed" are likely to think that either this returns the seed for the RNG or perhaps that this method is only suitable for seeding another RNG, rather than using this method as an RNG. The latter case is somewhat plausible because on some systems there are RNG sources that aren't suitable for generating lots of random data, but can be used to seed a PRNG, so I think it's important to distinguish from that.

I think urandom is probably a better name than raw_seed because, although it doesn't always draw from urandom, it does always draw from random number generators that have similar properties to urandom (non-blocking, suitable for reading lots of data from).

I think os_random or os_nonblocking_random are still better names because they quickly tell anyone reading the source of SecureRandom that it gets its numbers from the OS random number generator (if not from OpenSSL). That makes reviewing the code from a security point of view a lot easier, and I think that's a highly desirable design goal for code that is so critical to the security of applications.

Updated by Eregon (Benoit Daloze) 3 months ago

zofrex (James Sanderson) wrote in #note-6:

I think that people reading "raw_seed" are likely to think that either this returns the seed for the RNG or perhaps that this method is only suitable for seeding another RNG, rather than using this method as an RNG. The latter case is somewhat plausible because on some systems there are RNG sources that aren't suitable for generating lots of random data, but can be used to seed a PRNG, so I think it's important to distinguish from that.

That's the point, it's not a good idea to use this API to generate an arbitrary number of random bytes.
Only to use it to seed a RNG. It's just slower, inefficient and apparently not more secure to read many bytes from /dev/urandom.

FWIW there is already Random.new_seed #=> Integer.

The reference in the doc of Random.urandom to man 7 random seems to be:

  While some safety margin above that minimum is reasonable, as a guard against flaws in the  CSPRNG  algorithm,  no  cryptographic
  primitive  available  today  can  hope  to promise more than 256 bits of security, so if any program reads more than 256 bits (32
  bytes) from the kernel random pool per invocation, or per reasonable reseed interval (not less than one minute), that  should  be
  taken as a sign that its cryptography is not skillfully implemented.
#8

Updated by nobu (Nobuyoshi Nakada) 2 months ago

  • Description updated (diff)
  • Subject changed from Rename Random::urandom to os_random and document random data sources to Rename Random.urandom to os_random and document random data sources
#9

Updated by naruse (Yui NARUSE) 2 months ago

  • Related to Bug #9569: SecureRandom should try /dev/urandom first added

Updated by naruse (Yui NARUSE) 2 months ago

  • Status changed from Open to Rejected

As https://bugs.ruby-lang.org/issues/9569#note-58 says, the name urandom insists it doesn't block.

Ruby often provide Unix emulation layer on Windows. I don't think this needs special treatment for Random.urandom.
Also you can easily suspect Random.urandom uses /dev/urandom and Win32 in this context about secure_random.rb.

Updated by zofrex (James Sanderson) 2 months ago

Thank for explaining the rationale behind the naming, I understand it now.

How would you feel about a patch just to update the documentation, and leave the method names as they are? The documentation still only lists openssl, urandom, and win32 as sources, I think it would be good to list all the potential sources for completeness.

Updated by naruse (Yui NARUSE) 2 months ago

zofrex (James Sanderson) wrote in #note-11:

Thank for explaining the rationale behind the naming, I understand it now.

How would you feel about a patch just to update the documentation, and leave the method names as they are? The documentation still only lists openssl, urandom, and win32 as sources, I think it would be good to list all the potential sources for completeness.

You may already read, Random.urandom actually don't use /dev/urandom on many OSes. On Linux it uses getrandom(2). On macOS it uses SecRandomCopyBytes. On some new BSDs it uses arc4random_buf. You can write down this list now. But who updates it when the implementation changes in the future.

Improving documentation is good. But we also need to care about maintainability. In the view of maintainability, "completeness" is bad smell.

Also available in: Atom PDF