2017-07-09 08:06:36 -04:00
|
|
|
# frozen_string_literal: true
|
2017-07-10 09:39:13 -04:00
|
|
|
|
2017-09-25 08:06:15 -04:00
|
|
|
require "digest/sha2"
|
2015-10-29 13:42:44 -04:00
|
|
|
|
2014-10-23 09:56:48 -04:00
|
|
|
module ActiveSupport
|
|
|
|
module SecurityUtils
|
2016-04-11 17:11:06 -04:00
|
|
|
# Constant time string comparison, for fixed length strings.
|
2014-10-23 09:56:48 -04:00
|
|
|
#
|
|
|
|
# The values compared should be of fixed length, such as strings
|
2016-04-11 17:11:06 -04:00
|
|
|
# that have already been processed by HMAC. Raises in case of length mismatch.
|
|
|
|
def fixed_length_secure_compare(a, b)
|
|
|
|
raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
|
2014-10-23 09:56:48 -04:00
|
|
|
|
|
|
|
l = a.unpack "C#{a.bytesize}"
|
|
|
|
|
|
|
|
res = 0
|
|
|
|
b.each_byte { |byte| res |= byte ^ l.shift }
|
|
|
|
res == 0
|
|
|
|
end
|
2016-04-11 17:11:06 -04:00
|
|
|
module_function :fixed_length_secure_compare
|
2015-10-29 13:42:44 -04:00
|
|
|
|
2020-05-04 13:30:45 -04:00
|
|
|
# Secure string comparison for strings of variable length.
|
2016-04-11 17:11:06 -04:00
|
|
|
#
|
2020-05-04 13:30:45 -04:00
|
|
|
# While a timing attack would not be able to discern the content of
|
|
|
|
# a secret compared via secure_compare, it is possible to determine
|
|
|
|
# the secret length. This should be considered when using secure_compare
|
|
|
|
# to compare weak, short secrets to user input.
|
2016-04-11 17:11:06 -04:00
|
|
|
def secure_compare(a, b)
|
2020-05-04 13:30:45 -04:00
|
|
|
a.length == b.length && fixed_length_secure_compare(a, b)
|
2015-10-29 13:42:44 -04:00
|
|
|
end
|
2016-04-11 17:11:06 -04:00
|
|
|
module_function :secure_compare
|
2014-10-23 09:56:48 -04:00
|
|
|
end
|
|
|
|
end
|