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.
@@ -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).
@@ -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
- @digest = OpenSSL::Digest.new(options[:algorithm])
12
- @info = options[:info]
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[:read_size] || DefaultReadSize
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
@@ -1,84 +1,88 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe HKDF do
4
- before(:each) do
5
- @algorithm = 'SHA256'
6
- @source = 'source'
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(@source).next_bytes(32)
13
- output2 = HKDF.new(StringIO.new(@source)).next_bytes(32)
14
- output1.should == output2
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(@source)
19
- io.should_receive(:read).with(1)
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(@source, :read_size => 1)
26
- hkdf2 = HKDF.new(@source)
24
+ hkdf1 = HKDF.new(source, :read_size => 1)
25
+ hkdf2 = HKDF.new(source)
27
26
 
28
- hkdf1.next_bytes(32).should == hkdf2.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(@source).algorithm.should == 'SHA256'
31
+ expect(HKDF.new(source).algorithm).to eq('SHA256')
33
32
  end
34
33
 
35
34
  it 'takes an optional digest algorithm' do
36
- @hkdf = HKDF.new('source', :algorithm => 'SHA1')
37
- @hkdf.algorithm.should == 'SHA1'
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
- @hkdf_salt = HKDF.new(@source, :algorithm => @algorithm, :salt => salt)
44
- @hkdf_nosalt = HKDF.new(@source, :algorithm => @algorithm)
45
- @hkdf_salt.next_bytes(32) == @hkdf_nosalt.next_bytes(32)
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 of digest 32 if empty' do
49
- @hkdf_blanksalt = HKDF.new(@source, :algorithm => @algorithm, :salt => '')
50
- @hkdf_nosalt = HKDF.new(@source, :algorithm => @algorithm)
51
- @hkdf_blanksalt.next_bytes(32) == @hkdf_nosalt.next_bytes(32)
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
- @hkdf_info = HKDF.new(@source, :algorithm => @algorithm, :info => '')
56
- @hkdf_noinfo = HKDF.new(@source, :algorithm => @algorithm)
57
- @hkdf_info.next_bytes(32) == @hkdf_noinfo.next_bytes(32)
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
- @hkdf.max_length.should == 255 * 32
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 { @hkdf.next_bytes(@hkdf.max_length + 1) }.to raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
70
- expect { @hkdf.next_bytes(@hkdf.max_length) }.to_not raise_error(RangeError)
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
- @hkdf.next_bytes(32)
76
- @hkdf.next_bytes(@hkdf.max_length - 31)
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
- @hkdf.next_bytes(32).should_not == @hkdf.next_bytes(32)
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).should == options[:OKM]
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
- @hkdf.next_hex_bytes(20).should == 'fb496612b8cb82cd2297770f83c72b377af16d7b'
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
- @hkdf.next_bytes(10)
103
- output = @hkdf.next_bytes(32)
104
- @hkdf.seek(10)
105
- @hkdf.next_bytes(32).should == output
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 { @hkdf.seek(@hkdf.max_length + 1) }.to raise_error(RangeError, /cannot seek past \d+/)
110
- expect { @hkdf.seek(@hkdf.max_length) }.to_not raise_error(RangeError)
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 = @hkdf.next_bytes(32)
117
- @hkdf.rewind
118
- @hkdf.next_bytes(32).should == output
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
@@ -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
- test_lines = File.readlines('spec/test_vectors.txt').map(&:strip).reject(&:empty?)
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.inject({}) do |hash, line|
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[key.to_sym] = value
19
- hash
19
+ hash.merge(key.to_sym => value)
20
20
  end
21
- vectors[name] = values
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.2.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: 2012-09-23 00:00:00.000000000 Z
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: '0'
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: '0'
30
- description: ! 'A ruby implementation of RFC5869: HMAC-based Extract-and-Expand Key
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
- - lib/hkdf.rb
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: 1.8.23
90
+ rubygems_version: 2.5.1
65
91
  signing_key:
66
- specification_version: 3
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