From 5decbad3eb779b1bbe11245cbde84701909e9c68 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 11 Aug 2016 15:52:50 -0400 Subject: nearly able to generate shards now --- Tunables.hs | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 Tunables.hs (limited to 'Tunables.hs') diff --git a/Tunables.hs b/Tunables.hs new file mode 100644 index 0000000..7a646d3 --- /dev/null +++ b/Tunables.hs @@ -0,0 +1,97 @@ +{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-} + +module Tunables where + +import Cost +import qualified Crypto.Argon2 as Argon2 + +-- | To determine the tunables used for a key name the expensive hash of the +-- name is calculated, using a particular configuration, and if the +-- object names it generates are available, we know the tunables. +-- +-- Since this process is expensive, it's important that the most commonly +-- used tunables come first, so that the expensive hash does not have to be +-- calculated repatedly. +-- +-- The reason for using this expensive method of encoding the tunables +-- is that it prevents attacks where related objects are correlated based +-- on their tunables. +knownTunings :: [(ExpensiveHashTunable, Tunables)] +knownTunings = map (\t -> (expensiveHashTunable t, t)) + [ defaultTunables + ] + +-- | keysafe stores data for a long time, and needs to be able to process +-- data from a long time ago when restoring a key. We don't want to be +-- locked into old choices of crypto primitives etc forever. +-- +-- So, every parameter that can be tuned is configured in this data +-- structure. +data Tunables = Tunables + { shardParams :: [ShardParams] + -- ^ multiple ShardParams may be supported, with the user + -- allowed to choose between them + , objectSize :: Int + -- ^ a StorableObject is exactly this many bytes in size + , expensiveHashTunable :: ExpensiveHashTunable + , encryptionTunable :: EncryptionTunable + , decryptionPuzzleTunable :: DecryptionPuzzleTunable + } + +-- | Parameters for sharding. The secret is split into +-- N objects, such that only M are needed to reconstruct it. +data ShardParams = ShardParams + { totalObjects :: Int -- ^ N + , neededObjects :: Int -- ^ M + } + +-- | An expensive hash, used to make it hard to crack an encrypted secret key. +data ExpensiveHashTunable = UseArgon2 Argon2.HashOptions (Cost CreationOp) + deriving (Show) + +-- | What encryption to use. +data EncryptionTunable = UseAES256 + deriving (Show) + +-- | An additional puzzle that makes decryption more expensive. +data DecryptionPuzzleTunable = KeyBlindingLeftSide (Cost DecryptionOp) + deriving (Show) + +defaultTunables :: Tunables +defaultTunables = Tunables + { shardParams = [ShardParams { totalObjects = 3, neededObjects = 2 }] + , objectSize = 1024*64 -- 64 kb + , expensiveHashTunable = UseArgon2 argonoptions argoncost + , encryptionTunable = UseAES256 + -- AES can be calculated more efficiently by a GPU, so the + -- cost is a GPU cost. + -- This is set to only 1 minute because GPUs are quite a lot + -- faster than CPUs at AES, and so setting it higher would make + -- clients too slow at key recovery. + , decryptionPuzzleTunable = KeyBlindingLeftSide (GPUCost (Seconds 60)) + } + where + argonoptions = Argon2.HashOptions + { Argon2.hashIterations = 10000 + , Argon2.hashMemory = 131072 -- 128 mebibtyes per thread + , Argon2.hashParallelism = 4 -- 4 threads + , Argon2.hashVariant = Argon2.Argon2i + } + -- argon2 is GPU and ASIC resistent, so it uses CPU time. + -- The above HashOptions were benchmarked at 661 seconds CPU time + -- on a 2 core Intel(R) Core(TM) i5-4210Y CPU @ 1.50GHz. + -- Since cost is measured per core, we double that. + argoncost = CPUCost (Seconds (2*600)) + +-- | Dials back cryptographic difficulty, not for production use. +testModeTunables :: Tunables +testModeTunables = Tunables + { shardParams = [ShardParams { totalObjects = 3, neededObjects = 2 }] + , objectSize = 1024*64 + , expensiveHashTunable = UseArgon2 weakargonoptions argoncost + , encryptionTunable = UseAES256 + , decryptionPuzzleTunable = KeyBlindingLeftSide (GPUCost (Seconds 60)) + } + where + UseArgon2 argonoptions argoncost = expensiveHashTunable defaultTunables + weakargonoptions = argonoptions { Argon2.hashIterations = 1 } -- cgit v1.2.3