{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Scrypt where import Data.ByteString.Lazy (fromStrict) import Data.Maybe (fromJust) import Data.Text (Text) import Data.Text.Encoding (encodeUtf8) import Test.Tasty import Test.Tasty.Golden (goldenVsString) import Test.Tasty.QuickCheck import Test.QuickCheck.Instances.Text () #ifdef x86_64_HOST_ARCH import qualified Crypto.Scrypt as Scrypt #endif import Data.Password.Types import Data.Password.Scrypt import Internal testScrypt :: TestTree testScrypt = testGroup "scrypt" [ testCorrectPassword "Scrypt (hashPassword, 8 rounds)" hash8Rounds checkPassword extractParams testsParams8Rounds , testCorrectPassword "Scrypt (hashPassword, 4 rounds)" hash4Rounds checkPassword extractParams testsParams4Rounds , testIncorrectPassword "Scrypt (hashPassword) fail" hash8Rounds checkPassword , testWithSalt "Scrypt (hashPasswordWithSalt)" (hashPasswordWithSalt testsParams8Rounds) checkPassword extractParams testsParams8Rounds #ifdef x86_64_HOST_ARCH , testProperty "scrypt <-> cryptonite" $ withMaxSuccess 10 checkScrypt #endif , testGolden ] where hash8Rounds = hashPasswordWithParams testsParams8Rounds testsParams8Rounds = defaultParams{ scryptRounds = 8, scryptSalt = 16 } hash4Rounds = hashPasswordWithParams testsParams4Rounds testsParams4Rounds = defaultParams{ scryptRounds = 4, scryptSalt = 16 } #ifdef x86_64_HOST_ARCH -- The scrypt library is only available on x86_64, so we only compare password's -- scrypt functionality against the actual scrypt library when building on x86_64. checkScrypt :: Text -> Property checkScrypt pass = ioProperty $ do s@(Scrypt.Salt salt) <- Scrypt.newSalt let params = fromJust $ Scrypt.scryptParams 8 8 1 Scrypt.EncryptedPass scryptHash = Scrypt.encryptPass params s $ Scrypt.Pass $ encodeUtf8 pass PasswordHash ourHash = hashPasswordWithSalt defaultParams{ scryptRounds = 8 } (Salt salt) $ mkPassword pass return $ scryptHash === encodeUtf8 ourHash #endif testGolden :: TestTree testGolden = testGroup "Golden tests" [ go "defaultParams" "Scrypt_defaultParams" defaultParams "somesalt42" , go "rounds = 8" "Scrypt_rounds8" defaultParams{scryptRounds = 8} "somesalt42" , go "output length = 16" "Scrypt_outputLength16" defaultParams{scryptOutputLength = 16} "somesalt42" , go "scrypt length = 16" "Scrypt_saltLength16" defaultParams{scryptSalt = 16} "somesalt42" , go "Other salt" "Scrypt_otherSalt" defaultParams "somesalt0" ] where go testName fileName params salt = goldenVsString testName ("test/golden/" <> fileName <> ".golden") (return $ fromStrict $ encodeUtf8 $ unPasswordHash $ hashPasswordWithSalt params (Salt salt) $ mkPassword "password")