From 7192abc5d53aa5a6ee609ed30bd05f1575e67b65 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Sat, 6 Aug 2016 17:35:10 -0400 Subject: some basic data types and expensive hashing --- ExpensiveHash.hs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 ExpensiveHash.hs (limited to 'ExpensiveHash.hs') diff --git a/ExpensiveHash.hs b/ExpensiveHash.hs new file mode 100644 index 0000000..8bfe004 --- /dev/null +++ b/ExpensiveHash.hs @@ -0,0 +1,54 @@ +{-# LANGUAGE OverloadedStrings #-} + +module ExpensiveHash where + +import Types +import qualified Data.ByteString as B +import Raaz.Core.Encode +import qualified Crypto.Argon2 as Argon2 +import Data.Time.Clock +import Control.DeepSeq + +-- | 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 B.ByteString + deriving (Show) + +data Salt t = Salt t + +expensiveHash :: Encodable t => RunMode -> Salt t -> Password -> ExpensiveHash +expensiveHash runmode (Salt s) (Password password) = + ExpensiveHash cost $ Argon2.hash o password (toByteString s) + where + HashParams o cost = hashParams runmode + +data HashParams = HashParams Argon2.HashOptions Cost + +hashParams :: RunMode -> HashParams +hashParams SecureMode = HashParams o cost + where + -- argon2 is GPU and ASIC resistent, so it uses CPU time. + -- The selected HashOptions were benchmarked at 661 seconds CPU time + -- on a 2 core Intel(R) Core(TM) i5-4210Y CPU @ 1.50GHz. + cost = CPUCost (Seconds 600) + o = Argon2.HashOptions + { Argon2.hashIterations = 10000 + , Argon2.hashMemory = 131072 -- 128 mebibtyes per thread + , Argon2.hashParallelism = 4 -- 4 threads + , Argon2.hashVariant = Argon2.Argon2i + } +hashParams TestingMode = + HashParams Argon2.defaultHashOptions $ CPUCost (Seconds 0) + +benchmarkExpensiveHash :: IO (Benchmark Cost) +benchmarkExpensiveHash = do + start <- getCurrentTime + let ExpensiveHash expected b = expensiveHash SecureMode + (Salt (KeyIdent gpgKey (Name ("benchmark" :: B.ByteString)))) + (Password ("himom" :: B.ByteString)) + end <- b `deepseq` getCurrentTime + let actual = (CPUCost $ Seconds $ end `diffUTCTime` start) + return $ Benchmark { expectedBenchmark = expected, actualBenchmark = actual } -- cgit v1.2.3