hkdf 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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