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—which is a fork of [NaCl][6] by Daniel J. Bernstein—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`—meaning it "chokes" on
-the same inputs and throws the same exception types—that uses RbNaCl as
-its source of entropy.
+ A bug-for-bug reimplementation of Kernel`.rand`—meaning it "chokes" on
+ the same inputs and throws the same exception types—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