mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
f76ca450f5
Even that collisions are unlikely we need to make sure the two strings are equal. Timing is not important in this case because this only runs after the comparison between the SHA256 digested strings returns true.
31 lines
995 B
Ruby
31 lines
995 B
Ruby
# frozen_string_literal: true
|
|
|
|
require "digest/sha2"
|
|
|
|
module ActiveSupport
|
|
module SecurityUtils
|
|
# Constant time string comparison, for fixed length strings.
|
|
#
|
|
# The values compared should be of fixed length, such as strings
|
|
# 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
|
|
|
|
l = a.unpack "C#{a.bytesize}"
|
|
|
|
res = 0
|
|
b.each_byte { |byte| res |= byte ^ l.shift }
|
|
res == 0
|
|
end
|
|
module_function :fixed_length_secure_compare
|
|
|
|
# Constant time string comparison, for variable length strings.
|
|
#
|
|
# The values are first processed by SHA256, so that we don't leak length info
|
|
# via timing attacks.
|
|
def secure_compare(a, b)
|
|
fixed_length_secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b)) && a == b
|
|
end
|
|
module_function :secure_compare
|
|
end
|
|
end
|