<commit_before># SecurerRandomer

[![Build Status](https://travis-ci.org/mwpastore/securer_randomer.svg?branch=master)](https://travis-ci.org/mwpastore/securer_randomer)
[![Gem Version](https://badge.fury.io/rb/securer_randomer.svg)](https://badge.fury.io/rb/securer_randomer)

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.

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
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.

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:

* `Kernel.rand(nil)` and `SecureRandom.random_number(nil)` both return a float
  `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 `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!

## 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.

* SecureRandom`.random_number`

  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.

* SecurerRandomer`.rand`
<commit_msg>Add explanation of monkeypatch<commit_after># SecurerRandomer

[![Build Status](https://travis-ci.org/mwpastore/securer_randomer.svg?branch=master)](https://travis-ci.org/mwpastore/securer_randomer)
[![Gem Version](https://badge.fury.io/rb/securer_randomer.svg)](https://badge.fury.io/rb/securer_randomer)

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.

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
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.

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:

* `Kernel.rand(nil)` and `SecureRandom.random_number(nil)` both return a float
  `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 `n` such that `0.0 <= n < 1.0` in Ruby 2.3

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 easiest 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.

* SecureRandom`.random_number`

  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.

* SecurerRandomer`.rand`

{'fraction_non_alphanumeric': 0.08716600963644328, 'fraction_numerical': 0.008906409694845963, 'mean_word_length': 4.8447098976109215, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2666658', 'n_tokens_mistral': 2128, 'n_tokens_neox': 2000, 'n_words': 835}