securer_randomer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []