hkdf 0.3.0 → 1.0.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 +5 -5
- data/README.md +11 -5
- data/lib/hkdf.rb +44 -22
- data/lib/hkdf/version.rb +6 -0
- data/spec/hkdf_spec.rb +74 -67
- data/spec/spec_helper.rb +5 -20
- data/spec/support/test_vectors.rb +30 -0
- metadata +54 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b3981a10daf0d498be5d757d585f60d5b7ed39510da169fd57caaf05cfd19b55
|
4
|
+
data.tar.gz: 639210e0fa56a62d07483f2e67e8df7b20d35fb55f0ca55296509f1a029c906c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62d0e251f2ecc9f713571a38388851a3781667c3de53f339061a7663fdb09f9a78705df12828151b5d252a59754cd401ab80dd95e36f96a255018f1721b4203d
|
7
|
+
data.tar.gz: 8be1132f9dc82666401d1034e509c3ce02aff76f63c0c033b716d50836d805747e90cc1358105176e0df9c9cbc2658aa6a23e1140d0c4c52ff11d9cc02f3a4d0
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# HKDF
|
1
|
+
# HKDF
|
2
|
+
|
3
|
+
[](https://github.com/jtdowney/hkdf/actions/workflows/ci.yml)
|
2
4
|
|
3
5
|
This is a ruby implementation of [RFC 5869](http://tools.ietf.org/html/rfc5869): HMAC-based Extract-and-Expand Key Derivation Function. The goal of HKDF is to take some source key material and generate suitable cryptographic keys from it.
|
4
6
|
|
@@ -6,7 +8,7 @@ This is a ruby implementation of [RFC 5869](http://tools.ietf.org/html/rfc5869):
|
|
6
8
|
|
7
9
|
```ruby
|
8
10
|
hkdf = HKDF.new('source key material')
|
9
|
-
hkdf.
|
11
|
+
hkdf.read(32)
|
10
12
|
=> "\f#\xF4b\x98\x9B\x7Fw>|/|k\xF4k\xB7\xB9\x11e\xC5\x92\xD1\fH\xFDG\x94vt\xB4\x14\xCE"
|
11
13
|
```
|
12
14
|
|
@@ -14,14 +16,18 @@ The default algorithm is HMAC-SHA256, you can override this and other defaults b
|
|
14
16
|
|
15
17
|
```ruby
|
16
18
|
hkdf = HKDF.new('source key material', :salt => 'NaCl', :algorithm => 'SHA1', :info => 'the 411')
|
17
|
-
hkdf.
|
19
|
+
hkdf.read(16)
|
18
20
|
=> "\xC0<\x13\x85\x8C\x84z\xCE\xC7\xCE+\xFF\x1C\xEB\xE6\xBC"
|
19
21
|
```
|
20
22
|
|
21
|
-
You can also give an IO object as the source. It will be read in as a stream to generate the key. The optional argument
|
23
|
+
You can also give an IO object as the source. It will be read in as a stream to generate the key. The optional argument `:read_size` can be used to control how many bytes are read from the IO at a time.
|
22
24
|
|
23
25
|
```ruby
|
24
26
|
hkdf = HKDF.new(File.new('/tmp/filename'), :read_size => 512)
|
25
|
-
hkdf.
|
27
|
+
hkdf.read(32)
|
26
28
|
=> "\f#\xF4b\x98\x9B\x7Fw>|/|k\xF4k\xB7\xB9\x11e\xC5\x92\xD1\fH\xFDG\x94vt\xB4\x14\xCE"
|
27
29
|
```
|
30
|
+
|
31
|
+
## Requirements
|
32
|
+
|
33
|
+
- Ruby >= 2.4
|
data/lib/hkdf.rb
CHANGED
@@ -1,74 +1,96 @@
|
|
1
|
-
|
2
|
-
require 'stringio'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
DefaultReadSize = 512 * 1024
|
3
|
+
require "openssl"
|
4
|
+
require "stringio"
|
7
5
|
|
6
|
+
# Provide HMAC-based Extract-and-Expand Key Derivation Function (HKDF) for Ruby.
|
7
|
+
class HKDF
|
8
|
+
# Default hash algorithm to use for HMAC.
|
9
|
+
DEFAULT_ALGOTIHM = "SHA256"
|
10
|
+
# Default buffer size for reading source IO.
|
11
|
+
DEFAULT_READ_SIZE = 512 * 1024
|
12
|
+
|
13
|
+
# Create a new HKDF instance with then provided +source+ key material.
|
14
|
+
#
|
15
|
+
# Options:
|
16
|
+
# - +algorithm:+ hash function to use (defaults to SHA-256)
|
17
|
+
# - +info:+ optional context and application specific information
|
18
|
+
# - +salt:+ optional salt value (a non-secret random value)
|
19
|
+
# - +read_size:+ buffer size when reading from a source IO
|
8
20
|
def initialize(source, options = {})
|
9
21
|
source = StringIO.new(source) if source.is_a?(String)
|
10
22
|
|
11
|
-
algorithm = options.fetch(:algorithm,
|
23
|
+
algorithm = options.fetch(:algorithm, DEFAULT_ALGOTIHM)
|
12
24
|
@digest = OpenSSL::Digest.new(algorithm)
|
13
|
-
@info = options.fetch(:info,
|
25
|
+
@info = options.fetch(:info, "")
|
14
26
|
|
15
27
|
salt = options[:salt]
|
16
|
-
salt = 0.chr * @digest.digest_length if salt.nil?
|
17
|
-
read_size = options.fetch(:read_size,
|
28
|
+
salt = 0.chr * @digest.digest_length if salt.nil? || salt.empty?
|
29
|
+
read_size = options.fetch(:read_size, DEFAULT_READ_SIZE)
|
18
30
|
|
19
|
-
@prk =
|
31
|
+
@prk = generate_prk(salt, source, read_size)
|
20
32
|
@position = 0
|
21
|
-
@blocks = []
|
22
|
-
@blocks << ''
|
33
|
+
@blocks = [""]
|
23
34
|
end
|
24
35
|
|
36
|
+
# Returns the hash algorithm this instance was configured with.
|
25
37
|
def algorithm
|
26
38
|
@digest.name
|
27
39
|
end
|
28
40
|
|
41
|
+
# Maximum length that can be derived per the RFC.
|
29
42
|
def max_length
|
30
43
|
@max_length ||= @digest.digest_length * 255
|
31
44
|
end
|
32
45
|
|
46
|
+
# Adjust the reading position to an arbitrary offset. Will raise +RangeError+ if you attempt to seek longer than
|
47
|
+
# +#max_length+.
|
33
48
|
def seek(position)
|
34
|
-
raise RangeError
|
49
|
+
raise RangeError, "cannot seek past #{max_length}" if position > max_length
|
35
50
|
|
36
51
|
@position = position
|
37
52
|
end
|
38
53
|
|
54
|
+
# Adjust reading position back to the beginning.
|
39
55
|
def rewind
|
40
56
|
seek(0)
|
41
57
|
end
|
42
58
|
|
43
|
-
|
59
|
+
# Read the next +length+ bytes from the stream. Will raise +RangeError+ if you attempt to read beyond +#max_length+.
|
60
|
+
def read(length)
|
44
61
|
new_position = length + @position
|
45
|
-
raise RangeError
|
62
|
+
raise RangeError, "requested #{length} bytes, only #{max_length} available" if new_position > max_length
|
46
63
|
|
47
|
-
|
64
|
+
generate_blocks(new_position)
|
48
65
|
|
49
66
|
start = @position
|
50
67
|
@position = new_position
|
51
68
|
|
52
|
-
@blocks.join
|
69
|
+
@blocks.join.slice(start, length)
|
53
70
|
end
|
54
71
|
|
55
|
-
|
56
|
-
|
72
|
+
# Read the next +length+ bytes from the stream and return them hex encoded. Will raise +RangeError+ if you attempt to
|
73
|
+
# read beyond +#max_length+.
|
74
|
+
def read_hex(length)
|
75
|
+
read(length).unpack1("H*")
|
57
76
|
end
|
58
77
|
|
78
|
+
# :nodoc:
|
59
79
|
def inspect
|
60
80
|
"#{to_s[0..-2]} algorithm=#{@digest.name.inspect} info=#{@info.inspect}>"
|
61
81
|
end
|
62
82
|
|
63
|
-
|
83
|
+
private
|
84
|
+
|
85
|
+
def generate_prk(salt, source, read_size)
|
64
86
|
hmac = OpenSSL::HMAC.new(salt, @digest)
|
65
|
-
while block = source.read(read_size)
|
87
|
+
while (block = source.read(read_size))
|
66
88
|
hmac.update(block)
|
67
89
|
end
|
68
90
|
hmac.digest
|
69
91
|
end
|
70
92
|
|
71
|
-
def
|
93
|
+
def generate_blocks(length)
|
72
94
|
start = @blocks.size
|
73
95
|
block_count = (length.to_f / @digest.digest_length).ceil
|
74
96
|
start.upto(block_count) do |n|
|
data/lib/hkdf/version.rb
ADDED
data/spec/hkdf_spec.rb
CHANGED
@@ -1,132 +1,139 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
2
4
|
|
3
5
|
describe HKDF do
|
4
|
-
let(:source) { 'source' }
|
5
6
|
subject(:hkdf) do
|
6
|
-
|
7
|
+
described_class.new(source)
|
7
8
|
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
let(:source) { "source" }
|
11
|
+
|
12
|
+
describe "initialize" do
|
13
|
+
it "accepts an IO or a string as a source" do
|
14
|
+
output1 = described_class.new(source).read(32)
|
15
|
+
output2 = described_class.new(StringIO.new(source)).read(32)
|
13
16
|
expect(output1).to eq(output2)
|
14
17
|
end
|
15
18
|
|
16
|
-
it
|
17
|
-
io = StringIO
|
18
|
-
|
19
|
-
|
20
|
-
HKDF.new(io, :read_size => 1)
|
19
|
+
it "reads in an IO at a given read size" do
|
20
|
+
io = instance_spy(StringIO, :io, read: nil)
|
21
|
+
described_class.new(io, read_size: 1)
|
22
|
+
expect(io).to have_received(:read).with(1)
|
21
23
|
end
|
22
24
|
|
23
|
-
it
|
24
|
-
hkdf1 =
|
25
|
-
hkdf2 =
|
25
|
+
it "reads in the whole IO" do
|
26
|
+
hkdf1 = described_class.new(source, read_size: 1)
|
27
|
+
hkdf2 = described_class.new(source)
|
26
28
|
|
27
|
-
expect(hkdf1.
|
29
|
+
expect(hkdf1.read(32)).to eq(hkdf2.read(32))
|
28
30
|
end
|
29
31
|
|
30
|
-
it
|
31
|
-
expect(
|
32
|
+
it "defaults the algorithm to SHA-256" do
|
33
|
+
expect(described_class.new(source).algorithm).to eq("SHA256")
|
32
34
|
end
|
33
35
|
|
34
|
-
it
|
35
|
-
hkdf =
|
36
|
-
expect(hkdf.algorithm).to eq(
|
36
|
+
it "takes an optional digest algorithm" do
|
37
|
+
hkdf = described_class.new("source", algorithm: "SHA1")
|
38
|
+
expect(hkdf.algorithm).to eq("SHA1")
|
37
39
|
end
|
38
40
|
|
39
|
-
it
|
41
|
+
it "defaults salt to all zeros of digest length" do
|
40
42
|
salt = 0.chr * 32
|
41
43
|
|
42
|
-
hkdf_salt =
|
43
|
-
hkdf_nosalt =
|
44
|
-
expect(hkdf_salt.
|
44
|
+
hkdf_salt = described_class.new(source, salt: salt)
|
45
|
+
hkdf_nosalt = described_class.new(source)
|
46
|
+
expect(hkdf_salt.read(32)).to eq(hkdf_nosalt.read(32))
|
45
47
|
end
|
46
48
|
|
47
|
-
it
|
48
|
-
hkdf_blanksalt =
|
49
|
-
hkdf_nosalt =
|
50
|
-
expect(hkdf_blanksalt.
|
49
|
+
it "sets salt to all zeros if empty" do
|
50
|
+
hkdf_blanksalt = described_class.new(source, salt: "")
|
51
|
+
hkdf_nosalt = described_class.new(source)
|
52
|
+
expect(hkdf_blanksalt.read(32)).to eq(hkdf_nosalt.read(32))
|
51
53
|
end
|
52
54
|
|
53
|
-
it
|
54
|
-
hkdf_info =
|
55
|
-
hkdf_noinfo =
|
56
|
-
expect(hkdf_info.
|
55
|
+
it "defaults info to an empty string" do
|
56
|
+
hkdf_info = described_class.new(source, info: "")
|
57
|
+
hkdf_noinfo = described_class.new(source)
|
58
|
+
expect(hkdf_info.read(32)).to eq(hkdf_noinfo.read(32))
|
57
59
|
end
|
58
60
|
end
|
59
61
|
|
60
|
-
describe
|
61
|
-
it
|
62
|
+
describe "max_length" do
|
63
|
+
it "is 255 times the digest length" do
|
62
64
|
expect(hkdf.max_length).to eq(255 * 32)
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
66
|
-
describe
|
67
|
-
it
|
68
|
+
describe "read" do
|
69
|
+
it "does not raise if reading <= max_length" do
|
68
70
|
expect do
|
69
|
-
hkdf.
|
70
|
-
end.
|
71
|
+
hkdf.read(hkdf.max_length)
|
72
|
+
end.not_to raise_error
|
73
|
+
end
|
71
74
|
|
75
|
+
it "raises an error if requested size is > max_length" do
|
72
76
|
expect do
|
73
|
-
hkdf.
|
74
|
-
end.
|
77
|
+
hkdf.read(hkdf.max_length + 1)
|
78
|
+
end.to raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
|
75
79
|
end
|
76
80
|
|
77
|
-
it
|
81
|
+
it "raises an error if requested size + current position is > max_length" do
|
78
82
|
expect do
|
79
|
-
hkdf.
|
80
|
-
hkdf.
|
83
|
+
hkdf.read(32)
|
84
|
+
hkdf.read(hkdf.max_length - 31)
|
81
85
|
end.to raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
|
82
86
|
end
|
83
87
|
|
84
|
-
it
|
85
|
-
expect(hkdf.
|
88
|
+
it "advances the stream position" do
|
89
|
+
expect(hkdf.read(32)).not_to eq(hkdf.read(32))
|
86
90
|
end
|
87
91
|
|
88
|
-
|
92
|
+
TestVectors.vectors.each do |name, options|
|
89
93
|
it "matches output from the '#{name}' test vector" do
|
90
94
|
options[:algorithm] = options[:Hash]
|
91
95
|
|
92
|
-
hkdf =
|
93
|
-
expect(hkdf.
|
96
|
+
hkdf = described_class.new(options[:IKM], options)
|
97
|
+
expect(hkdf.read(options[:L].to_i)).to eq(options[:OKM])
|
94
98
|
end
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
98
|
-
describe
|
99
|
-
it
|
100
|
-
expect(hkdf.
|
102
|
+
describe "read_hex" do
|
103
|
+
it "returns the next bytes as hex" do
|
104
|
+
expect(hkdf.read_hex(20)).to eq("fb496612b8cb82cd2297770f83c72b377af16d7b")
|
101
105
|
end
|
102
106
|
end
|
103
107
|
|
104
|
-
describe
|
105
|
-
it
|
106
|
-
hkdf.
|
107
|
-
output = hkdf.
|
108
|
+
describe "seek" do
|
109
|
+
it "sets the position anywhere in the stream" do
|
110
|
+
hkdf.read(10)
|
111
|
+
output = hkdf.read(32)
|
108
112
|
hkdf.seek(10)
|
109
|
-
expect(hkdf.
|
113
|
+
expect(hkdf.read(32)).to eq(output)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does not raise if <= max_length" do
|
117
|
+
expect { hkdf.seek(hkdf.max_length) }.not_to raise_error
|
110
118
|
end
|
111
119
|
|
112
|
-
it
|
120
|
+
it "raises an error if requested to seek past end of stream" do
|
113
121
|
expect { hkdf.seek(hkdf.max_length + 1) }.to raise_error(RangeError, /cannot seek past \d+/)
|
114
|
-
expect { hkdf.seek(hkdf.max_length) }.to_not raise_error
|
115
122
|
end
|
116
123
|
end
|
117
124
|
|
118
|
-
describe
|
119
|
-
it
|
120
|
-
output = hkdf.
|
125
|
+
describe "rewind" do
|
126
|
+
it "resets the stream position to the beginning" do
|
127
|
+
output = hkdf.read(32)
|
121
128
|
hkdf.rewind
|
122
|
-
expect(hkdf.
|
129
|
+
expect(hkdf.read(32)).to eq(output)
|
123
130
|
end
|
124
131
|
end
|
125
132
|
|
126
|
-
describe
|
127
|
-
it
|
128
|
-
hkdf =
|
129
|
-
expect(hkdf.inspect).to match(/^#<HKDF:0x[
|
133
|
+
describe "inspect" do
|
134
|
+
it "returns minimal information" do
|
135
|
+
hkdf = described_class.new("secret", info: "public")
|
136
|
+
expect(hkdf.inspect).to match(/^#<HKDF:0x[0-9a-f]+ algorithm="SHA256" info="public">$/)
|
130
137
|
end
|
131
138
|
end
|
132
139
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,23 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
end
|
3
|
+
require "hkdf"
|
4
|
+
require_relative "support/test_vectors"
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
map(&:strip).
|
10
|
-
reject(&:empty?).
|
11
|
-
each_slice(8)
|
12
|
-
|
13
|
-
test_parts.reduce({}) do |vectors, lines|
|
14
|
-
name = lines.shift
|
15
|
-
values = lines.reduce({}) do |hash, line|
|
16
|
-
key, value = line.split('=').map(&:strip)
|
17
|
-
value = '' unless value
|
18
|
-
value = [value.slice(2..-1)].pack('H*') if value.start_with?('0x')
|
19
|
-
hash.merge(key.to_sym => value)
|
20
|
-
end
|
21
|
-
vectors.merge(name => values)
|
22
|
-
end
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.order = "random"
|
23
8
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# :nodoc:
|
4
|
+
module TestVectors
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
def vectors
|
9
|
+
test_parts = File.readlines("spec/fixtures/test_vectors.txt")
|
10
|
+
.map(&:strip)
|
11
|
+
.reject(&:empty?)
|
12
|
+
.each_slice(8)
|
13
|
+
|
14
|
+
test_parts.reduce({}) do |vectors, lines|
|
15
|
+
name = lines.shift
|
16
|
+
values = split_test_vector(lines)
|
17
|
+
vectors.merge(name => values)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# :nodoc:
|
22
|
+
def split_test_vector(lines)
|
23
|
+
lines.reduce({}) do |hash, line|
|
24
|
+
key, value = line.split("=").map(&:strip)
|
25
|
+
value ||= ""
|
26
|
+
value = [value.slice(2..-1)].pack("H*") if value.start_with?("0x")
|
27
|
+
hash.merge(key.to_sym => value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,60 +1,88 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hkdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Downey
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '12.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '12.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '3.9'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '3.9'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '1.12'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop-rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
53
60
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
55
|
-
|
56
|
-
|
57
|
-
|
61
|
+
version: 0.5.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.5.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.2'
|
83
|
+
description: |
|
84
|
+
A ruby implementation of RFC5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF). The goal of HKDF is
|
85
|
+
to take some source key material and generate suitable cryptographic keys from it.
|
58
86
|
email:
|
59
87
|
- jdowney@gmail.com
|
60
88
|
executables: []
|
@@ -64,14 +92,16 @@ files:
|
|
64
92
|
- LICENSE
|
65
93
|
- README.md
|
66
94
|
- lib/hkdf.rb
|
95
|
+
- lib/hkdf/version.rb
|
67
96
|
- spec/fixtures/test_vectors.txt
|
68
97
|
- spec/hkdf_spec.rb
|
69
98
|
- spec/spec_helper.rb
|
99
|
+
- spec/support/test_vectors.rb
|
70
100
|
homepage: http://github.com/jtdowney/hkdf
|
71
101
|
licenses:
|
72
102
|
- MIT
|
73
103
|
metadata: {}
|
74
|
-
post_install_message:
|
104
|
+
post_install_message:
|
75
105
|
rdoc_options: []
|
76
106
|
require_paths:
|
77
107
|
- lib
|
@@ -79,19 +109,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
109
|
requirements:
|
80
110
|
- - ">="
|
81
111
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
112
|
+
version: 2.4.0
|
83
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
114
|
requirements:
|
85
115
|
- - ">="
|
86
116
|
- !ruby/object:Gem::Version
|
87
117
|
version: '0'
|
88
118
|
requirements: []
|
89
|
-
|
90
|
-
|
91
|
-
signing_key:
|
119
|
+
rubygems_version: 3.2.15
|
120
|
+
signing_key:
|
92
121
|
specification_version: 4
|
93
122
|
summary: HMAC-based Key Derivation Function
|
94
123
|
test_files:
|
95
124
|
- spec/fixtures/test_vectors.txt
|
96
125
|
- spec/hkdf_spec.rb
|
97
126
|
- spec/spec_helper.rb
|
127
|
+
- spec/support/test_vectors.rb
|