Skip to content

Commit

Permalink
Use faster OpenSSL secure_compare if available
Browse files Browse the repository at this point in the history
Comparing a 16 byte string:
openssl_secure_compare:  9397508.4 i/s
   rack_secure_compare:   515938.0 i/s - 18.21x  (± 0.00) slower
  • Loading branch information
bdewater authored and ioquatix committed Nov 13, 2020
1 parent cd5d902 commit 03b4b97
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file. For info on
- `Rack::Request#[]` and `#[]=` now warn even in non-verbose mode. ([#1277](https://github.com/rack/rack/issues/1277), [@jeremyevans](https://github.com/jeremyevans))
- Decrease default allowed parameter recursion level from 100 to 32. ([#1640](https://github.com/rack/rack/issues/1640), [@jeremyevans](https://github.com/jeremyevans))
- Attempting to parse a multipart response with an empty body now raises Rack::Multipart::EmptyContentError. ([#1603](https://github.com/rack/rack/issues/1603), [@jeremyevans](https://github.com/jeremyevans))
- `Rack::Utils.secure_compare` uses OpenSSL's faster implementation if available. ([#1711](https://github.com/rack/rack/pull/1711), [@bdewater](https://github.com/bdewater))

### Fixed

Expand Down
20 changes: 14 additions & 6 deletions lib/rack/utils.rb
Expand Up @@ -374,14 +374,22 @@ def get_byte_ranges(http_range, size)
# that have already been processed by HMAC. This should not be used
# on variable length plaintext strings because it could leak length info
# via timing attacks.
def secure_compare(a, b)
return false unless a.bytesize == b.bytesize
if defined?(OpenSSL.fixed_length_secure_compare)
def secure_compare(a, b)
return false unless a.bytesize == b.bytesize

l = a.unpack("C*")
OpenSSL.fixed_length_secure_compare(a, b)
end
else
def secure_compare(a, b)
return false unless a.bytesize == b.bytesize

r, i = 0, -1
b.each_byte { |v| r |= v ^ l[i += 1] }
r == 0
l = a.unpack("C*")

r, i = 0, -1
b.each_byte { |v| r |= v ^ l[i += 1] }
r == 0
end
end

# Context allows the use of a compatible middleware at different points
Expand Down

1 comment on commit 03b4b97

@b24-74usry
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SSL

Please sign in to comment.