diff options
author | Joey Hess <joeyh@joeyh.name> | 2016-08-17 17:29:11 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2016-08-17 17:29:46 -0400 |
commit | c394b41a2ffb7e987864fa64fd583017c717703b (patch) | |
tree | 9aaaf9467badba9baeed3b634a1155be1ee833a0 | |
parent | b66b497244ab2a094bec5c3a678f448f23c8404d (diff) | |
download | keysafe-c394b41a2ffb7e987864fa64fd583017c717703b.tar.gz |
allow configuring N and M
User has to remember they did this and use the same configuration on
restore.
-rw-r--r-- | CmdLine.hs | 22 | ||||
-rw-r--r-- | Shard.hs | 10 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | Tunables.hs | 8 | ||||
-rw-r--r-- | keysafe.hs | 24 |
5 files changed, 41 insertions, 24 deletions
@@ -3,9 +3,10 @@ - Licensed under the GNU AGPL version 3 or higher. -} -module CmdLine (CmdLine(..), Mode(..), get, parse, selectMode) where +module CmdLine where import Types +import Tunables import qualified Gpg import Options.Applicative import qualified Data.ByteString.UTF8 as BU8 @@ -20,6 +21,7 @@ data CmdLine = CmdLine , storage :: Storage , gui :: Bool , testMode :: Bool + , customShardParams :: Maybe ShardParams } data Mode = Backup | Restore | Benchmark @@ -32,6 +34,7 @@ parse = CmdLine <*> localstorageflag <*> guiswitch <*> testmodeswitch + <*> optional (ShardParams <$> totalobjects <*> neededobjects) where backup = flag' Backup ( long "backup" @@ -47,10 +50,12 @@ parse = CmdLine ) gpgswitch = GpgKey . KeyId . BU8.fromString <$> strOption ( long "gpgkeyid" + <> metavar "KEYID" <> help "Specify keyid of gpg key to back up or restore. (When this option is used to back up a key, it must also be used at restore time.)" ) fileswitch = KeyFile <$> strOption ( long "keyfile" + <> metavar "FILE" <> help "Specify secret key file to back up or restore. (The same filename must be used to restore a key as was used to back it up.)" ) localstorageflag = flag networkStorage localStorage @@ -65,6 +70,16 @@ parse = CmdLine ( long "gui" <> help "Use GUI interface for interaction. Default is to use readline interface when run in a terminal, and GUI otherwise." ) + totalobjects = option auto + ( long "totalshards" + <> metavar "M" + <> help ("Configure the number of shards to split encrypted secret key into. Default: " ++ show (totalObjects (shardParams defaultTunables)) ++ " (When this option is used to back up a key, it must also be provided at restore time.)") + ) + neededobjects = option auto + ( long "neededshards" + <> metavar "N" + <> help ("Configure the number of shards needed to restore. Default: " ++ show (neededObjects (shardParams defaultTunables)) ++ " (When this option is used to back up a key, it must also be provided at restore time.)") + ) get :: IO CmdLine get = execParser opts @@ -85,3 +100,8 @@ selectMode cmdline = case mode cmdline of where present True = Backup present False = Restore + +customizeShardParams :: CmdLine -> Tunables -> Tunables +customizeShardParams cmdline t = case customShardParams cmdline of + Nothing -> t + Just ps -> t { shardParams = ps } @@ -53,15 +53,15 @@ shardIdents tunables (Name name) keyid = E.encodeUtf8 $ basename <> T.pack (show n) mksha :: B.ByteString -> Raaz.Base16 mksha = Raaz.encode . Raaz.sha256 - idents = map mk [1..totalObjects (head (shardParams tunables))] + idents = map mk [1..totalObjects (shardParams tunables)] bruteforcecalc = bruteForceLinearSearch creationcost hashtunables = nameGenerationHash $ nameGenerationTunable tunables genShards :: EncryptedSecretKey -> Tunables -> IO [Shard] genShards (EncryptedSecretKey esk _) tunables = do shares <- SS.encode - (neededObjects $ head $ shardParams tunables) - (totalObjects $ head $ shardParams tunables) + (neededObjects $ shardParams tunables) + (totalObjects $ shardParams tunables) (BL.fromStrict esk) return $ map (\(n, share) -> Shard n (StorableObject $ encodeShare share)) (zip [1..] shares) @@ -70,14 +70,14 @@ combineShards :: Tunables -> [Shard] -> Either String EncryptedSecretKey combineShards tunables shards | null shards = Left "No shards could be downloaded. Perhaps you entered the wrong name or password?" - | length shards < minimum (map neededObjects (shardParams tunables)) = + | length shards < neededObjects (shardParams tunables) = Left "Not enough are shards currently available to reconstruct your data." | otherwise = Right $ mk $ SS.decode $ map decodeshard shards where mk b = EncryptedSecretKey (BL.toStrict b) unknownCostCalc decodeshard (Shard sharenum so) = decodeShare sharenum sharesneeded $ fromStorableObject so - sharesneeded = neededObjects $ head $ shardParams tunables + sharesneeded = neededObjects $ shardParams tunables -- | This efficient encoding relies on the share using a finite field of -- size 256, so it maps directly to bytes. @@ -2,3 +2,4 @@ * prompt for name that is less obviously connected to user * tune hashes on more powerful hardware than thermal throttling laptop * store to servers +* improve restore progress bar points (10m, 5m, 50m) diff --git a/Tunables.hs b/Tunables.hs index f4f74a4..2e8d43b 100644 --- a/Tunables.hs +++ b/Tunables.hs @@ -33,9 +33,7 @@ knownTunings = map (\t -> (nameGenerationHash (nameGenerationTunable t), t)) -- 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 + { shardParams :: ShardParams , objectSize :: Int -- ^ a StorableObject is exactly this many bytes in size -- (must be a multiple of AES block size 16) @@ -82,7 +80,7 @@ data EncryptionTunable = UseAES256 defaultTunables :: Tunables defaultTunables = Tunables - { shardParams = [ShardParams { totalObjects = 3, neededObjects = 2 }] + { shardParams = ShardParams { totalObjects = 3, neededObjects = 2 } , objectSize = 1024*64 -- 64 kb -- The nameGenerationHash was benchmarked at 661 seconds CPU time -- on a 2 core Intel(R) Core(TM) i5-4210Y CPU @ 1.50GHz. @@ -114,7 +112,7 @@ defaultTunables = Tunables -- Not for production use! testModeTunables :: Tunables testModeTunables = Tunables - { shardParams = [ShardParams { totalObjects = 3, neededObjects = 2 }] + { shardParams = ShardParams { totalObjects = 3, neededObjects = 2 } , objectSize = 1024*64 , nameGenerationTunable = NameGenerationTunable { nameGenerationHash = weakargon2 (CPUCost (Seconds (2*600))) @@ -35,16 +35,17 @@ main :: IO () main = do cmdline <- CmdLine.get ui <- selectUI (CmdLine.gui cmdline) - tunables <- if CmdLine.testMode cmdline + let mkt = CmdLine.customizeShardParams cmdline + (tunables, possibletunables) <- if CmdLine.testMode cmdline then do showInfo ui "Test mode" "Keysafe is running in test mode. This is not secure, and should not be used with real secret keys!" - return testModeTunables - else return defaultTunables - dispatch cmdline ui tunables + return (mkt testModeTunables, [mkt testModeTunables]) + else return (mkt defaultTunables, map (mkt . snd) knownTunings) + dispatch cmdline ui tunables possibletunables -dispatch :: CmdLine.CmdLine -> UI -> Tunables -> IO () -dispatch cmdline ui tunables = do +dispatch :: CmdLine.CmdLine -> UI -> Tunables -> [Tunables] -> IO () +dispatch cmdline ui tunables possibletunables = do mode <- CmdLine.selectMode cmdline go mode (CmdLine.secretkeysource cmdline) where @@ -53,12 +54,12 @@ dispatch cmdline ui tunables = do backup storage ui tunables secretkeysource =<< getSecretKey secretkeysource go CmdLine.Restore (Just secretkeydest) = - restore storage ui (CmdLine.testMode cmdline) secretkeydest + restore storage ui possibletunables secretkeydest go CmdLine.Backup Nothing = backup storage ui tunables Gpg.anyKey =<< Gpg.getKeyToBackup ui go CmdLine.Restore Nothing = - restore storage ui (CmdLine.testMode cmdline) Gpg.anyKey + restore storage ui possibletunables Gpg.anyKey go CmdLine.Benchmark _ = benchmarkTunables tunables @@ -143,8 +144,8 @@ backup storage ui tunables secretkeysource secretkey = do , "Please wait..." ] -restore :: Storage -> UI -> Bool -> SecretKeySource -> IO () -restore storage ui testmode secretkeydest = do +restore :: Storage -> UI -> [Tunables] -> SecretKeySource -> IO () +restore storage ui possibletunables secretkeydest = do username <- userName name <- fromMaybe (error "Aborting on no name") <$> promptName ui "Enter name" @@ -169,9 +170,6 @@ restore storage ui testmode secretkeydest = do writeSecretKey secretkeydest secretkey showInfo ui "Success" "Your secret key successfully restored!" where - possibletunables - | testmode = [testModeTunables] - | otherwise = map snd knownTunings namedesc = unlines [ "When you backed up your secret key, you entered a name and a password." , "Now it's time to remember what you entered back then." |