Class: HKDF

Inherits:
Object
  • Object
show all
Defined in:
lib/hkdf.rb,
lib/hkdf/version.rb

Overview

Provide HMAC-based Extract-and-Expand Key Derivation Function (HKDF) for Ruby.

Constant Summary collapse

DEFAULT_ALGOTIHM =

Default hash algorithm to use for HMAC.

"SHA256"
DEFAULT_READ_SIZE =

Default buffer size for reading source IO.

512 * 1024
VERSION =

:nodoc:

"1.0.0"

Instance Method Summary collapse

Constructor Details

#initialize(source, options = {}) ⇒ HKDF

Create a new HKDF instance with then provided source key material.

Options:

  • algorithm: hash function to use (defaults to SHA-256)

  • info: optional context and application specific information

  • salt: optional salt value (a non-secret random value)

  • read_size: buffer size when reading from a source IO


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/hkdf.rb', line 20

def initialize(source, options = {})
  source = StringIO.new(source) if source.is_a?(String)

  algorithm = options.fetch(:algorithm, DEFAULT_ALGOTIHM)
  @digest = OpenSSL::Digest.new(algorithm)
  @info = options.fetch(:info, "")

  salt = options[:salt]
  salt = 0.chr * @digest.digest_length if salt.nil? || salt.empty?
  read_size = options.fetch(:read_size, DEFAULT_READ_SIZE)

  @prk = generate_prk(salt, source, read_size)
  @position = 0
  @blocks = [""]
end

Instance Method Details

#algorithmObject

Returns the hash algorithm this instance was configured with.


37
38
39
# File 'lib/hkdf.rb', line 37

def algorithm
  @digest.name
end

#inspectObject

:nodoc:


79
80
81
# File 'lib/hkdf.rb', line 79

def inspect
  "#{to_s[0..-2]} algorithm=#{@digest.name.inspect} info=#{@info.inspect}>"
end

#max_lengthObject

Maximum length that can be derived per the RFC.


42
43
44
# File 'lib/hkdf.rb', line 42

def max_length
  @max_length ||= @digest.digest_length * 255
end

#read(length) ⇒ Object

Read the next length bytes from the stream. Will raise RangeError if you attempt to read beyond #max_length.

Raises:

  • (RangeError)

60
61
62
63
64
65
66
67
68
69
70
# File 'lib/hkdf.rb', line 60

def read(length)
  new_position = length + @position
  raise RangeError, "requested #{length} bytes, only #{max_length} available" if new_position > max_length

  generate_blocks(new_position)

  start = @position
  @position = new_position

  @blocks.join.slice(start, length)
end

#read_hex(length) ⇒ Object

Read the next length bytes from the stream and return them hex encoded. Will raise RangeError if you attempt to read beyond #max_length.


74
75
76
# File 'lib/hkdf.rb', line 74

def read_hex(length)
  read(length).unpack1("H*")
end

#rewindObject

Adjust reading position back to the beginning.


55
56
57
# File 'lib/hkdf.rb', line 55

def rewind
  seek(0)
end

#seek(position) ⇒ Object

Adjust the reading position to an arbitrary offset. Will raise RangeError if you attempt to seek longer than #max_length.

Raises:

  • (RangeError)

48
49
50
51
52
# File 'lib/hkdf.rb', line 48

def seek(position)
  raise RangeError, "cannot seek past #{max_length}" if position > max_length

  @position = position
end