hkdf 0.1.0 → 0.2.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.
data/README.md CHANGED
@@ -18,6 +18,14 @@ hkdf.next_bytes(16)
18
18
  => "\xC0<\x13\x85\x8C\x84z\xCE\xC7\xCE+\xFF\x1C\xEB\xE6\xBC"
19
19
  ```
20
20
 
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 ```:read_size``` can be used to control how many bytes are read from the IO at a time.
22
+
23
+ ```ruby
24
+ hkdf = HKDF.new(File.new('/tmp/filename'), :read_size => 512)
25
+ hkdf.next_bytes(32)
26
+ => "\f#\xF4b\x98\x9B\x7Fw>|/|k\xF4k\xB7\xB9\x11e\xC5\x92\xD1\fH\xFDG\x94vt\xB4\x14\xCE"
27
+ ```
28
+
21
29
  ## License
22
30
 
23
31
  The HKDF gem is released under the [MIT license](http://www.opensource.org/licenses/MIT).
@@ -1,16 +1,21 @@
1
1
  require 'openssl'
2
+ require 'stringio'
2
3
 
3
4
  class HKDF
5
+ DefaultReadSize = 512 * 1024
6
+
4
7
  def initialize(source, options = {})
5
- options = {:algorithm => 'SHA256', :info => '', :salt => nil}.merge(options)
8
+ options = {:algorithm => 'SHA256', :info => '', :salt => nil, :read_size => nil}.merge(options)
9
+ source = StringIO.new(source) if source.is_a?(String)
6
10
 
7
11
  @digest = OpenSSL::Digest.new(options[:algorithm])
8
12
  @info = options[:info]
9
13
 
10
14
  salt = options[:salt]
11
15
  salt = 0.chr * @digest.digest_length if salt.nil? or salt.empty?
16
+ read_size = options[:read_size] || DefaultReadSize
12
17
 
13
- @prk = OpenSSL::HMAC.digest(@digest, salt, source)
18
+ @prk = _generate_prk(salt, source, read_size)
14
19
  @position = 0
15
20
  @blocks = []
16
21
  @blocks << ''
@@ -50,6 +55,14 @@ class HKDF
50
55
  next_bytes(length).unpack('H*').first
51
56
  end
52
57
 
58
+ def _generate_prk(salt, source, read_size)
59
+ hmac = OpenSSL::HMAC.new(salt, @digest)
60
+ while block = source.read(read_size)
61
+ hmac.update(block)
62
+ end
63
+ hmac.digest
64
+ end
65
+
53
66
  def _generate_blocks(length)
54
67
  start = @blocks.size
55
68
  block_count = (length.to_f / @digest.digest_length).ceil
@@ -8,6 +8,26 @@ describe HKDF do
8
8
  end
9
9
 
10
10
  describe 'initialize' do
11
+ 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
15
+ end
16
+
17
+ it 'reads in an IO at a given read size' do
18
+ io = StringIO.new(@source)
19
+ io.should_receive(:read).with(1)
20
+
21
+ HKDF.new(io, :read_size => 1)
22
+ end
23
+
24
+ it 'reads in the whole IO' do
25
+ hkdf1 = HKDF.new(@source, :read_size => 1)
26
+ hkdf2 = HKDF.new(@source)
27
+
28
+ hkdf1.next_bytes(32).should == hkdf2.next_bytes(32)
29
+ end
30
+
11
31
  it 'defaults the algorithm to SHA-256' do
12
32
  HKDF.new(@source).algorithm.should == 'SHA256'
13
33
  end
@@ -46,15 +66,15 @@ describe HKDF do
46
66
 
47
67
  describe 'next_bytes' do
48
68
  it 'raises an error if requested size is > max_length' do
49
- expect { @hkdf.next_bytes(@hkdf.max_length + 1) }.should raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
50
- expect { @hkdf.next_bytes(@hkdf.max_length) }.should_not raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
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)
51
71
  end
52
72
 
53
73
  it 'raises an error if requested size + current position is > max_length' do
54
74
  expect do
55
75
  @hkdf.next_bytes(32)
56
76
  @hkdf.next_bytes(@hkdf.max_length - 31)
57
- end.should raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
77
+ end.to raise_error(RangeError, /requested \d+ bytes, only \d+ available/)
58
78
  end
59
79
 
60
80
  it 'advances the stream position' do
@@ -86,8 +106,8 @@ describe HKDF do
86
106
  end
87
107
 
88
108
  it 'raises an error if requested to seek past end of stream' do
89
- expect { @hkdf.seek(@hkdf.max_length + 1) }.should raise_error(RangeError, /cannot seek past \d+/)
90
- expect { @hkdf.seek(@hkdf.max_length) }.should_not raise_error(RangeError, /cannot seek past \d+/)
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)
91
111
  end
92
112
  end
93
113
 
@@ -1,5 +1,10 @@
1
1
  require 'hkdf'
2
2
 
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.order = 'random'
6
+ end
7
+
3
8
  def test_vectors
4
9
  test_lines = File.readlines('spec/test_vectors.txt').map(&:strip).reject(&:empty?)
5
10
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hkdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-14 00:00:00.000000000 Z
12
+ date: 2012-09-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70196819801820 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,12 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70196819801820
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  description: ! 'A ruby implementation of RFC5869: HMAC-based Extract-and-Expand Key
26
31
  Derivation Function (HKDF). The goal of HKDF is to take some source key material
27
32
  and generate suitable cryptographic keys from it.'
@@ -56,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
61
  version: '0'
57
62
  requirements: []
58
63
  rubyforge_project:
59
- rubygems_version: 1.8.17
64
+ rubygems_version: 1.8.23
60
65
  signing_key:
61
66
  specification_version: 3
62
67
  summary: HMAC-based Key Derivation Function