Module: RbNaCl::Util

Extended by:
Sodium
Defined in:
lib/rbnacl/util.rb

Overview

Various utility functions

Class Method Summary collapse

Methods included from Sodium

primitive, sodium_constant, sodium_function, sodium_function_with_return_code, sodium_primitive, sodium_type

Class Method Details

.bin2hex(bytes) ⇒ String

Hex encodes a message


277
278
279
# File 'lib/rbnacl/util.rb', line 277

def bin2hex(bytes)
  bytes.to_s.unpack("H*").first
end

.check_hmac_key(string, _description) ⇒ Object

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 https://tools.ietf.org/html/rfc2104#section-3

Raises:

  • (ArgumentError)

    If we cannot convert to a string with #to_str

  • (RbNaCl::LengthError)

    If the string is empty


140
141
142
143
144
145
146
147
148
149
150
151
152
# 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) ⇒ Object

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.

Raises:


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 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) ⇒ Object

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.

Raises:

  • (ArgumentError)

    If we cannot convert to a string with #to_str

  • (RbNaCl::LengthError)

    If the string is not the right length


111
112
113
114
115
116
117
# 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) ⇒ Object

Check a passed string is it valid

Raise an error if passed argument is invalid

Raises:

  • (TypeError)

    If string cannot convert to a string with #to_str

  • (EncodingError)

    If string have wrong encoding


162
163
164
165
166
167
168
# 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) ⇒ String

Hex decodes a message


286
287
288
# File 'lib/rbnacl/util.rb', line 286

def hex2bin(hex)
  [hex.to_s].pack("H*")
end

.prepend_zeros(n, message) ⇒ String

Prepends a message with zeros

Many functions require a string with some zeros prepended.


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

def prepend_zeros(n, message)
  zeros(n) + message
end

.remove_zeros(n, message) ⇒ String

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


50
51
52
# File 'lib/rbnacl/util.rb', line 50

def remove_zeros(n, message)
  message.slice!(n, message.bytesize - n)
end

.verify16(one, two) ⇒ Boolean

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.


248
249
250
251
252
# 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) ⇒ Boolean

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.

Raises:

  • (ArgumentError)

    If the strings are not equal in length


266
267
268
269
270
# 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) ⇒ Boolean

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.


214
215
216
217
218
# 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) ⇒ Boolean

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.

Raises:

  • (ArgumentError)

    If the strings are not equal in length


232
233
234
235
236
# 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) ⇒ Boolean

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.


180
181
182
183
184
# 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) ⇒ Boolean

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.

Raises:

  • (ArgumentError)

    If the strings are not equal in length


198
199
200
201
202
# 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) ⇒ String

Pad a string out to n characters with zeros

Raises:


62
63
64
65
66
67
68
69
70
71
# 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) ⇒ String

Returns a string of n zeros

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


22
23
24
25
26
27
# 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