README.md in securer_randomer-0.1.5 vs README.md in securer_randomer-0.1.6

- old
+ new

@@ -5,71 +5,97 @@ Ruby's SecureRandom prefers OpenSSL over other mechanisms (such as `/dev/urandom` and `getrandom(2)`). This has recently garnered [some][1] [criticism][2]. -[RbNaCl][3] provides Ruby bindings to a portable crypto library -([libsodium][4]) that includes an alternative, OpenSSL-free pseudo-random -number generator (PRNG) implementation. +[RbNaCl][3] provides Ruby bindings to [libsodium][4], a portable crypto +library&mdash;which is a fork of [NaCl][6] by Daniel J. Bernstein&mdash;that +includes hooks to alternative, OpenSSL-free pseudo-random number generators +(PRNGs) such as `getrandom(2)` on modern Linux kernels and `RtlGenRandom()` on +Windows. This gem monkeypatches RbNaCl into SecureRandom and aims to be "bug-for-bug" compatible with the "stock" implementation of SecureRandom across Ruby -versions. It also provides a nice "do what I mean" random number method that +versions. It also provides a bonus "do what I mean" random number method that can be used instead of Kernel`.rand` and SecureRandom`.random_number`. ## History This gem started out as a very simple monkeypatch to -SecureRandom`.random_bytes` and grew as I dug deeper. In newer Rubies, you need -to patch `.gen_random` instead of `.random_bytes`, and it has no default byte -size. +SecureRandom`.random_bytes` and grew as I dug deeper. In newer rubies, for +example, you need to patch `.gen_random` instead of `.random_bytes`, and it has +a different calling signature. -Generating random numbers proved to be rather tricky due to inconsistencies -between the implementations and functionality of Kernel`.rand` and -SecureRandom`.random_number` between Ruby versions. For example: +Generating random numbers proved to be rather tricky due to inconsistencies of +of Kernel`.rand` and SecureRandom`.random_number` between Ruby implementations +and versions. For example: * `Kernel.rand(nil)` and `SecureRandom.random_number(nil)` both return a float - such that `{ 0.0 <= n < 1.0 }` in Ruby 2.3; but + `n` such that `0.0 <= n < 1.0` in Ruby 2.3; but `SecureRandom.random_number(nil)` throws an ArgumentError in Ruby 2.2 * Kernel`.rand` with an inverted range (e.g. `0..-10`) returns `nil` in Ruby 2.2+, but SecureRandom`.random_number` throws an ArgumentError in Ruby 2.2 - and returns a float such that `{ 0.0 <= n < 1.0 }` in Ruby 2.3 + and returns a float `n` such that `0.0 <= n < 1.0` in Ruby 2.3 -Tests started to accumulate so I decided it was probably a good idea to gemify -this! +Branching logic and tests started to accumulate so I decided it was probably a +good idea to gemify this! +### Why a monkeypatch? + +The concept of monkeypatching in Ruby is a sensitive subject. It has the +potential to break things in unexpected ways and make Ruby code more difficult +to troubleshoot, and it's these kinds of practices that give Ruby (and +Rubyists) a bad name. It was actually way more labor-intensive to write this as +a monkeypatch rather than landing it as a completely separate module. So why? + +Simply put, I do not anticipate this gem being a long-term solution! At some +point in the hopefully-near future I would like to see the Ruby core team +acquiesce to community pressure and modify `securerandom.rb` and `random.c` to +not utilize OpenSSL and prefer `getrandom(2)` over `urandom`. And so my goal +was not to write some super-maintainable, standalone piece of software, but +rather a temporary fix that can be easily dropped into an existing project and +easily pulled out at a later date. A monkeypatch is the best way to achieve +this. + ## Features * SecureRandom`.gen_random` (or `.random_bytes`) -Monkeypatches SecureRandom such that its various formatter methods (`.uuid`, -`.hex`, `.base64`, `.urlsafe_base64`, and `.random_bytes`) use RbNaCl for random -byte generation instead of OpenSSL. + Monkeypatches SecureRandom such that its various formatter methods (`.uuid`, + `.hex`, `.base64`, `.urlsafe_base64`, and `.random_bytes`) use RbNaCl for random + byte generation instead of OpenSSL. * SecureRandom`.random_number` -Monkeypatches SecureRandom such that it uses SecurerRandomer`.kernel_rand` -instead of OpenSSL (or Kernel`.rand`) to generate random numbers from numeric -types and ranges. It is bug-for-bug compatible with "stock" SecureRandom, -meaning it "chokes" on the same inputs and throws the same exception types. + Monkeypatches SecureRandom such that it uses SecurerRandomer`.kernel_rand` + instead of OpenSSL to generate random numbers from numeric types and ranges. It + is bug-for-bug compatible with "stock" SecureRandom, meaning it "chokes" on the + same inputs and throws the same exception types. + If you prefer to use Kernel`.rand` instead of SecurerRandomer`.kernel_rand`, + add this statement to your bootup process after requiring SecurerRandomer: + + ```ruby + SecurerRandomer::KERNEL_RAND = Kernel.method(:rand) + ``` + * SecurerRandomer`.kernel_rand` -A bug-for-bug reimplementation of Kernel`.rand`&mdash;meaning it "chokes" on -the same inputs and throws the same exception types&mdash;that uses RbNaCl as -its source of entropy. + A bug-for-bug reimplementation of Kernel`.rand`&mdash;meaning it "chokes" on + the same inputs and throws the same exception types&mdash;that uses RbNaCl as + its source of entropy. * SecurerRandomer`.rand` -An idealistic, "do what I mean" random number method that accepts a variety of -inputs and returns what you might expect. Whereas `Kernel.rand(-5.6)` returns -an integer such that `{ 0 <= n < 5 }` and `SecureRandom.random_number(-5.6)` -returns a float such that `{ 0.0 <= n < 1.0 }`, **`SecurerRandomer.rand(-5.6)` -returns a float such that `{ 0 >= n > -5.6 }`**. Whereas `Kernel.rand(10..0)` -returns `nil` and `SecureRandom.random_number(10..0)` returns a float such that -`{ 0.0 <= n < 1.0 }` (in Ruby 2.3), **`SecurerRandomer.rand(10..0)` returns an -integer such that `{ 10 >= n >= 0 }`**. + An idealistic, "do what I mean" random number method that accepts a variety of + inputs and returns what you might expect. Whereas `Kernel.rand(-5.6)` returns + an integer `n` such that `0 <= n < 5` and `SecureRandom.random_number(-5.6)` + returns a float `n` such that `0.0 <= n < 1.0`, **`SecurerRandomer.rand(-5.6)` + returns a float `n` such that `0 >= n > -5.6`**. Whereas `Kernel.rand(10..0)` + returns `nil` and `SecureRandom.random_number(10..0)` returns a float `n` such + that `0.0 <= n < 1.0` (in Ruby 2.3), **`SecurerRandomer.rand(10..0)` returns an + integer `n` such that `10 >= n >= 0`**. ## Installation Please review the installation instructions for [RbNaCl][3]. You will need to install either [libsodium][4] or [rbnacl-libsodium][5] before installing this @@ -98,13 +124,12 @@ **Use at your own risk!** I am neither a cryptologist nor a cryptographer. Although I'm fairly confident in the test suite, serious bugs affecting compatibility, randomness, and -performance may be present. If you're cautious, I would recommend using the -monkeypatched SecureRandom formatter methods for random data and Kernel`.rand` -for random numbers. Bug reports are welcome. +performance may be present. If you're cautious, I would recommend setting +`SecurerRandomer::KERNEL_RAND = Kernel.method(:rand)` as described above. ## Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. @@ -121,5 +146,6 @@ [1]: https://bugs.ruby-lang.org/issues/9569 [2]: https://news.ycombinator.com/item?id=11624890 [3]: https://github.com/cryptosphere/rbnacl [4]: https://github.com/jedisct1/libsodium [5]: https://github.com/cryptosphere/rbnacl-libsodium +[6]: http://nacl.cr.yp.to