From 308fb199811d085c771e421eb304b4aedf501262 Mon Sep 17 00:00:00 2001 From: Bart de Water Date: Sat, 26 Oct 2019 12:13:25 -0400 Subject: 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 --- lib/openssl.rb | 14 ++++++++++++++ test/test_ossl.rb | 17 +++++++++++++++++ 2 files changed, 31 insertions(+) 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. -- cgit v1.2.3