securer_randomer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c64cc94ae8ed41dc5612889e38d0bd8d7f814ebd
4
+ data.tar.gz: 428a48564b8eb0e9429973e9809f777ec4e9ccfa
5
+ SHA512:
6
+ metadata.gz: 836c3eff41e7b0bb2316c777a377173bbfe3b38e94eddce50421519984f5a6bd4e41e666ffaf8a635712e39a0994d3eb25035a34aaaca1530dbf88dba911ba7d
7
+ data.tar.gz: db821db16a154ce3c4be8b4f4476c3e13ce71264fb92fcddeaac961ab6cb327d1e643d97b40adf4366a07fb151a580c1c6e787dc75d0435381bced2816c0034e
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .ruby-version
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ AllCops:
2
+ TargetRubyVersion: 1.9
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ sudo: required
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.8
8
+ - 2.2.4
9
+ - 2.3.0
10
+ before_install:
11
+ - gem install bundler -v 1.11.2
12
+ - sudo add-apt-repository -y ppa:chris-lea/libsodium
13
+ - sudo apt-get update -q
14
+ - sudo apt-get install -y libsodium-dev
15
+ env:
16
+ - WITH_MONKEYPATCH=false
17
+ - WITH_MONKEYPATCH=true
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in securer_randomer.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Mike Pastore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # SecurerRandomer
2
+
3
+ [![Build Status](https://travis-ci.org/mwpastore/securer_randomer.svg?branch=master)](https://travis-ci.org/mwpastore/securer_randomer)
4
+ [![Gem Version](https://badge.fury.io/rb/securer_randomer.svg)](https://badge.fury.io/rb/securer_randomer)
5
+
6
+ Ruby's SecureRandom prefers OpenSSL over other mechanisms (such as
7
+ `/dev/urandom` and `getrandom()`). This has recently garnered [some][1]
8
+ [criticism][2].
9
+
10
+ [RbNaCl][3] provides Ruby bindings to a portable crypto library
11
+ ([libsodium][4]) that includes an alternative, OpenSSL-free pseudo-random
12
+ number generator (PRNG) implementation.
13
+
14
+ This gem monkeypatches RbNaCl into SecureRandom and aims to be "bug-for-bug"
15
+ compatible with the "stock" implementation of SecureRandom across Ruby
16
+ versions. It also provides a nice "do what I mean" random number method that
17
+ can be used instead of Kernel`.rand` and SecureRandom`.random_number`.
18
+
19
+ ## History
20
+
21
+ This gem started out as a very simple monkeypatch to
22
+ SecureRandom`.random_bytes` and grew as I dug deeper. In newer Rubies, you need
23
+ to patch `.gen_random` instead of `.random_bytes`, and it has no default byte
24
+ size.
25
+
26
+ Generating random numbers proved to be rather tricky due to inconsistencies
27
+ between the implementations and functionality of Kernel`.rand` and
28
+ SecureRandom`.random_number` between Ruby versions. For example:
29
+
30
+ * `Kernel.rand(nil)` and `SecureRandom.random_number(nil)` both return a float
31
+ such that `{ 0.0 <= n < 1.0 }` in Ruby 2.3; but
32
+ `SecureRandom.random_number(nil)` throws an ArgumentError in Ruby 2.2
33
+ * Kernel`.rand` with an inverted range (e.g. `0..-10`) returns `nil` in Ruby
34
+ 2.2+, but SecureRandom`.random_number` throws an ArgumentError in Ruby 2.2
35
+ and returns a float such that `{ 0.0 <= n < 1.0 }` in Ruby 2.3
36
+
37
+ Tests started to accumulate so I decided it was probably a good idea to gemify
38
+ this!
39
+
40
+ ## Features
41
+
42
+ * SecureRandom`.gen_random` (or `.random_bytes`)
43
+
44
+ Monkeypatches SecureRandom such that its various formatter methods (`.uuid`,
45
+ `.hex`, `.base64`, `.urlsafe_base64`, and `.random_bytes`) use RbNaCl for random
46
+ byte generation instead of OpenSSL.
47
+
48
+ * SecureRandom`.random_number`
49
+
50
+ Monkeypatches SecureRandom such that it uses SecurerRandomer`.kernel_rand`
51
+ instead of OpenSSL (or Kernel`.rand`) to generate random numbers from numeric
52
+ types and ranges. It is bug-for-bug compatible with "stock" SecureRandom,
53
+ meaning it "chokes" on the same inputs and throws the same exception types.
54
+
55
+ * SecurerRandomer`.kernel_rand`
56
+
57
+ A bug-for-bug reimplementation of Kernel`.rand`&mdash;meaning it "chokes" on
58
+ the same inputs and throws the same exception types&mdash;that uses RbNaCl as
59
+ its source of entropy.
60
+
61
+ * SecurerRandomer`.rand`
62
+
63
+ An idealistic, "do what I mean" random number method that accepts a variety of
64
+ inputs and returns what you might expect. Whereas `Kernel.rand(-5.6)` returns
65
+ an integer such that `{ 0 <= n < 5 }` and `SecureRandom.random_number(-5.6)`
66
+ returns a float such that `{ 0.0 <= n < 1.0 }`, **`SecurerRandomer.rand(-5.6)`
67
+ returns a float such that `{ 0 >= n > -5.6 }`**. Whereas `Kernel.rand(10..0)`
68
+ returns `nil` and `SecureRandom.random_number(10..0)` returns a float such that
69
+ `{ 0.0 <= n < 1.0 }` (in Ruby 2.3), **`SecurerRandomer.rand(10..0)` returns an
70
+ integer such that `{ 10 >= n >= 0 }`**.
71
+
72
+ ## Installation
73
+
74
+ Please review the installation instructions for [RbNaCl][3]. You will need to
75
+ install either [libsodium][4] or [rbnacl-libsodium][5] before installing this
76
+ gem.
77
+
78
+ Add this line to your application's Gemfile:
79
+
80
+ ```ruby
81
+ gem 'securer_randomer', '~> 0.1.0'
82
+ ```
83
+
84
+ And then execute:
85
+
86
+ $ bundle install
87
+
88
+ Or install it yourself as:
89
+
90
+ $ gem install securer_randomer
91
+
92
+ ## Compatibility
93
+
94
+ SecurerRandomer has been tested under MRI/YARV versions 1.9.3, 2.0, 2.1, 2.2,
95
+ and 2.3.
96
+
97
+ ## DISCLAIMER
98
+
99
+ **Use at your own risk!**
100
+
101
+ I am neither a cryptologist nor a cryptographer. Although I'm fairly confident
102
+ in the test suite, serious bugs affecting compatibility, randomness, and
103
+ performance may be present. If you're cautious, I would recommend using the
104
+ monkeypatched SecureRandom formatter methods for random data and Kernel`.rand`
105
+ for random numbers. Bug reports are welcome.
106
+
107
+ ## Development
108
+
109
+ 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.
110
+
111
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
112
+
113
+ ## Contributing
114
+
115
+ Bug reports and pull requests are welcome on GitHub at https://github.com/mwpastore/securer_randomer.
116
+
117
+ ## License
118
+
119
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
120
+
121
+ [1]: https://bugs.ruby-lang.org/issues/9569
122
+ [2]: https://news.ycombinator.com/item?id=11624890
123
+ [3]: https://github.com/cryptosphere/rbnacl
124
+ [4]: https://github.com/jedisct1/libsodium
125
+ [5]: https://github.com/cryptosphere/rbnacl-libsodium
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'securer_randomer'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module SecureRandom
6
+ RUBY_VER_OBJ = Gem::Version.new(RUBY_VERSION.dup)
7
+ RUBY_GE_2_2 = RUBY_VER_OBJ >= Gem::Version.new(String.new('2.2.0'))
8
+ RUBY_GE_2_3 = RUBY_VER_OBJ >= Gem::Version.new(String.new('2.3.0'))
9
+
10
+ if RUBY_GE_2_2
11
+ def self.gen_random(n)
12
+ RbNaCl::Random.random_bytes(n)
13
+ end
14
+ else
15
+ def self.random_bytes(n = nil)
16
+ RbNaCl::Random.random_bytes(n ? n.to_i : 16)
17
+ end
18
+ end
19
+
20
+ if RUBY_GE_2_3
21
+ def self.random_number(n = 0)
22
+ arg =
23
+ case n
24
+ when nil
25
+ 0
26
+ when Range
27
+ n.end < n.begin ? 0 : n
28
+ when Numeric
29
+ n > 0 ? n : 0
30
+ end
31
+
32
+ raise TypeError unless arg
33
+
34
+ SecurerRandomer.rand(arg, true)
35
+ rescue TypeError
36
+ raise ArgumentError, "invalid argument - #{n}"
37
+ end
38
+ else
39
+ def self.random_number(n = 0)
40
+ raise ArgumentError, "comparison of Fixnum with #{n} failed" unless n.is_a?(Numeric)
41
+ if n.is_a?(Float) and n > 0
42
+ if RUBY_GE_2_2
43
+ raise TypeError, 'Cannot convert into OpenSSL::BN'
44
+ else
45
+ raise ArgumentError, 'wrong number of arguments'
46
+ end
47
+ end
48
+
49
+ SecurerRandomer.rand(n > 0 ? n : 0, true)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SecurerRandomer
4
+ VERSION = '0.1.0' # rubocop:disable Style/MutableConstant
5
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbnacl/sodium'
4
+ require 'rbnacl/util'
5
+ require 'rbnacl/random'
6
+
7
+ require 'securer_randomer/version'
8
+ require 'securer_randomer/monkeypatch/secure_random'
9
+
10
+ module SecurerRandomer
11
+ def self.kernel_rand(max = 0)
12
+ rand(max, true)
13
+ end
14
+
15
+ def self.rand(n = 0, emulate_kernel = false)
16
+ if n.is_a?(Range)
17
+ raise TypeError, 'no implicit conversion of Range into Fixnum' \
18
+ unless n.begin.is_a?(Numeric) and n.end.is_a?(Numeric)
19
+
20
+ if n.end < n.begin
21
+ if emulate_kernel
22
+ nil
23
+ else
24
+ m = Range.new(n.end, n.begin, false)
25
+
26
+ while true # TODO: better way to do this than looping?
27
+ q = _rand_range(m)
28
+
29
+ break q unless n.exclude_end? and q == n.end
30
+ end
31
+ end
32
+ else
33
+ _rand_range(n)
34
+ end
35
+ else
36
+ raise TypeError, "no implicit conversion of #{n.class} into Fixnum" \
37
+ unless n.nil? or n.is_a?(Numeric)
38
+
39
+ if n.nil? or n.zero?
40
+ _randex
41
+ elsif emulate_kernel
42
+ _rand_range(Range.new(0, n.to_i.abs, true))
43
+ else
44
+ _rand_range(Range.new(0, n.abs, true)) * (n < 0 ? -1 : 1)
45
+ end
46
+ end
47
+ end
48
+
49
+ def self._randex
50
+ i64 = RbNaCl::Random.random_bytes(8).unpack('Q').first
51
+ Math.ldexp(i64 >> (64 - Float::MANT_DIG), -Float::MANT_DIG)
52
+ end
53
+
54
+ def self._randin
55
+ _randex >= 0.5 ? 1 - _randex : _randex
56
+ end
57
+
58
+ def self._rand_range(n)
59
+ n.begin + if n.end.is_a?(Float) or n.begin.is_a?(Float)
60
+ (n.exclude_end? ? _randex : _randin) * (n.end - n.begin)
61
+ else
62
+ (_randex * (n.end - n.begin + (n.exclude_end? ? 0 : 1))).to_i
63
+ end
64
+ end
65
+
66
+ private_class_method(:_randex, :_randin, :_rand_range) if respond_to?(:private_class_method)
67
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'securer_randomer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'securer_randomer'
8
+ spec.version = SecurerRandomer::VERSION
9
+ spec.authors = ['Mike Pastore']
10
+ spec.email = ['mike@oobak.org']
11
+
12
+ spec.summary = 'Monkeypatch SecureRandom (and Kernel.rand) with RbNaCl'
13
+ spec.homepage = 'https://github.com/mwpastore/securer_randomer'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split(%r{\x0}).reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = 'exe'
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.required_ruby_version = '>= 2.2.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.11'
24
+ spec.add_development_dependency 'rake', '~> 11.1.1'
25
+ spec.add_development_dependency 'rspec', '~> 3.0'
26
+ spec.add_development_dependency 'rspec-given', '~> 3.8.0'
27
+ spec.add_development_dependency 'rubocop', '~> 0.39.0'
28
+
29
+ spec.add_runtime_dependency 'rbnacl', '~> 3.3.0'
30
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: securer_randomer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mike Pastore
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 11.1.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 11.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-given
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.8.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.8.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.39.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.39.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rbnacl
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 3.3.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 3.3.0
97
+ description:
98
+ email:
99
+ - mike@oobak.org
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".rubocop.yml"
107
+ - ".travis.yml"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - lib/securer_randomer.rb
115
+ - lib/securer_randomer/monkeypatch/secure_random.rb
116
+ - lib/securer_randomer/version.rb
117
+ - securer_randomer.gemspec
118
+ homepage: https://github.com/mwpastore/securer_randomer
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 2.2.0
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.5.1
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Monkeypatch SecureRandom (and Kernel.rand) with RbNaCl
142
+ test_files: []