securerandom 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5369e43862e4524d9261f2c50b175c1bb99958cb2abfba54bae9fec715556133
4
+ data.tar.gz: cbe246fd3da662ace60c0ffe53a5175227611a4ed74d5c4ac84fde64c44d9ebb
5
+ SHA512:
6
+ metadata.gz: b416a144b9d4a134212b215ad45d03a80a1cc07d866ea7714363250d6f5f665bbf09410b37856ced86ebc2a7b5e16b3b04f4cab64b1b5ff05c1b4a223f3fcc7a
7
+ data.tar.gz: 174eb8f33e98f66f61c8792d512f04feedb9881ff4a79a39040da625b7b973f4c4796857cd1c132d16435df57ad74a229a1f7ec959cb66aac969d084496ee691
@@ -0,0 +1,24 @@
1
+ name: build
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, 2.5, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake compile test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rake"
4
+ gem "test-unit"
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,72 @@
1
+ # Securerandom
2
+
3
+ This library is an interface to secure random number generators which are
4
+ suitable for generating session keys in HTTP cookies, etc.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'securerandom'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle install
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install securerandom
21
+
22
+ ## Usage
23
+
24
+ Generate random hexadecimal strings:
25
+
26
+ ```ruby
27
+ require 'securerandom'
28
+
29
+ SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
30
+ SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
31
+ SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
32
+ ```
33
+
34
+ Generate random base64 strings:
35
+
36
+ ```ruby
37
+ SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
38
+ SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
39
+ SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
40
+ ```
41
+
42
+ Generate random binary strings:
43
+
44
+ ```ruby
45
+ SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
46
+ SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
47
+ ```
48
+
49
+ Generate alphanumeric strings:
50
+
51
+ ```ruby
52
+ SecureRandom.alphanumeric(10) #=> "S8baxMJnPl"
53
+ SecureRandom.alphanumeric(10) #=> "aOxAg8BAJe"
54
+ ```
55
+
56
+ Generate UUIDs:
57
+
58
+ ```ruby
59
+ SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
60
+ SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
61
+ ```
62
+
63
+ ## Development
64
+
65
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
66
+
67
+ 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).
68
+
69
+ ## Contributing
70
+
71
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/securerandom.
72
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "securerandom"
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(__FILE__)
@@ -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,317 @@
1
+ # -*- coding: us-ascii -*-
2
+ # frozen_string_literal: true
3
+
4
+ # == Secure random number generator interface.
5
+ #
6
+ # This library is an interface to secure random number generators which are
7
+ # suitable for generating session keys in HTTP cookies, etc.
8
+ #
9
+ # You can use this library in your application by requiring it:
10
+ #
11
+ # require 'securerandom'
12
+ #
13
+ # It supports the following secure random number generators:
14
+ #
15
+ # * openssl
16
+ # * /dev/urandom
17
+ # * Win32
18
+ #
19
+ # SecureRandom is extended by the Random::Formatter module which
20
+ # defines the following methods:
21
+ #
22
+ # * alphanumeric
23
+ # * base64
24
+ # * choose
25
+ # * gen_random
26
+ # * hex
27
+ # * rand
28
+ # * random_bytes
29
+ # * random_number
30
+ # * urlsafe_base64
31
+ # * uuid
32
+ #
33
+ # These methods are usable as class methods of SecureRandom such as
34
+ # `SecureRandom.hex`.
35
+ #
36
+ # === Examples
37
+ #
38
+ # Generate random hexadecimal strings:
39
+ #
40
+ # require 'securerandom'
41
+ #
42
+ # SecureRandom.hex(10) #=> "52750b30ffbc7de3b362"
43
+ # SecureRandom.hex(10) #=> "92b15d6c8dc4beb5f559"
44
+ # SecureRandom.hex(13) #=> "39b290146bea6ce975c37cfc23"
45
+ #
46
+ # Generate random base64 strings:
47
+ #
48
+ # SecureRandom.base64(10) #=> "EcmTPZwWRAozdA=="
49
+ # SecureRandom.base64(10) #=> "KO1nIU+p9DKxGg=="
50
+ # SecureRandom.base64(12) #=> "7kJSM/MzBJI+75j8"
51
+ #
52
+ # Generate random binary strings:
53
+ #
54
+ # SecureRandom.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
55
+ # SecureRandom.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
56
+ #
57
+ # Generate alphanumeric strings:
58
+ #
59
+ # SecureRandom.alphanumeric(10) #=> "S8baxMJnPl"
60
+ # SecureRandom.alphanumeric(10) #=> "aOxAg8BAJe"
61
+ #
62
+ # Generate UUIDs:
63
+ #
64
+ # SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
65
+ # SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
66
+ #
67
+
68
+ module SecureRandom
69
+ class << self
70
+ def bytes(n)
71
+ return gen_random(n)
72
+ end
73
+
74
+ private
75
+
76
+ def gen_random_openssl(n)
77
+ @pid = 0 unless defined?(@pid)
78
+ pid = $$
79
+ unless @pid == pid
80
+ now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
81
+ OpenSSL::Random.random_add([now, @pid, pid].join(""), 0.0)
82
+ seed = Random.urandom(16)
83
+ if (seed)
84
+ OpenSSL::Random.random_add(seed, 16)
85
+ end
86
+ @pid = pid
87
+ end
88
+ return OpenSSL::Random.random_bytes(n)
89
+ end
90
+
91
+ def gen_random_urandom(n)
92
+ ret = Random.urandom(n)
93
+ unless ret
94
+ raise NotImplementedError, "No random device"
95
+ end
96
+ unless ret.length == n
97
+ raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
98
+ end
99
+ ret
100
+ end
101
+
102
+ ret = Random.urandom(1)
103
+ if ret.nil?
104
+ begin
105
+ require 'openssl'
106
+ rescue NoMethodError
107
+ raise NotImplementedError, "No random device"
108
+ else
109
+ alias gen_random gen_random_openssl
110
+ end
111
+ else
112
+ alias gen_random gen_random_urandom
113
+ end
114
+
115
+ public :gen_random
116
+ end
117
+ end
118
+
119
+ module Random::Formatter
120
+
121
+ # SecureRandom.random_bytes generates a random binary string.
122
+ #
123
+ # The argument _n_ specifies the length of the result string.
124
+ #
125
+ # If _n_ is not specified or is nil, 16 is assumed.
126
+ # It may be larger in future.
127
+ #
128
+ # The result may contain any byte: "\x00" - "\xff".
129
+ #
130
+ # require 'securerandom'
131
+ #
132
+ # SecureRandom.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
133
+ # SecureRandom.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
134
+ #
135
+ # If a secure random number generator is not available,
136
+ # +NotImplementedError+ is raised.
137
+ def random_bytes(n=nil)
138
+ n = n ? n.to_int : 16
139
+ gen_random(n)
140
+ end
141
+
142
+ # SecureRandom.hex generates a random hexadecimal string.
143
+ #
144
+ # The argument _n_ specifies the length, in bytes, of the random number to be generated.
145
+ # The length of the resulting hexadecimal string is twice of _n_.
146
+ #
147
+ # If _n_ is not specified or is nil, 16 is assumed.
148
+ # It may be larger in the future.
149
+ #
150
+ # The result may contain 0-9 and a-f.
151
+ #
152
+ # require 'securerandom'
153
+ #
154
+ # SecureRandom.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
155
+ # SecureRandom.hex #=> "91dc3bfb4de5b11d029d376634589b61"
156
+ #
157
+ # If a secure random number generator is not available,
158
+ # +NotImplementedError+ is raised.
159
+ def hex(n=nil)
160
+ random_bytes(n).unpack("H*")[0]
161
+ end
162
+
163
+ # SecureRandom.base64 generates a random base64 string.
164
+ #
165
+ # The argument _n_ specifies the length, in bytes, of the random number
166
+ # to be generated. The length of the result string is about 4/3 of _n_.
167
+ #
168
+ # If _n_ is not specified or is nil, 16 is assumed.
169
+ # It may be larger in the future.
170
+ #
171
+ # The result may contain A-Z, a-z, 0-9, "+", "/" and "=".
172
+ #
173
+ # require 'securerandom'
174
+ #
175
+ # SecureRandom.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
176
+ # SecureRandom.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
177
+ #
178
+ # If a secure random number generator is not available,
179
+ # +NotImplementedError+ is raised.
180
+ #
181
+ # See RFC 3548 for the definition of base64.
182
+ def base64(n=nil)
183
+ [random_bytes(n)].pack("m0")
184
+ end
185
+
186
+ # SecureRandom.urlsafe_base64 generates a random URL-safe base64 string.
187
+ #
188
+ # The argument _n_ specifies the length, in bytes, of the random number
189
+ # to be generated. The length of the result string is about 4/3 of _n_.
190
+ #
191
+ # If _n_ is not specified or is nil, 16 is assumed.
192
+ # It may be larger in the future.
193
+ #
194
+ # The boolean argument _padding_ specifies the padding.
195
+ # If it is false or nil, padding is not generated.
196
+ # Otherwise padding is generated.
197
+ # By default, padding is not generated because "=" may be used as a URL delimiter.
198
+ #
199
+ # The result may contain A-Z, a-z, 0-9, "-" and "_".
200
+ # "=" is also used if _padding_ is true.
201
+ #
202
+ # require 'securerandom'
203
+ #
204
+ # SecureRandom.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
205
+ # SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
206
+ #
207
+ # SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
208
+ # SecureRandom.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
209
+ #
210
+ # If a secure random number generator is not available,
211
+ # +NotImplementedError+ is raised.
212
+ #
213
+ # See RFC 3548 for the definition of URL-safe base64.
214
+ def urlsafe_base64(n=nil, padding=false)
215
+ s = [random_bytes(n)].pack("m0")
216
+ s.tr!("+/", "-_")
217
+ s.delete!("=") unless padding
218
+ s
219
+ end
220
+
221
+ # SecureRandom.uuid generates a random v4 UUID (Universally Unique IDentifier).
222
+ #
223
+ # require 'securerandom'
224
+ #
225
+ # SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
226
+ # SecureRandom.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
227
+ # SecureRandom.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
228
+ #
229
+ # The version 4 UUID is purely random (except the version).
230
+ # It doesn't contain meaningful information such as MAC addresses, timestamps, etc.
231
+ #
232
+ # The result contains 122 random bits (15.25 random bytes).
233
+ #
234
+ # See RFC 4122 for details of UUID.
235
+ #
236
+ def uuid
237
+ ary = random_bytes(16).unpack("NnnnnN")
238
+ ary[2] = (ary[2] & 0x0fff) | 0x4000
239
+ ary[3] = (ary[3] & 0x3fff) | 0x8000
240
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
241
+ end
242
+
243
+ private def gen_random(n)
244
+ self.bytes(n)
245
+ end
246
+
247
+ # SecureRandom.choose generates a string that randomly draws from a
248
+ # source array of characters.
249
+ #
250
+ # The argument _source_ specifies the array of characters from which
251
+ # to generate the string.
252
+ # The argument _n_ specifies the length, in characters, of the string to be
253
+ # generated.
254
+ #
255
+ # The result may contain whatever characters are in the source array.
256
+ #
257
+ # require 'securerandom'
258
+ #
259
+ # SecureRandom.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
260
+ # SecureRandom.choose([*'0'..'9'], 5) #=> "27309"
261
+ #
262
+ # If a secure random number generator is not available,
263
+ # +NotImplementedError+ is raised.
264
+ private def choose(source, n)
265
+ size = source.size
266
+ m = 1
267
+ limit = size
268
+ while limit * size <= 0x100000000
269
+ limit *= size
270
+ m += 1
271
+ end
272
+ result = ''.dup
273
+ while m <= n
274
+ rs = random_number(limit)
275
+ is = rs.digits(size)
276
+ (m-is.length).times { is << 0 }
277
+ result << source.values_at(*is).join('')
278
+ n -= m
279
+ end
280
+ if 0 < n
281
+ rs = random_number(limit)
282
+ is = rs.digits(size)
283
+ if is.length < n
284
+ (n-is.length).times { is << 0 }
285
+ else
286
+ is.pop while n < is.length
287
+ end
288
+ result.concat source.values_at(*is).join('')
289
+ end
290
+ result
291
+ end
292
+
293
+ ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
294
+ # SecureRandom.alphanumeric generates a random alphanumeric string.
295
+ #
296
+ # The argument _n_ specifies the length, in characters, of the alphanumeric
297
+ # string to be generated.
298
+ #
299
+ # If _n_ is not specified or is nil, 16 is assumed.
300
+ # It may be larger in the future.
301
+ #
302
+ # The result may contain A-Z, a-z and 0-9.
303
+ #
304
+ # require 'securerandom'
305
+ #
306
+ # SecureRandom.alphanumeric #=> "2BuBuLf3WfSKyQbR"
307
+ # SecureRandom.alphanumeric(10) #=> "i6K93NdqiH"
308
+ #
309
+ # If a secure random number generator is not available,
310
+ # +NotImplementedError+ is raised.
311
+ def alphanumeric(n=nil)
312
+ n = 16 if n.nil?
313
+ choose(ALPHANUMERIC, n)
314
+ end
315
+ end
316
+
317
+ SecureRandom.extend(Random::Formatter)
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "securerandom"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Tanaka Akira"]
5
+ spec.email = ["akr@fsij.org"]
6
+
7
+ spec.summary = %q{Interface for secure random number generator.}
8
+ spec.description = %q{Interface for secure random number generator.}
9
+ spec.homepage = "https://github.com/ruby/securerandom"
10
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
11
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
12
+
13
+ spec.metadata["homepage_uri"] = spec.homepage
14
+ spec.metadata["source_code_uri"] = spec.homepage
15
+
16
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: securerandom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tanaka Akira
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-09-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Interface for secure random number generator.
14
+ email:
15
+ - akr@fsij.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".github/workflows/test.yml"
21
+ - ".gitignore"
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - bin/console
27
+ - bin/setup
28
+ - lib/securerandom.rb
29
+ - securerandom.gemspec
30
+ homepage: https://github.com/ruby/securerandom
31
+ licenses:
32
+ - Ruby
33
+ - BSD-2-Clause
34
+ metadata:
35
+ homepage_uri: https://github.com/ruby/securerandom
36
+ source_code_uri: https://github.com/ruby/securerandom
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 2.3.0
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubygems_version: 3.2.0.rc.1
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Interface for secure random number generator.
56
+ test_files: []