module RbNaCl::Util

Various utility functions

Public Instance Methods

bin2hex(bytes) click to toggle source

Hex encodes a message

@param [String] bytes The bytes to encode

@return [String] Tasty, tasty hexadecimal

# File lib/rbnacl/util.rb, line 277
def bin2hex(bytes)
  bytes.to_s.unpack("H*").first
end
check_hmac_key(string, _description) click to toggle source

Check a passed in string, convertion if necessary

This method will check the key, and raise error if argument is not a string, and if it's empty string.

RFC 2104 HMAC The key for HMAC can be of any length (keys longer than B bytes are first hashed using H). However, less than L bytes is strongly discouraged as it would decrease the security strength of the function. Keys longer than L bytes are acceptable but the extra length would not significantly increase the function strength. (A longer key may be advisable if the randomness of the key is considered weak.)

see tools.ietf.org/html/rfc2104#section-3

@raise [ArgumentError] If we cannot convert to a string with to_str @raise [RbNaCl::LengthError] If the string is empty

@param string [#to_str] The input string

# File lib/rbnacl/util.rb, line 140
def check_hmac_key(string, _description)
  check_string_validation(string)

  string = string.to_str

  if string.bytesize.zero?
    raise LengthError,
          "#{Description} was #{string.bytesize} bytes (Expected more than 0)",
          caller
  end

  string
end
check_length(string, length, description) click to toggle source

Check the length of the passed in string

In several places through the codebase we have to be VERY strict with what length of string we accept. This method supports that.

@raise [RbNaCl::LengthError] If the string is not the right length

@param string [String] The string to compare @param length [Integer] The desired length @param description [String] Description of the string (used in the error)

# File lib/rbnacl/util.rb, line 83
def check_length(string, length, description)
  if string.nil?
    # code below is runs only in test cases
    # nil can't be converted to str with #to_str method
    raise LengthError,
          "#{description} was nil (Expected #{length.to_int})",
          caller
  end

  if string.bytesize != length.to_int
    raise LengthError,
          "#{description} was #{string.bytesize} bytes (Expected #{length.to_int})",
          caller
  end
  true
end
check_string(string, length, description) click to toggle source

Check a passed in string, converting the argument if necessary

In several places through the codebase we have to be VERY strict with the strings we accept. This method supports that.

@raise [ArgumentError] If we cannot convert to a string with to_str @raise [RbNaCl::LengthError] If the string is not the right length

@param string [#to_str] The input string @param length [Integer] The only acceptable length of the string @param description [String] Description of the string (used in the error)

# File lib/rbnacl/util.rb, line 111
def check_string(string, length, description)
  check_string_validation(string)
  string = string.to_s
  check_length(string, length, description)

  string
end
check_string_validation(string) click to toggle source

Check a passed string is it valid

Raise an error if passed argument is invalid

@raise [TypeError] If string cannot convert to a string with to_str @raise [EncodingError] If string have wrong encoding

@param string [#to_str] The input string

# File lib/rbnacl/util.rb, line 162
def check_string_validation(string)
  raise TypeError, "can't convert #{string.class} into String with #to_str" unless string.respond_to? :to_str

  string = string.to_str

  raise EncodingError, "strings must use BINARY encoding (got #{string.encoding})" if string.encoding != Encoding::BINARY
end
hex2bin(hex) click to toggle source

Hex decodes a message

@param [String] hex hex to decode.

@return [String] crisp and clean bytes

# File lib/rbnacl/util.rb, line 286
def hex2bin(hex)
  [hex.to_s].pack("H*")
end
prepend_zeros(n, message) click to toggle source

Prepends a message with zeros

Many functions require a string with some zeros prepended.

@param [Integer] n The number of zeros to prepend @param [String] message The string to be prepended

@return [String] a bunch of zeros

# File lib/rbnacl/util.rb, line 37
def prepend_zeros(n, message)
  zeros(n) + message
end
remove_zeros(n, message) click to toggle source

Remove zeros from the start of a message

Many functions require a string with some zeros prepended, then need them removing after. Note: this modifies the passed in string

@param [Integer] n The number of zeros to remove @param [String] message The string to be slice

@return [String] less a bunch of zeros

# File lib/rbnacl/util.rb, line 50
def remove_zeros(n, message)
  message.slice!(n, message.bytesize - n)
end
verify16(one, two) click to toggle source

Compare two 16 byte strings in constant time

This should help to avoid timing attacks for string comparisons in your application. Note that many of the functions (such as OneTime#verify) use this method under the hood already.

@param [String] one String #1 @param [String] two String #2

@return [Boolean] Well, are they equal?

# File lib/rbnacl/util.rb, line 248
def verify16(one, two)
  return false unless two.bytesize == 16 && one.bytesize == 16

  c_verify16(one, two)
end
verify16!(one, two) click to toggle source

Compare two 16 byte strings in constant time

This should help to avoid timing attacks for string comparisons in your application. Note that many of the functions (such as OneTime#verify) use this method under the hood already.

@param [String] one String #1 @param [String] two String #2

@raise [ArgumentError] If the strings are not equal in length

@return [Boolean] Well, are they equal?

# File lib/rbnacl/util.rb, line 266
def verify16!(one, two)
  check_length(one, 16, "First message")
  check_length(two, 16, "Second message")
  c_verify16(one, two)
end
verify32(one, two) click to toggle source

Compare two 32 byte strings in constant time

This should help to avoid timing attacks for string comparisons in your application. Note that many of the functions (such as HmacSha256#verify) use this method under the hood already.

@param [String] one String #1 @param [String] two String #2

@return [Boolean] Well, are they equal?

# File lib/rbnacl/util.rb, line 214
def verify32(one, two)
  return false unless two.bytesize == 32 && one.bytesize == 32

  c_verify32(one, two)
end
verify32!(one, two) click to toggle source

Compare two 32 byte strings in constant time

This should help to avoid timing attacks for string comparisons in your application. Note that many of the functions (such as HmacSha256#verify) use this method under the hood already.

@param [String] one String #1 @param [String] two String #2

@raise [ArgumentError] If the strings are not equal in length

@return [Boolean] Well, are they equal?

# File lib/rbnacl/util.rb, line 232
def verify32!(one, two)
  check_length(one, 32, "First message")
  check_length(two, 32, "Second message")
  c_verify32(one, two)
end
verify64(one, two) click to toggle source

Compare two 64 byte strings in constant time

This should help to avoid timing attacks for string comparisons in your application. Note that many of the functions (such as HmacSha512#verify) use this method under the hood already.

@param [String] one String #1 @param [String] two String #2

@return [Boolean] Well, are they equal?

# File lib/rbnacl/util.rb, line 180
def verify64(one, two)
  return false unless two.bytesize == 64 && one.bytesize == 64

  c_verify64(one, two)
end
verify64!(one, two) click to toggle source

Compare two 64 byte strings in constant time

This should help to avoid timing attacks for string comparisons in your application. Note that many of the functions (such as HmacSha512#verify) use this method under the hood already.

@param [String] one String #1 @param [String] two String #2

@raise [ArgumentError] If the strings are not equal in length

@return [Boolean] Well, are they equal?

# File lib/rbnacl/util.rb, line 198
def verify64!(one, two)
  check_length(one, 64, "First message")
  check_length(two, 64, "Second message")
  c_verify64(one, two)
end
zero_pad(n, message) click to toggle source

Pad a string out to n characters with zeros

@param [Integer] n The length of the resulting string @param [String] message the message to be padded

@raise [RbNaCl::LengthError] If the string is too long

@return [String] A string, n bytes long

# File lib/rbnacl/util.rb, line 62
def zero_pad(n, message)
  len = message.bytesize
  if len == n
    message
  elsif len > n
    raise LengthError, "String too long for zero-padding to #{n} bytes"
  else
    message + zeros(n - len)
  end
end
zeros(n = 32) click to toggle source

Returns a string of n zeros

Lots of the functions require us to create strings to pass into functions of a specified size.

@param [Integer] n the size of the string to make

@return [String] A nice collection of zeros

# File lib/rbnacl/util.rb, line 22
def zeros(n = 32)
  zeros = "\0" * n
  # make sure they're 8-bit zeros, not 7-bit zeros.  Otherwise we might get
  # encoding errors later
  zeros.respond_to?(:force_encoding) ? zeros.force_encoding("ASCII-8BIT") : zeros
end