From 3b4a775d536b2b2956269a59f886487efe29ed51 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 16 Aug 2016 12:57:19 -0400 Subject: switch to random salt byte to make decryption expensive --- ExpensiveHash.hs | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'ExpensiveHash.hs') diff --git a/ExpensiveHash.hs b/ExpensiveHash.hs index 226fac7..3d832fb 100644 --- a/ExpensiveHash.hs +++ b/ExpensiveHash.hs @@ -17,6 +17,7 @@ import qualified Crypto.Argon2 as Argon2 import Raaz.Core.Encode import Data.Time.Clock import Control.DeepSeq +import Control.Monad import Data.Monoid -- | A hash that is expensive to calculate. @@ -29,32 +30,45 @@ data ExpensiveHash = ExpensiveHash (Cost CreationOp) T.Text data Salt t = Salt t --- | Would rather use haskell argon2 library, but it doesn't build --- from source, and is buggy. https://github.com/ocharles/argon2/issues/3 -expensiveHash :: Encodable t => Tunables -> Salt t -> B.ByteString -> ExpensiveHash -expensiveHash tunables (Salt s) b = - case expensiveHashTunable tunables of - UseArgon2 opts cost -> ExpensiveHash cost $ - -- Using hashEncoded here and not hash, - -- because of this bug: - -- https://github.com/ocharles/argon2/issues/3 - Argon2.hashEncoded opts b argonsalt +expensiveHash :: Encodable t => ExpensiveHashTunable -> Salt t -> B.ByteString -> ExpensiveHash +expensiveHash (UseArgon2 cost opts) (Salt s) b = ExpensiveHash cost $ + -- Using hashEncoded here and not hash, + -- because of this bug: + -- https://github.com/ocharles/argon2/issues/3 + 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 -benchmarkExpensiveHash :: Tunables -> IO (Benchmark (Cost CreationOp)) -benchmarkExpensiveHash tunables = do +benchmarkExpensiveHash :: Int -> ExpensiveHashTunable -> Cost op -> IO (Benchmark (Cost op)) +benchmarkExpensiveHash rounds tunables expected = do start <- getCurrentTime - let ExpensiveHash expected t = expensiveHash tunables - (Salt (KeyId gpgKey ("benchmark" :: B.ByteString))) - ("himom" :: B.ByteString) - end <- t `deepseq` getCurrentTime + forM_ [1..rounds] $ \_ -> do + let ExpensiveHash _ t = expensiveHash tunables + (Salt (KeyId gpgKey ("benchmark" :: B.ByteString))) + ("himom" :: B.ByteString) + t `deepseq` return () + end <- getCurrentTime let diff = floor $ end `diffUTCTime` start let actual = CPUCost $ Seconds diff return $ Benchmark { expectedBenchmark = expected , actualBenchmark = actual } + +benchmarkTunables :: Tunables -> IO () +benchmarkTunables tunables = do + putStrLn "Note that expected times are for 1 core machine." + putStrLn "If this machine has 2 cores, the actual times should be half the expected times." + putStrLn "Benchmarking 16 rounds of key generation hash..." + print =<< benchmarkExpensiveHash 16 + (keyEncryptionKeyHash $ keyEncryptionKeyTunable tunables) + (mapCost (`div` 16) $ randomSaltBytesBruteForceCost $ keyEncryptionKeyTunable tunables) + putStrLn "Benchmarking 1 round of name generation hash..." + print =<< benchmarkExpensiveHash 1 + (nameGenerationHash $ nameGenerationTunable tunables) + (getexpected $ nameGenerationHash $ nameGenerationTunable tunables) + where + getexpected (UseArgon2 cost _) = cost -- cgit v1.2.3