From bbc1553b5917b7fd02c20c11a0a9a8d1c6a6be9d Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Thu, 6 Aug 2015 14:06:03 -0400 Subject: [PATCH] Use a constant-time secure comparison for passwords Use a constant-time byte-by-byte secure comparison to compare potential password hashes rather than `String#==`, which uses strcmp under the hood and stops as soon as there's an unmatched byte. --- lib/bcrypt/password.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/bcrypt/password.rb b/lib/bcrypt/password.rb index fd19b47..f05deb6 100644 --- a/lib/bcrypt/password.rb +++ b/lib/bcrypt/password.rb @@ -61,9 +61,17 @@ def initialize(raw_hash) end end - # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise. + # Compares a potential secret against the hash using a constant-time comparison function. Returns true if the secret + # is the original secret, false otherwise. def ==(secret) - super(BCrypt::Engine.hash_secret(secret, @salt)) + hash = BCrypt::Engine.hash_secret(secret, @salt) + + return false if hash.strip.empty? || strip.empty? || hash.bytesize != bytesize + l = hash.unpack "C#{hash.bytesize}" + + res = 0 + each_byte { |byte| res |= byte ^ l.shift } + res == 0 end alias_method :is_password?, :==