{-# LANGUAGE OverloadedStrings #-} {- Copyright 2016 Joey Hess - - Licensed under the GNU AGPL version 3 or higher. -} module ExpensiveHash where import Tunables import Cost import Serialization () import qualified Data.Text as T import Data.Text.Short (toText) import qualified Data.ByteString as B import qualified Crypto.Argon2 as Argon2 import Raaz.Core.Encode -- | A hash that is expensive to calculate. -- -- This is a lynchpin of keysafe's security, because using this hash -- as an encryption key forces brute force attackers to generate -- hashes over and over again, taking a very long time. data ExpensiveHash = ExpensiveHash (Cost CreationOp) T.Text deriving (Show) instance HasCreationCost ExpensiveHash where getCreationCost (ExpensiveHash c _) = c data Salt t = Salt t expensiveHash :: Encodable t => ExpensiveHashTunable -> Salt t -> B.ByteString -> ExpensiveHash expensiveHash (UseArgon2 cost opts) (Salt s) b = ExpensiveHash cost $ either hashfailed toText $ Argon2.hashEncoded opts b argonsalt where -- argon salt cannot be shorter than 8 bytes, so pad with spaces. argonsalt = let sb = toByteString s in sb <> B.replicate (8 - B.length sb ) 32 hashfailed e = error ("hash generation failed: " ++ show e)