securerandom 0.2.2 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ae0b7af17b7e1ae5e5538a9faf771856d7052e570dd2edb7f3876b44ff73caa
4
- data.tar.gz: 99bbfb8ac5dfa0f2089e4b8ab18a9dcf3628bb1b2564778b14045056e6473879
3
+ metadata.gz: 6f14853630e9280f98e432e1da48fd1eb894a7376c4e3678dc97639e28929c3d
4
+ data.tar.gz: 79846163a70d7b0198271a61ce63a7320c9a141dd59d0912a91e9a5259353999
5
5
  SHA512:
6
- metadata.gz: 5a6b61eecc2cf9681ea54abc84909635dca596e1ff453c5af84e75e87b042345e5d9b55f30a99149c61f7407e9238993dbc836efc9feb03067cb0538770cfa5d
7
- data.tar.gz: c458cecffdea575d9eea0ec41341520d1465d359dda792b8448149a5c32b6e76ccf8f85074c919a97d916dfe379e41f97d461e5dd242a155708808cf99dc7e07
6
+ metadata.gz: 7d448c439592c67f07e543c855fa4c06e6da72ce84d31ade33ea97d76d5ee90952b575c938a34bf8e11453353920582d0d5311cf9212b6ba7397fa3d038bc2e5
7
+ data.tar.gz: c3080d88c1a11a88ca3a28ddc6e173ab5afbf6027d60c353263ed9f78b8982a55dcc15c4a88cc3f2a44ba6e8a5933d7283af91b2f38965f67ebd68e636d78922
@@ -4,10 +4,10 @@ Redistribution and use in source and binary forms, with or without
4
4
  modification, are permitted provided that the following conditions
5
5
  are met:
6
6
  1. Redistributions of source code must retain the above copyright
7
- notice, this list of conditions and the following disclaimer.
7
+ notice, this list of conditions and the following disclaimer.
8
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.
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
11
 
12
12
  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
13
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
data/COPYING ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a. place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b. use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c. give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d. make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a. distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b. accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c. give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d. make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
@@ -165,15 +165,133 @@ module Random::Formatter
165
165
  #
166
166
  # The result contains 122 random bits (15.25 random bytes).
167
167
  #
168
- # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
168
+ # See RFC9562[https://www.rfc-editor.org/rfc/rfc9562] for details of UUIDv4.
169
169
  #
170
170
  def uuid
171
- ary = random_bytes(16).unpack("NnnnnN")
172
- ary[2] = (ary[2] & 0x0fff) | 0x4000
173
- ary[3] = (ary[3] & 0x3fff) | 0x8000
174
- "%08x-%04x-%04x-%04x-%04x%08x" % ary
171
+ ary = random_bytes(16)
172
+ ary.setbyte(6, (ary.getbyte(6) & 0x0f) | 0x40)
173
+ ary.setbyte(8, (ary.getbyte(8) & 0x3f) | 0x80)
174
+ ary.unpack("H8H4H4H4H12").join(?-)
175
175
  end
176
176
 
