aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart de Water <bartdewater@gmail.com>2019-10-26 12:13:25 -0400
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2019-10-28 17:54:29 +1300
commit308fb199811d085c771e421eb304b4aedf501262 (patch)
tree6d7c16c61506d537db049797d881e5a4c5a20fbe
parent0faa750c223e2aec90637d895e23a3104266fd85 (diff)
downloadruby-openssl-308fb199811d085c771e421eb304b4aedf501262.tar.gz
Add OpenSSL.secure_compare with same semantics as Active Support >= 5.2
secure_compare is for user input, fixed_length_secure_compare for already processed data that is known to have the same length
-rw-r--r--lib/openssl.rb14
-rw-r--r--test/test_ossl.rb17
2 files changed, 31 insertions, 0 deletions
diff --git a/lib/openssl.rb b/lib/openssl.rb
index 09142829..47a8fc49 100644
--- a/lib/openssl.rb
+++ b/lib/openssl.rb
@@ -20,3 +20,17 @@ require 'openssl/digest'
require 'openssl/x509'
require 'openssl/ssl'
require 'openssl/pkcs5'
+
+module OpenSSL
+ # call-seq:
+ # OpenSSL.secure_compare(string, string) -> boolean
+ #
+ # Constant time memory comparison. Inputs are hashed using SHA-256 to mask
+ # the length of the secret. Returns +true+ if the strings are identical,
+ # +false+ otherwise.
+ def self.secure_compare(a, b)
+ hashed_a = OpenSSL::Digest::SHA256.digest(a)
+ hashed_b = OpenSSL::Digest::SHA256.digest(b)
+ OpenSSL.fixed_length_secure_compare(hashed_a, hashed_b) && a == b
+ end
+end
diff --git a/test/test_ossl.rb b/test/test_ossl.rb
index 85363cb5..394f30e0 100644
--- a/test/test_ossl.rb
+++ b/test/test_ossl.rb
@@ -26,6 +26,23 @@ class OpenSSL::OSSL < OpenSSL::SSLTestCase
assert_raises(ArgumentError) { OpenSSL.fixed_length_secure_compare("aaa", "bbbb") }
end
+ def test_secure_compare
+ refute OpenSSL.secure_compare("aaa", "a")
+ refute OpenSSL.secure_compare("aaa", "aa")
+
+ assert OpenSSL.secure_compare("aaa", "aaa")
+
+ refute OpenSSL.secure_compare("aaa", "aaaa")
+ refute OpenSSL.secure_compare("aaa", "baa")
+ refute OpenSSL.secure_compare("aaa", "aba")
+ refute OpenSSL.secure_compare("aaa", "aab")
+ refute OpenSSL.secure_compare("aaa", "aaab")
+ refute OpenSSL.secure_compare("aaa", "b")
+ refute OpenSSL.secure_compare("aaa", "bb")
+ refute OpenSSL.secure_compare("aaa", "bbb")
+ refute OpenSSL.secure_compare("aaa", "bbbb")
+ end
+
def test_memcmp_timing
# Ensure using fixed_length_secure_compare takes almost exactly the same amount of time to compare two different strings.
# Regular string comparison will short-circuit on the first non-matching character, failing this test.