hkdf 0.2.0 → 0.3.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 +7 -0
- data/LICENSE +19 -0
- data/README.md +0 -4
- data/lib/hkdf.rb +10 -5
- data/spec/{test_vectors.txt → fixtures/test_vectors.txt} +9 -0
- data/spec/hkdf_spec.rb +53 -42
- data/spec/spec_helper.rb +8 -9
- metadata +46 -20
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 32e2c102c323f4510551f669261ce3fe39c11dc3
|
4
|
+
data.tar.gz: f2585bdce88e509b0d7acf699b0313029fb767ab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 303d49a8b562e90325cc90fe5bb1ce6294de07973d6f974f136c50bc9ae23e02cb09f36c725be7394e610bd4526beea9f61b9b5aee67fa7f370a0e553a4b1713
|
7
|
+
data.tar.gz: 1037d09b22dac87dea10a86a8ec1dea9f84390d43d5a9d5ace084e1d6c02a0e50ce57015a916dad6fe75f58683487cee911043168f63119c15da12ea17347685
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2013 John Downey
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -25,7 +25,3 @@ hkdf = HKDF.new(File.new('/tmp/filename'), :read_size => 512)
|
|
25
25
|
hkdf.next_bytes(32)
|
26
26
|
=> "\f#\xF4b\x98\x9B\x7Fw>|/|k\xF4k\xB7\xB9\x11e\xC5\x92\xD1\fH\xFDG\x94vt\xB4\x14\xCE"
|
27
27
|
```
|
28
|
-
|
29
|
-
## License
|
30
|
-
|
31
|
-
The HKDF gem is released under the [MIT license](http://www.opensource.org/licenses/MIT).
|
data/lib/hkdf.rb
CHANGED
@@ -2,18 +2,19 @@ require 'openssl'
|
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
class HKDF
|
5
|
+
DefaultAlgorithm = 'SHA256'
|
5
6
|
DefaultReadSize = 512 * 1024
|
6
7
|
|
7
8
|
def initialize(source, options = {})
|
8
|
-
options = {:algorithm => 'SHA256', :info => '', :salt => nil, :read_size => nil}.merge(options)
|
9
9
|
source = StringIO.new(source) if source.is_a?(String)
|
10
10
|
|
11
|
-
|
12
|
-
@
|
11
|
+
algorithm = options.fetch(:algorithm, DefaultAlgorithm)
|
12
|
+
@digest = OpenSSL::Digest.new(algorithm)
|
13
|
+
@info = options.fetch(:info, '')
|
13
14
|
|
14
15
|
salt = options[:salt]
|
15
16
|
salt = 0.chr * @digest.digest_length if salt.nil? or salt.empty?
|
16
|
-
read_size = options
|
17
|
+
read_size = options.fetch(:read_size, DefaultReadSize)
|
17
18
|
|
18
19
|
@prk = _generate_prk(salt, source, read_size)
|
19
20
|
@position = 0
|
@@ -26,7 +27,7 @@ class HKDF
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def max_length
|
29
|
-
@digest.digest_length * 255
|
30
|
+
@max_length ||= @digest.digest_length * 255
|
30
31
|
end
|
31
32
|
|
32
33
|
def seek(position)
|
@@ -55,6 +56,10 @@ class HKDF
|
|
55
56
|
next_bytes(length).unpack('H*').first
|
56
57
|
end
|
57
58
|
|
59
|
+
def inspect
|
60
|
+
"#{to_s[0..-2]} algorithm=#{@digest.name.inspect} info=#{@info.inspect}>"
|
61
|
+
end
|
62
|
+
|
58
63
|
def _generate_prk(salt, source, read_size)
|
59
64
|
hmac = OpenSSL::HMAC.new(salt, @digest)
|
60
65
|
while block = source.read(read_size)
|
@@ -51,3 +51,12 @@ info =
|
|
51
51
|
L = 42
|
52
52
|
PRK = 0xda8c8a73c7fa77288ec6f5e7c297786aa0d32d01
|
53
53
|
OKM = 0x0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918
|
54
|
+
|
55
|
+
Test with SHA-1, salt not provided (defaults to HashLen zero octets), zero-length info
|
56
|
+
Hash = SHA1
|
57
|
+
IKM = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
|
58
|
+
salt =
|
59
|
+
info =
|
60
|
+
L = 42
|
61
|
+
PRK = 0x2adccada18779e7c2077ad2eb19d3f3e731385dd
|
62
|
+
OKM = 0x2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48
|
data/spec/hkdf_spec.rb
CHANGED
@@ -1,84 +1,88 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe HKDF do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@hkdf = HKDF.new(@source, :algorithm => @algorithm)
|
4
|
+
let(:source) { 'source' }
|
5
|
+
subject(:hkdf) do
|
6
|
+
HKDF.new(source)
|
8
7
|
end
|
9
8
|
|
10
9
|
describe 'initialize' do
|
11
10
|
it 'accepts an IO or a string as a source' do
|
12
|
-
output1 = HKDF.new(
|
13
|
-
output2 = HKDF.new(StringIO.new(
|
14
|
-
output1.
|
11
|
+
output1 = HKDF.new(source).next_bytes(32)
|
12
|
+
output2 = HKDF.new(StringIO.new(source)).next_bytes(32)
|
13
|
+
expect(output1).to eq(output2)
|
15
14
|
end
|
16
15
|
|
17
16
|
it 'reads in an IO at a given read size' do
|
18
|
-
io = StringIO.new(
|
19
|
-
io.
|
17
|
+
io = StringIO.new(source)
|
18
|
+
expect(io).to receive(:read).with(1)
|
20
19
|
|
21
20
|
HKDF.new(io, :read_size => 1)
|
22
21
|
end
|
23
22
|
|
24
23
|
it 'reads in the whole IO' do
|
25
|
-
hkdf1 = HKDF.new(
|
26
|
-
hkdf2 = HKDF.new(
|
24
|
+
hkdf1 = HKDF.new(source, :read_size => 1)
|
25
|
+
hkdf2 = HKDF.new(source)
|
27
26
|
|
28
|
-
hkdf1.next_bytes(32).
|
27
|
+
expect(hkdf1.next_bytes(32)).to eq(hkdf2.next_bytes(32))
|
29
28
|
end
|
30
29
|
|
31
30
|
it 'defaults the algorithm to SHA-256' do
|
32
|
-
HKDF.new(
|
31
|
+
expect(HKDF.new(source).algorithm).to eq('SHA256')
|
33
32
|
end
|
34
33
|
|
35
34
|
it 'takes an optional digest algorithm' do
|
36
|
-
|
37
|
-
|
35
|
+
hkdf = HKDF.new('source', :algorithm => 'SHA1')
|
36
|
+
expect(hkdf.algorithm).to eq('SHA1')
|
38
37
|
end
|
39
38
|
|
40
39
|
it 'defaults salt to all zeros of digest length' do
|
41
40
|
salt = 0.chr * 32
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
hkdf_salt = HKDF.new(source, :salt => salt)
|
43
|
+
hkdf_nosalt = HKDF.new(source)
|
44
|
+
expect(hkdf_salt.next_bytes(32)).to eq(hkdf_nosalt.next_bytes(32))
|
46
45
|
end
|
47
46
|
|
48
|
-
it 'sets salt to all zeros
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
it 'sets salt to all zeros if empty' do
|
48
|
+
hkdf_blanksalt = HKDF.new(source, :salt => '')
|
49
|
+
hkdf_nosalt = HKDF.new(source)
|
50
|
+
expect(hkdf_blanksalt.next_bytes(32)).to eq(hkdf_nosalt.next_bytes(32))
|
52
51
|
end
|
53
52
|
|
54
53
|
it 'defaults info to an empty string' do
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
hkdf_info = HKDF.new(source, :info => '')
|
55
|
+
hkdf_noinfo = HKDF.new(source)
|
56
|
+
expect(hkdf_info.next_bytes(32)).to eq(hkdf_noinfo.next_bytes(32))
|
58
57
|
end
|
59
58
|
end
|
60
59
|
|
61
60
|
describe 'max_length' do
|
62
61
|
it 'is 255 times the digest length' do
|
63
|
-
|
62
|
+
expect(hkdf.max_length).to eq(255 * 32)
|
64
63
|
end
|
65
64
|
end
|
66
65
|
|
67
66
|
describe 'next_bytes' do
|
68
67
|
it 'raises an error if requested size is > max_length' do
|
69
|
-
expect
|
70
|
-
|
68
|
+
expect do
|
69
|
+
hkdf.next_bytes(hkdf.max_length + 1)
|
70
|
+
end.to raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
|
71
|
+
|
72
|
+
expect do
|
73
|
+
hkdf.next_bytes(hkdf.max_length)
|
74
|
+
end.to_not raise_error
|
71
75
|
end
|
72
76
|
|
73
77
|
it 'raises an error if requested size + current position is > max_length' do
|
74
78
|
expect do
|
75
|
-
|
76
|
-
|
79
|
+
hkdf.next_bytes(32)
|
80
|
+
hkdf.next_bytes(hkdf.max_length - 31)
|
77
81
|
end.to raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
|
78
82
|
end
|
79
83
|
|
80
84
|
it 'advances the stream position' do
|
81
|
-
|
85
|
+
expect(hkdf.next_bytes(32)).not_to eq(hkdf.next_bytes(32))
|
82
86
|
end
|
83
87
|
|
84
88
|
test_vectors.each do |name, options|
|
@@ -86,36 +90,43 @@ describe HKDF do
|
|
86
90
|
options[:algorithm] = options[:Hash]
|
87
91
|
|
88
92
|
hkdf = HKDF.new(options[:IKM], options)
|
89
|
-
hkdf.next_bytes(options[:L].to_i).
|
93
|
+
expect(hkdf.next_bytes(options[:L].to_i)).to eq(options[:OKM])
|
90
94
|
end
|
91
95
|
end
|
92
96
|
end
|
93
97
|
|
94
98
|
describe 'next_hex_bytes' do
|
95
99
|
it 'returns the next bytes as hex' do
|
96
|
-
|
100
|
+
expect(hkdf.next_hex_bytes(20)).to eq('fb496612b8cb82cd2297770f83c72b377af16d7b')
|
97
101
|
end
|
98
102
|
end
|
99
103
|
|
100
104
|
describe 'seek' do
|
101
105
|
it 'sets the position anywhere in the stream' do
|
102
|
-
|
103
|
-
output =
|
104
|
-
|
105
|
-
|
106
|
+
hkdf.next_bytes(10)
|
107
|
+
output = hkdf.next_bytes(32)
|
108
|
+
hkdf.seek(10)
|
109
|
+
expect(hkdf.next_bytes(32)).to eq(output)
|
106
110
|
end
|
107
111
|
|
108
112
|
it 'raises an error if requested to seek past end of stream' do
|
109
|
-
expect {
|
110
|
-
expect {
|
113
|
+
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
|
111
115
|
end
|
112
116
|
end
|
113
117
|
|
114
118
|
describe 'rewind' do
|
115
119
|
it 'resets the stream position to the beginning' do
|
116
|
-
output =
|
117
|
-
|
118
|
-
|
120
|
+
output = hkdf.next_bytes(32)
|
121
|
+
hkdf.rewind
|
122
|
+
expect(hkdf.next_bytes(32)).to eq(output)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'inspect' do
|
127
|
+
it 'returns minimal information' do
|
128
|
+
hkdf = HKDF.new('secret', info: 'public')
|
129
|
+
expect(hkdf.inspect).to match(/^#<HKDF:0x[\h]+ algorithm="SHA256" info="public">$/)
|
119
130
|
end
|
120
131
|
end
|
121
132
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
require 'hkdf'
|
2
2
|
|
3
3
|
RSpec.configure do |config|
|
4
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
5
4
|
config.order = 'random'
|
6
5
|
end
|
7
6
|
|
8
7
|
def test_vectors
|
9
|
-
|
8
|
+
test_parts = File.readlines('spec/fixtures/test_vectors.txt').
|
9
|
+
map(&:strip).
|
10
|
+
reject(&:empty?).
|
11
|
+
each_slice(8)
|
10
12
|
|
11
|
-
vectors
|
12
|
-
test_lines.each_slice(8) do |lines|
|
13
|
+
test_parts.reduce({}) do |vectors, lines|
|
13
14
|
name = lines.shift
|
14
|
-
values = lines.
|
15
|
+
values = lines.reduce({}) do |hash, line|
|
15
16
|
key, value = line.split('=').map(&:strip)
|
16
17
|
value = '' unless value
|
17
18
|
value = [value.slice(2..-1)].pack('H*') if value.start_with?('0x')
|
18
|
-
hash
|
19
|
-
hash
|
19
|
+
hash.merge(key.to_sym => value)
|
20
20
|
end
|
21
|
-
vectors
|
21
|
+
vectors.merge(name => values)
|
22
22
|
end
|
23
|
-
vectors
|
24
23
|
end
|
metadata
CHANGED
@@ -1,33 +1,58 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hkdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- John Downey
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-11-09 00:00:00.000000000 Z
|
13
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.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 10.5.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 10.5.0
|
14
41
|
- !ruby/object:Gem::Dependency
|
15
42
|
name: rspec
|
16
43
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
44
|
requirements:
|
19
|
-
- -
|
45
|
+
- - '='
|
20
46
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
47
|
+
version: 3.4.0
|
22
48
|
type: :development
|
23
49
|
prerelease: false
|
24
50
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
51
|
requirements:
|
27
|
-
- -
|
52
|
+
- - '='
|
28
53
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
30
|
-
description:
|
54
|
+
version: 3.4.0
|
55
|
+
description: 'A ruby implementation of RFC5869: HMAC-based Extract-and-Expand Key
|
31
56
|
Derivation Function (HKDF). The goal of HKDF is to take some source key material
|
32
57
|
and generate suitable cryptographic keys from it.'
|
33
58
|
email:
|
@@ -36,36 +61,37 @@ executables: []
|
|
36
61
|
extensions: []
|
37
62
|
extra_rdoc_files: []
|
38
63
|
files:
|
39
|
-
-
|
64
|
+
- LICENSE
|
40
65
|
- README.md
|
66
|
+
- lib/hkdf.rb
|
67
|
+
- spec/fixtures/test_vectors.txt
|
41
68
|
- spec/hkdf_spec.rb
|
42
69
|
- spec/spec_helper.rb
|
43
|
-
- spec/test_vectors.txt
|
44
70
|
homepage: http://github.com/jtdowney/hkdf
|
45
|
-
licenses:
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
46
74
|
post_install_message:
|
47
75
|
rdoc_options: []
|
48
76
|
require_paths:
|
49
77
|
- lib
|
50
78
|
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
79
|
requirements:
|
53
|
-
- -
|
80
|
+
- - ">="
|
54
81
|
- !ruby/object:Gem::Version
|
55
82
|
version: '0'
|
56
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
84
|
requirements:
|
59
|
-
- -
|
85
|
+
- - ">="
|
60
86
|
- !ruby/object:Gem::Version
|
61
87
|
version: '0'
|
62
88
|
requirements: []
|
63
89
|
rubyforge_project:
|
64
|
-
rubygems_version:
|
90
|
+
rubygems_version: 2.5.1
|
65
91
|
signing_key:
|
66
|
-
specification_version:
|
92
|
+
specification_version: 4
|
67
93
|
summary: HMAC-based Key Derivation Function
|
68
94
|
test_files:
|
95
|
+
- spec/fixtures/test_vectors.txt
|
69
96
|
- spec/hkdf_spec.rb
|
70
97
|
- spec/spec_helper.rb
|
71
|
-
- spec/test_vectors.txt
|