177
+ alias uuid_v4 uuid
178
+
179
+ # Generate a random v7 UUID (Universally Unique IDentifier).
180
+ #
181
+ # require 'random/formatter'
182
+ #
183
+ # Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
184
+ # Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
185
+ # Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
186
+ # Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
187
+ # # |<--sorted-->| |<----- random ---->|
188
+ #
189
+ # # or
190
+ # prng = Random.new
191
+ # prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
192
+ #
193
+ # The version 7 UUID starts with the least significant 48 bits of a 64 bit
194
+ # Unix timestamp (milliseconds since the epoch) and fills the remaining bits
195
+ # with random data, excluding the version and variant bits.
196
+ #
197
+ # This allows version 7 UUIDs to be sorted by creation time. Time ordered
198
+ # UUIDs can be used for better database index locality of newly inserted
199
+ # records, which may have a significant performance benefit compared to random
200
+ # data inserts.
201
+ #
202
+ # The result contains 74 random bits (9.25 random bytes).
203
+ #
204
+ # Note that this method cannot be made reproducible because its output
205
+ # includes not only random bits but also timestamp.
206
+ #
207
+ # See RFC9562[https://www.rfc-editor.org/rfc/rfc9562] for details of UUIDv7.
208
+ #
209
+ # ==== Monotonicity
210
+ #
211
+ # UUIDv7 has millisecond precision by default, so multiple UUIDs created
212
+ # within the same millisecond are not issued in monotonically increasing
213
+ # order. To create UUIDs that are time-ordered with sub-millisecond
214
+ # precision, up to 12 bits of additional timestamp may added with
215
+ # +extra_timestamp_bits+. The extra timestamp precision comes at the expense
216
+ # of random bits. Setting <tt>extra_timestamp_bits: 12</tt> provides ~244ns
217
+ # of precision, but only 62 random bits (7.75 random bytes).
218
+ #
219
+ # prng = Random.new
220
+ # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
221
+ # # =>
222
+ # ["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
223
+ # "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
224
+ # "0188d4c7-13da-754a-88ea-ac0baeedd8db",
225
+ # "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
226
+ # # |<--- sorted --->| |<-- random --->|
227
+ #
228
+ # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
229
+ # # =>
230
+ # ["0188d4c7-3333-7a95-850a-de6edb858f7e",
231
+ # "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
232
+ # "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
233
+ # "0188d4c7-3333-7af9-87c3-8f612edac82e"]
234
+ # # |<--- sorted -->||<---- random --->|
235
+ #
236
+ # Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
237
+ # on UTC, which excludes leap seconds and can rollback the clock. To avoid
238
+ # this, the system clock can synchronize with an NTP server configured to use
239
+ # a "leap smear" approach. NTP or PTP will also be needed to synchronize
240
+ # across distributed nodes.
241
+ #
242
+ # Counters and other mechanisms for stronger guarantees of monotonicity are
243
+ # not implemented. Applications with stricter requirements should follow
244
+ # {Section 6.2}[https://www.rfc-editor.org/rfc/rfc9562.html#name-monotonicity-and-counters]
245
+ # of the specification.
246
+ #
247
+ def uuid_v7(extra_timestamp_bits: 0)
248
+ case (extra_timestamp_bits = Integer(extra_timestamp_bits))
249
+ when 0 # min timestamp precision
250
+ ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
251
+ rand = random_bytes(10)
252
+ rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version
253
+ rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant
254
+ "%08x-%04x-%s" % [
255
+ (ms & 0x0000_ffff_ffff_0000) >> 16,
256
+ (ms & 0x0000_0000_0000_ffff),
257
+ rand.unpack("H4H4H12").join("-")
258
+ ]
259
+
260
+ when 12 # max timestamp precision
261
+ ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
262
+ .divmod(1_000_000)
263
+ extra_bits = ns * 4096 / 1_000_000
264
+ rand = random_bytes(8)
265
+ rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant
266
+ "%08x-%04x-7%03x-%s" % [
267
+ (ms & 0x0000_ffff_ffff_0000) >> 16,
268
+ (ms & 0x0000_0000_0000_ffff),
269
+ extra_bits,
270
+ rand.unpack("H4H12").join("-")
271
+ ]
272
+
273
+ when (0..12) # the generic version is slower than the special cases above
274
+ rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN")
275
+ rand_mask_bits = 12 - extra_timestamp_bits
276
+ ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
277
+ .divmod(1_000_000)
278
+ "%08x-%04x-%04x-%04x-%04x%08x" % [
279
+ (ms & 0x0000_ffff_ffff_0000) >> 16,
280
+ (ms & 0x0000_0000_0000_ffff),
281
+ 0x7000 |
282
+ ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) |
283
+ rand_a & ((1 << rand_mask_bits) - 1),
284
+ 0x8000 | (rand_b1 & 0x3fff),
285
+ rand_b2,
286
+ rand_b3
287
+ ]
288
+
289
+ else
290
+ raise ArgumentError, "extra_timestamp_bits must be in 0..12"
291
+ end
292
+ end
293
+
294
+ # Internal interface to Random; Generate random data _n_ bytes.
177
295
  private def gen_random(n)
178
296
  self.bytes(n)
179
297
  end
@@ -221,16 +339,20 @@ module Random::Formatter
221
339
  result
222
340
  end
223
341
 
342
+ # The default character list for #alphanumeric.
224
343
  ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
344
+
225
345
  # Generate a random alphanumeric string.
226
346
  #
227
347
  # The argument _n_ specifies the length, in characters, of the alphanumeric
228
348
  # string to be generated.
349
+ # The argument _chars_ specifies the character list which the result is
350
+ # consist of.
229
351
  #
230
352
  # If _n_ is not specified or is nil, 16 is assumed.
231
353
  # It may be larger in the future.
232
354
  #
233
- # The result may contain A-Z, a-z and 0-9.
355
+ # The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
234
356
  #
235
357
  # require 'random/formatter'
236
358
  #
@@ -238,8 +360,13 @@ module Random::Formatter
238
360
  # # or
239
361
  # prng = Random.new
240
362
  # prng.alphanumeric(10) #=> "i6K93NdqiH"
241
- def alphanumeric(n=nil)
363
+ #
364
+ # Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
365
+ # # or
366
+ # prng = Random.new
367
+ # prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
368
+ def alphanumeric(n = nil, chars: ALPHANUMERIC)
242
369
  n = 16 if n.nil?
