diff options
author | James Tucker <jftucker@gmail.com> | 2013-02-06 15:31:53 -0800 |
---|---|---|
committer | James Tucker <jftucker@gmail.com> | 2013-02-07 14:40:17 -0800 |
commit | fa2db31472d4bb32700b6f1d18a6884fd32e6856 (patch) | |
tree | ab434e2ab8119b0f23a2f42dc748de6716cbbe23 | |
parent | 22ef9e18198eaa4cb7c6c38df296a2fa7c5d8581 (diff) | |
download | rack-fa2db31472d4bb32700b6f1d18a6884fd32e6856.tar.gz |
Add secure_compare to Rack::Utils
Conflicts: lib/rack/utils.rb test/spec_utils.rb
-rw-r--r-- | lib/rack/utils.rb | 25 | ||||
-rw-r--r-- | test/spec_utils.rb | 7 |
2 files changed, 31 insertions, 1 deletions
diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb index 7dff2873..282fca93 100644 --- a/lib/rack/utils.rb +++ b/lib/rack/utils.rb @@ -298,6 +298,31 @@ module Rack end module_function :rfc2822 + # Return the bytesize of String; uses String#length under Ruby 1.8 and + # String#bytesize under 1.9. + if ''.respond_to?(:bytesize) + def bytesize(string) + string.bytesize + end + else + def bytesize(string) + string.size + end + end + module_function :bytesize + + # Constant time string comparison. + def secure_compare(a, b) + return false unless bytesize(a) == bytesize(b) + + l = a.unpack("C*") + + r, i = 0, -1 + b.each_byte { |v| r |= v ^ l[i+=1] } + r == 0 + end + module_function :secure_compare + # Context allows the use of a compatible middleware at different points # in a request handling stack. A compatible middleware must define # #context which should take the arguments env and app. The first of which diff --git a/test/spec_utils.rb b/test/spec_utils.rb index 92770e35..5f234f1d 100644 --- a/test/spec_utils.rb +++ b/test/spec_utils.rb @@ -274,7 +274,12 @@ describe Rack::Utils do Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6 end - should "return status code for integer" do + should "should perform constant time string comparison" do + Rack::Utils.secure_compare('a', 'a').should.equal true + Rack::Utils.secure_compare('a', 'b').should.equal false + end + + should "should return status code for integer" do Rack::Utils.status_code(200).should.equal 200 end |