diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,13 @@
 # Changelog for password
 
+## 2.0.1.0
+
+-   Switched checking hashes to using `Data.ByteArray.constEq`, instead of
+    the default `(==)` method of `ByteString`. This is to make it more secure
+    against timing attacks. [#16](https://github.com/cdepillabout/password/pull/16)
+-   Thanks to maralorn ([@maralorn](https://github.com/maralorn)) for bringing
+    this up.
+
 ## 2.0.0.1
 
 -   Fixed README markdown for hackage.
@@ -47,4 +55,3 @@
 ## 0.1.0.0
 
 - Initial version.
-
diff --git a/password.cabal b/password.cabal
--- a/password.cabal
+++ b/password.cabal
@@ -1,7 +1,7 @@
 cabal-version: 1.12
 
 name:           password
-version:        2.0.0.1
+version:        2.0.1.0
 category:       Data
 synopsis:       Hashing and checking of passwords
 description:    A library providing functionality for working with plain-text and hashed passwords with different types of algorithms.
diff --git a/src/Data/Password/Argon2.hs b/src/Data/Password/Argon2.hs
--- a/src/Data/Password/Argon2.hs
+++ b/src/Data/Password/Argon2.hs
@@ -73,7 +73,7 @@
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Crypto.Error (throwCryptoError)
 import Crypto.KDF.Argon2 as Argon2
-import Data.ByteArray (Bytes, convert)
+import Data.ByteArray (Bytes, constEq, convert)
 import Data.ByteString (ByteString)
 import Data.ByteString.Base64 (encodeBase64)
 import qualified Data.ByteString.Char8 as C8 (length)
@@ -278,7 +278,7 @@
     hashedKey <- from64 hashedKey64
     let argon2OutputLength = fromIntegral $ C8.length hashedKey -- only here because of warnings
         producedKey = hashPasswordWithSalt' Argon2Params{..} (Salt salt) pass
-    guard $ hashedKey == producedKey
+    guard $ hashedKey `constEq` producedKey
     return PasswordCheckSuccess
   where
     argon2Salt = 16 -- only here because of warnings
diff --git a/src/Data/Password/Internal.hs b/src/Data/Password/Internal.hs
--- a/src/Data/Password/Internal.hs
+++ b/src/Data/Password/Internal.hs
@@ -29,8 +29,9 @@
 
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Crypto.Random (getRandomBytes)
-import Data.ByteArray (Bytes, convert)
+import Data.ByteArray (Bytes, constEq, convert)
 import Data.ByteString (ByteString)
+import Data.Function (on)
 import Data.ByteString.Base64 (decodeBase64)
 import Data.String (IsString(..))
 import Data.Text as T (Text, pack, unpack)
@@ -98,7 +99,10 @@
 -- The hashed password can be stored in a database.
 newtype PasswordHash a = PasswordHash
   { unPasswordHash :: Text
-  } deriving (Eq, Ord, Read, Show)
+  } deriving (Ord, Read, Show)
+
+instance Eq (PasswordHash a)  where
+  (==) = constEq `on` encodeUtf8 . unPasswordHash
 
 -- | The result of checking a password against a hashed version. This is
 -- returned by the @checkPassword@ functions.
diff --git a/src/Data/Password/PBKDF2.hs b/src/Data/Password/PBKDF2.hs
--- a/src/Data/Password/PBKDF2.hs
+++ b/src/Data/Password/PBKDF2.hs
@@ -69,7 +69,7 @@
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Crypto.Hash.Algorithms as Crypto (MD5(..))
 import Crypto.KDF.PBKDF2 as PBKDF2
-import Data.ByteArray (ByteArray, ByteArrayAccess, Bytes, convert)
+import Data.ByteArray (ByteArray, ByteArrayAccess, Bytes, constEq, convert)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Base64 as Base64
 import qualified Data.ByteString.Char8 as C8 (length)
@@ -239,7 +239,7 @@
     hashedKey <- from64 hashedKey64
     let pbkdf2OutputLength = fromIntegral $ C8.length hashedKey
         producedKey = hashPasswordWithSalt' PBKDF2Params{..} (Salt salt) pass
-    guard $ hashedKey == producedKey
+    guard $ hashedKey `constEq` producedKey
     return PasswordCheckSuccess
   where
     pbkdf2Salt = 16
diff --git a/src/Data/Password/Scrypt.hs b/src/Data/Password/Scrypt.hs
--- a/src/Data/Password/Scrypt.hs
+++ b/src/Data/Password/Scrypt.hs
@@ -64,7 +64,7 @@
 import Control.Monad (guard)
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Crypto.KDF.Scrypt as Scrypt
-import Data.ByteArray (Bytes, convert)
+import Data.ByteArray (Bytes, constEq, convert)
 import Data.ByteString (ByteString)
 import Data.ByteString.Base64 (encodeBase64)
 import qualified Data.ByteString.Char8 as C8 (length)
@@ -250,7 +250,7 @@
     hashedKey <- from64 hashedKey64
     let scryptOutputLength = fromIntegral $ C8.length hashedKey
         producedKey = hashPasswordWithSalt' ScryptParams{..} (Salt salt) pass
-    guard $ hashedKey == producedKey
+    guard $ hashedKey `constEq` producedKey
     return PasswordCheckSuccess
   where
     scryptSalt = 32 -- only here because of warnings
diff --git a/test/tasty/Bcrypt.hs b/test/tasty/Bcrypt.hs
--- a/test/tasty/Bcrypt.hs
+++ b/test/tasty/Bcrypt.hs
@@ -1,19 +1,15 @@
 module Bcrypt where
 
-import Data.Text (Text)
 import Test.Tasty
-import Test.Tasty.QuickCheck
-import Test.QuickCheck.Instances.Text ()
 
-import Data.Password
 import Data.Password.Bcrypt
 
-import Internal (testCorrectPassword, testIncorrectPassword_, testWithSalt)
+import Internal (testCorrectPassword, testIncorrectPassword, testWithSalt)
 
 
 testBcrypt :: TestTree
 testBcrypt = testGroup "bcrypt"
   [ testCorrectPassword "Bcrypt (hashPassword)" (hashPasswordWithParams 4) checkPassword
-  , testIncorrectPassword_ "Bcrypt (hashPassword) fail" (hashPasswordWithParams 4) checkPassword
+  , testIncorrectPassword "Bcrypt (hashPassword) fail" (hashPasswordWithParams 4) checkPassword
   , testWithSalt "Bcrypt (hashPasswordWithSalt)" (hashPasswordWithSalt 4) checkPassword
   ]
diff --git a/test/tasty/Internal.hs b/test/tasty/Internal.hs
--- a/test/tasty/Internal.hs
+++ b/test/tasty/Internal.hs
@@ -3,7 +3,6 @@
 module Internal where
 
 import Data.ByteArray (pack)
-import Data.Text (Text)
 import Test.Tasty
 import Test.Tasty.QuickCheck
 import Test.QuickCheck.Instances.Text ()
@@ -16,7 +15,7 @@
                     -> (Password -> PasswordHash a -> PasswordCheck)
                     -> TestTree
 testCorrectPassword s hashF checkF = testProperty s $
-  \pass -> run10 $ do
+  \pass -> ioProperty $ do
     let pw = mkPassword pass
     hpw <- hashF pw
     return $ checkF pw hpw === PasswordCheckSuccess
@@ -25,45 +24,25 @@
                       -> (Password -> IO (PasswordHash a))
                       -> (Password -> PasswordHash a -> PasswordCheck)
                       -> TestTree
-testIncorrectPassword s hashF checkF =
-    testProperty s $ testIncorrectPassword' hashF checkF
-
--- Similar to 'testIncorrectPassword', but exempts the comparison of
--- "" and "\NUL", since 'bcrypt' and 'PBKDF2' match those as well.
-testIncorrectPassword_ :: String
-                       -> (Password -> IO (PasswordHash a))
-                       -> (Password -> PasswordHash a -> PasswordCheck)
-                       -> TestTree
-testIncorrectPassword_ s hashF checkF =
-    testProperty s $ \pass pass2 ->
-      not (all isEmpty [pass, pass2]) ==>
-        testIncorrectPassword' hashF checkF pass pass2
+testIncorrectPassword s hashF checkF = testProperty s $
+  \pass pass2 -> pass /= pass2 && not (all isEmpty [pass, pass2]) ==>
+    ioProperty $ do
+      let pw = mkPassword pass
+          pw2 = mkPassword pass2
+      hpw <- hashF pw
+      return $ checkF pw2 hpw === PasswordCheckFail
   where
     isEmpty c = c `elem` ["", "\NUL"]
 
-testIncorrectPassword' :: (Password -> IO (PasswordHash a))
-                       -> (Password -> PasswordHash a -> PasswordCheck)
-                       -> Text -> Text -> Property
-testIncorrectPassword' hashF checkF pass pass2 = run10 $ do
-    let pw = mkPassword pass
-        pw2 = mkPassword pass2
-        result = if pass == pass2 then PasswordCheckSuccess
-                                  else PasswordCheckFail
-    hpw <- hashF pw
-    return $ checkF pw2 hpw === result
-
 testWithSalt :: String
              -> (Salt a -> Password -> PasswordHash a)
              -> (Password -> PasswordHash a -> PasswordCheck)
              -> TestTree
 testWithSalt s hashWithSalt checkF = testProperty s $
-  \pass salt -> withMaxSuccess 10 $
+  \pass salt ->
     let pw = mkPassword pass
         hpw = hashWithSalt salt pw
     in checkF pw hpw === PasswordCheckSuccess
-
-run10 :: Testable prop => IO prop -> Property
-run10 = withMaxSuccess 10 . ioProperty
 
 instance Arbitrary (Salt a) where
   arbitrary = Salt . pack <$> vector 16
diff --git a/test/tasty/PBKDF2.hs b/test/tasty/PBKDF2.hs
--- a/test/tasty/PBKDF2.hs
+++ b/test/tasty/PBKDF2.hs
@@ -17,44 +17,40 @@
 
 import Internal
 
-_10k :: Num a => a
-_10k = 10 * 1000
-
 testPBKDF2 :: TestTree
 testPBKDF2 = testGroup "PBKDF2"
-  [ testIt "PBKDF2 (hashPassword)" $ _10k defaultParams -- This is PBKDF2_SHA512
-  , testIncorrectPassword_
+  [ testIt "PBKDF2 (hashPassword)" testParams -- This is PBKDF2_SHA512
+  , testIncorrectPassword
       "PBKDF2 (hashPassword) fail"
-      (hashPasswordWithParams $ _10k defaultParams)
+      (hashPasswordWithParams testParams)
       checkPassword
   , testWithSalt
       "PBKDF2 (hashPasswordWithSalt)"
-      (hashPasswordWithSalt $ _10k defaultParams)
+      (hashPasswordWithSalt testParams)
       checkPassword
-  , testIt "PBKDF2 (md5)"    (defaultParams{ pbkdf2Algorithm = PBKDF2_MD5, pbkdf2Iterations = 5000 })
-  , testIt "PBKDF2 (sha1)"   (_10k defaultParams{ pbkdf2Algorithm = PBKDF2_SHA1 })
-  , testIt "PBKDF2 (sha256)" (_10k defaultParams{ pbkdf2Algorithm = PBKDF2_SHA256 })
+  , testIt "PBKDF2 (md5)"    (defaultParams{ pbkdf2Algorithm = PBKDF2_MD5, pbkdf2Iterations = 1000 })
+  , testIt "PBKDF2 (sha1)"   (testParams{ pbkdf2Algorithm = PBKDF2_SHA1 })
+  , testIt "PBKDF2 (sha256)" (testParams{ pbkdf2Algorithm = PBKDF2_SHA256 })
   , testFast Crypto.SHA1   20 PBKDF2.fastPBKDF2_SHA1
   , testFast Crypto.SHA256 32 PBKDF2.fastPBKDF2_SHA256
   , testFast Crypto.SHA512 64 PBKDF2.fastPBKDF2_SHA512
   -- Check to see if a hash with "pbkdf2:" prefixed also works
   , testCorrectPassword
       "PBKDF2 (pbkdf2:sha-...)"
-      (hashPasswordWithParams $ _10k defaultParams)
+      (hashPasswordWithParams testParams)
       (\pass (PasswordHash hash) -> checkPassword pass . PasswordHash $ "pbkdf2:" <> hash)
   ]
   where
     testIt s params = testCorrectPassword s (hashPasswordWithParams params) checkPassword
-    _10k params = params{ pbkdf2Iterations = 10 * 1000 }
+    testParams = defaultParams{ pbkdf2Iterations = 4 * 1000 }
 
 testFast :: (HashAlgorithm a, Show a)
          => a
          -> Int
          -> (Parameters -> ByteString -> ByteString -> ByteString)
          -> TestTree
-testFast alg i f = testProperty s $ \pass salt -> run10 $
-    return $ f params pass salt ===
-             PBKDF2.generate (PBKDF2.prfHMAC alg) params pass salt
+testFast alg i f = testProperty s $ \pass salt ->
+    f params pass salt === PBKDF2.generate (PBKDF2.prfHMAC alg) params pass salt
   where
     params = cryptoParams i
     s = sAlg ++ " HMAC == fast_" ++ sAlg
@@ -62,6 +58,6 @@
 
 cryptoParams :: Int -> PBKDF2.Parameters
 cryptoParams i = PBKDF2.Parameters {
-    PBKDF2.iterCounts = 5000,
+    PBKDF2.iterCounts = 2000,
     PBKDF2.outputLength = i
   }