243
- choose(ALPHANUMERIC, n)
370
+ choose(chars, n)
244
371
  end
245
372
  end
data/lib/securerandom.rb CHANGED
@@ -39,28 +39,28 @@ require 'random/formatter'
39
39
  # +NotImplementedError+ is raised.
40
40
 
41
41
  module SecureRandom
42
+
43
+ # The version
44
+ VERSION = "0.3.2"
45
+
42
46
  class << self
47
+ # Returns a random binary string containing +size+ bytes.
48
+ #
49
+ # See Random.bytes
43
50
  def bytes(n)
44
51
  return gen_random(n)
45
52
  end
46
53
 
47
54
  private
48
55
 
56
+ # :stopdoc:
57
+
58
+ # Implementation using OpenSSL
49
59
  def gen_random_openssl(n)
50
- @pid = 0 unless defined?(@pid)
51
- pid = $$
52
- unless @pid == pid
53
- now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
54
- OpenSSL::Random.random_add([now, @pid, pid].join(""), 0.0)
55
- seed = Random.urandom(16)
56
- if (seed)
57
- OpenSSL::Random.random_add(seed, 16)
58
- end
59
- @pid = pid
60
- end
61
60
  return OpenSSL::Random.random_bytes(n)
62
61
  end
63
62
 
63
+ # Implementation using system random device
64
64
  def gen_random_urandom(n)
65
65
  ret = Random.urandom(n)
66
66
  unless ret
@@ -86,6 +86,9 @@ module SecureRandom
86
86
  end
87
87
  end
88
88
 
89
+ # :startdoc:
90
+
91
+ # Generate random data bytes for Random::Formatter
89
92
  public :gen_random
90
93
  end
91
94
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: securerandom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanaka Akira
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-14 00:00:00.000000000 Z
11
+ date: 2024-11-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Interface for secure random number generator.
14
14
  email:
@@ -17,19 +17,11 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - ".github/dependabot.yml"
21
- - ".github/workflows/test.yml"
22
- - ".gitignore"
23
- - Gemfile
24
- - LICENSE.txt
20
+ - BSDL
21
+ - COPYING
25
22
  - README.md
26
- - Rakefile
27
- - bin/console
28
- - bin/setup
29
23
  - lib/random/formatter.rb
30
24
  - lib/securerandom.rb
31
- - rakelib/epoch.rake
32
- - securerandom.gemspec
33
25
  homepage: https://github.com/ruby/securerandom
34
26
  licenses:
35
27
  - Ruby
@@ -37,7 +29,7 @@ licenses:
37
29
  metadata:
38
30
  homepage_uri: https://github.com/ruby/securerandom
39
31
  source_code_uri: https://github.com/ruby/securerandom
40
- post_install_message:
32
+ post_install_message:
41
33
  rdoc_options: []
42
34
  require_paths:
43
35
  - lib
@@ -52,8 +44,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
52
44
  - !ruby/object:Gem::Version
53
45
  version: '0'
54
46
  requirements: []
55
- rubygems_version: 3.4.0.dev
56
- signing_key:
47
+ rubygems_version: 3.5.11
48
+ signing_key:
57
49
  specification_version: 4
58
50
  summary: Interface for secure random number generator.
59
51
  test_files: []
@@ -1,6 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: 'github-actions'
4
- directory: '/'
5
- schedule:
6
- interval: 'weekly'
@@ -1,22 +0,0 @@
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: [ head, '3.0', '2.7', '2.6' ]
11
- os: [ ubuntu-latest, macos-latest, windows-latest ]
12
- runs-on: ${{ matrix.os }}
13
- steps:
14
- - uses: actions/checkout@v3
15
- - name: Set up Ruby
16
- uses: ruby/setup-ruby@v1
17
- with:
18
- ruby-version: ${{ matrix.ruby }}
19
- - name: Install dependencies
20
- run: bundle install
21
- - name: Run test
22
- run: rake test
data/.gitignore DELETED
@@ -1,8 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem "rake"
4
- gem "test-unit"
data/Rakefile DELETED
@@ -1,10 +0,0 @@
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
data/bin/console DELETED
@@ -1,14 +0,0 @@
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__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
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
data/rakelib/epoch.rake DELETED
@@ -1,5 +0,0 @@
1
- task "build" => "date_epoch"
2
-
3
- task "date_epoch" do
4
- ENV["SOURCE_DATE_EPOCH"] = IO.popen(%W[git -C #{__dir__} log -1 --format=%ct], &:read).chomp
5
- end
data/securerandom.gemspec DELETED
@@ -1,22 +0,0 @@
1
- Gem::Specification.new do |spec|
2
- spec.name = "securerandom"
3
- spec.version = "0.2.2"
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.6.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