packages feed

keysafe 0.20161022 → 0.20161107

raw patch · 10 files changed

+107/−38 lines, 10 files

Files

CHANGELOG view
@@ -1,3 +1,20 @@+keysafe (0.20161107) unstable; urgency=medium++  * The third keysafe server is now available, provided by Purism.+  * Purism's keysafe server has been vetted to Recommended level!+  * Change default for --port to 4242.+  * Fix --check-server to not fail when the server has not had anything+    stored on it yet.+  * --upload-queued: Exit nonzero if unable to upload all queued objects.+  * --autostart: If unable to upload all queued objects initially,+    delay between 1 and 2 hours and try again.+  * Better suggestion when user is having difficulty thinking of a strong+    enough password.+  * Defer requesting secret key from gpg until just before backup, so the+    user knows why gpg is asking for this secret key to be backed up.++ -- Joey Hess <id@joeyh.name>  Mon, 07 Nov 2016 15:05:29 -0400+ keysafe (0.20161022) unstable; urgency=medium    * Add keywords to desktop file.
CmdLine.hs view
@@ -181,7 +181,7 @@ 	<$> option auto 		( long "port" 		<> metavar "P"-		<> value 80+		<> value 4242 		<> showDefault 		<> help "Port for server to listen on." 		)@@ -243,4 +243,4 @@ 		(h, ':':ps) -> case reads ps of 			[(p, "")] -> Right (h, p) 			_ -> Left $ "unable to parse port \"" ++ ps ++ "\""-		(h, _) -> Right (h, 80)+		(h, _) -> Right (h, 4242)
Gpg.hs view
@@ -21,19 +21,17 @@ -- -- If there is only one gpg secret key, -- the choice is obvious. Otherwise prompt the user with a list.-getKeyToBackup :: UI -> IO (SecretKeySource, SecretKey)+getKeyToBackup :: UI -> IO SecretKeySource getKeyToBackup ui = go =<< listSecretKeys   where 	go [] = do 		showError ui "You have no gpg secret keys to back up." 		error "Aborting on no gpg secret keys."-	go [(_, kid)] = mkret kid-	go l = maybe (error "Canceled") mkret+	go [(_, kid)] = selected kid+	go l = maybe (error "Canceled") selected 		=<< promptKeyId ui "Pick gpg secret key" 			"Pick gpg secret key to back up:" l-	mkret kid = do-		sk <- getSecretKey kid-		return (GpgKey kid, sk)+	selected = return . GpgKey  listSecretKeys :: IO [(Name, KeyId)] listSecretKeys = map mk . parse . lines <$> readProcess "gpg"
SecretKey.hs view
@@ -12,12 +12,9 @@ import System.IO import System.Posix.IO -getSecretKey :: SecretKeySource -> IO (SecretKeySource, SecretKey)-getSecretKey sks = do-	sk <- case sks of-		GpgKey kid -> Gpg.getSecretKey kid-		KeyFile f -> SecretKey <$> B.readFile f-	return (sks, sk)+getSecretKey :: SecretKeySource -> IO SecretKey+getSecretKey (GpgKey kid) = Gpg.getSecretKey kid+getSecretKey (KeyFile f) = SecretKey <$> B.readFile f  -- | Can throw exception if the secret key already exists. writeSecretKey :: Distinguisher -> SecretKey -> IO ()
Servers.hs view
@@ -23,9 +23,13 @@ 		[ServerAddress "vzgrspuxbtnlrtup.onion" 4242] 		"Provided by Joey Hess. Digital Ocean VPS, located in Indonesia" -	, mk Alternate $ Server (ServerName "keysafe.puri.sm")-		[]-		"Purism server is not yet deployed, but planned."+	, mk Recommended $ Server (ServerName "keysafe.puri.sm")+		[ServerAddress "hlmjmeth356s5ekm.onion" 4242]+		"Provided by Purism. Located in the EU (Cyprus)"+		-- Note that while Joey Hess is employed by Purism,+		-- he does not have access to this server or its data,+		-- and Purism has policy to never allow him such access.+		-- This is important since he runs keysafe.joeyh.name.  	-- still being vetted 	, mk Alternate $ Server (ServerName "thirdserver")
Storage/Local.hs view
@@ -112,8 +112,11 @@ count :: Section -> GetShareDir -> IO CountResult count section getsharedir = onError (CountFailure . show) $ do 	dir <- getsharedir section-	CountResult . genericLength . filter isShareFile-		<$> getDirectoryContents dir+	exists <- doesDirectoryExist dir+	if exists+		then CountResult . genericLength . filter isShareFile+			<$> getDirectoryContents dir+		else return (CountResult 0)  move :: Section -> GetShareDir -> Storage -> IO [StoreResult] move section getsharedir storage = do
TODO view
@@ -1,6 +1,6 @@ Soon: -* Get some keysafe servers set up.+* Finish vetting 2 servers to Recommended. * Set up --check-servers in a cron job, so I know when servers are down.  Later:@@ -8,6 +8,8 @@ * The attack cost display can lead to a false sense of security if the user   takes it as gospel. It needs to be clear that it's an estimate. This and   other parts of the keysafe UI need usability testing.+* Make --gui password entry fields longer, so user does not feel they need+  to make password short. (zenity may not allow configuring this) * improve restore progress bar points (update after every hash try) * If we retrieved enough shares successfully, but decrypt failed, must   be a wrong password, so prompt for re-entry and retry with those shares.@@ -24,11 +26,19 @@   harder for traffic analysis to tell that given TOR traffic is   keysafe traffic. * Argon2d is more resistent to GPU/ASIC attack optimisation.-  Switching from Argon2i would require new tunables, so deferred for now+  Switching from Argon2i would require new tunables, and delay restores+  (of keys backed up using the old tunables, and when the user provides the+  wrong name) by ~10 minutes, so deferred for now   until there's some other reason to change the tunables.  Wishlist: +* Custom GUI, instead of zenity. Allows:+  - Fewer screens by consolidating multiple prompts.+  - Check same password entered second time and don't allow continuing+    if not.+  - Password strengh display, and don't allow continuing if password is too+    weak. * Keep secret keys in locked memory until they're encrypted.   (Raaz makes this possible to do.)   Would be nice, but not super-important, since gpg secret keys@@ -51,4 +61,14 @@   with 2 shares, then 3, etc, and once it found shares, it would know the   number needed. It should also be possible to avoid breaking backwards   compatability, by only including the number of shares in the name when-  it's not the standard number.+  it's not the standard number. To avoid needing to re-run argon2 for each+  try, the argon2 hash of the name could be calculated first, and then the+  number of needed shares appended before the final sha256 hash is+  generated.+  +  If an attacker is able to guess the name, and a nonstandard number of+  shares was used, the attacker could upload other objects where they would+  be found before the real objects. This could be used to prevent+  restore from working. (It also makes a malicious data attack (as described+  in https://joeyh.name/keysafe/details/) possible by attackers who do not+  control the servers.
keysafe.1 view
@@ -141,7 +141,7 @@ server first before any of its built-in servers. .PP .IP "--port P"-Port for server to listen on. (default: 80)+Port for server to listen on. (default: 4242) .PP .IP "--address A" Address for server to bind to. (Use "*" to bind to
keysafe.cabal view
@@ -1,5 +1,5 @@ Name: keysafe-Version: 0.20161022+Version: 0.20161107 Cabal-Version: >= 1.8 Maintainer: Joey Hess <joey@kitenet.net> Author: Joey Hess
keysafe.hs view
@@ -40,6 +40,9 @@ import qualified Data.ByteString as B import qualified Data.ByteString.UTF8 as BU8 import qualified Data.Set as S+import Control.Concurrent.Thread.Delay+import System.Random+import System.Exit import System.Posix.User (userGecos, getUserEntryForID, getEffectiveUserID)  main :: IO ()@@ -62,7 +65,7 @@   where 	go CmdLine.Backup (Just secretkeysource) = 		backup cmdline ui tunables (Distinguisher secretkeysource)-			=<< getSecretKey secretkeysource+			secretkeysource 	go CmdLine.Restore (Just secretkeydest) = 		restore cmdline ui possibletunables (Distinguisher secretkeydest) 	go CmdLine.Backup Nothing =@@ -70,8 +73,11 @@ 			=<< Gpg.getKeyToBackup ui 	go CmdLine.Restore Nothing = 		restore cmdline ui possibletunables AnyGpgKey-	go CmdLine.UploadQueued _ =-		uploadQueued ui (CmdLine.localstoragedirectory cmdline)+	go CmdLine.UploadQueued _ = do+		ok <- uploadQueued ui (CmdLine.localstoragedirectory cmdline)+		if ok+			then exitSuccess+			else exitFailure 	go CmdLine.AutoStart _ = 		autoStart cmdline tunables ui 	go (CmdLine.Server) _ =@@ -91,8 +97,8 @@ 	go CmdLine.Test _ = 		runTests -backup :: CmdLine.CmdLine -> UI -> Tunables -> Distinguisher -> (SecretKeySource, SecretKey) -> IO ()-backup cmdline ui tunables distinguisher (secretkeysource, secretkey) = do+backup :: CmdLine.CmdLine -> UI -> Tunables -> Distinguisher -> SecretKeySource -> IO ()+backup cmdline ui tunables distinguisher secretkeysource = do 	installAutoStartFile  	let m = totalObjects (shareParams tunables)@@ -116,9 +122,9 @@ 		Nothing -> fromMaybe (error "Aborting on no username")  			<$> promptName ui "Enter your name" 				usernamedesc (Just username) validateName-	go theirname locs+	go theirname locs Nothing   where-	go theirname locs = do+	go theirname locs msecretkey = do 		cores <- fromMaybe 1 <$> getNumCores 		Name othername <- case CmdLine.name cmdline of 			Just n -> pure n@@ -129,6 +135,9 @@ 		(kek, passwordentropy) <- promptpassword name 		let sis = shareIdents tunables name distinguisher 		let cost = getCreationCost kek <> getCreationCost sis+		secretkey <- case msecretkey of+			Just sk -> pure sk+			Nothing -> getSecretKey secretkeysource 		(r, queued, usedlocs) <- withProgressIncremental ui "Encrypting and storing data" 			(encryptdesc cost cores) $ \addpercent -> do 				let esk = encrypt tunables kek secretkey@@ -153,7 +162,7 @@ 					[ "Another secret key is already being stored under the name you entered." 					, "Please try again with a different name." 					]-				go theirname locs+				go theirname locs (Just secretkey) 	promptpassword name = do 		password <- fromMaybe (error "Aborting on no password")  			<$> promptPassword ui True "Enter password" passworddesc@@ -164,7 +173,12 @@ 		let mincost = Dollars 100000 		if crackcost < mincost 			then do-				showError ui $ "Weak password! It would cost only " ++ show crackcost ++ " to crack the password. Please think of a better one. More words would be good.."+				showError ui $ unlines+					[ "Weak password! It would cost only " ++ show crackcost ++ " to crack the password."+					, "Please think of a better one."+					, ""+					, "Suggestion: Pick 3 or 4 unrelated words for a strong password, like \"correct horse battery staple\""+					] 				promptpassword name 			else do 				(thisyear, _, _) <- toGregorian . utctDay@@ -384,18 +398,20 @@   where 	namewords (Name nb) = words (BU8.toString nb) -uploadQueued :: UI -> Maybe LocalStorageDirectory -> IO ()+uploadQueued :: UI -> Maybe LocalStorageDirectory -> IO Bool uploadQueued ui d = do 	problems <- tryUploadQueued d 	if null problems-		then return ()-		else showError ui ("Problem uploading queued data to servers:\n\n" ++ unlines problems ++ "\n\nYour secret keys have not yet been backed up.")+		then return True+		else do+			showError ui ("Problem uploading queued data to servers:\n\n" ++ unlines problems ++ "\n\nYour secret keys have not yet been backed up.")+			return False  autoStart :: CmdLine.CmdLine -> Tunables -> UI -> IO () autoStart cmdline tunables ui = do 	-- Upload queued first, before making any more backups that might 	-- queue more.-	uploadQueued ui (CmdLine.localstoragedirectory cmdline)+	queueok <- uploadQueued ui (CmdLine.localstoragedirectory cmdline)  	-- Ask about backing up any gpg secret key that has not been backed up 	-- or asked about before. If there are multiple secret keys, only@@ -414,9 +430,23 @@ 				"Do you want to back up the gpg secret key now?" 			if ans 				then backup cmdline ui tunables AnyGpgKey-					=<< getSecretKey (GpgKey kid)+					(GpgKey kid) 				else storeBackupLog 					=<< mkBackupLog (BackupSkipped (GpgKey kid))++	if queueok+		then return ()+		else retryqueue+  where+	-- Delay for between 1 and 2 hours, and retry queued uploads.+	retryqueue = do+		let hourdelay = 1000000 * 60*60+		msdelay <- getStdRandom (randomR (hourdelay, hourdelay*2))+		delay msdelay+		problems <- tryUploadQueued (CmdLine.localstoragedirectory cmdline)+		if null problems+			then return ()+			else retryqueue  checkServers :: CmdLine.CmdLine -> IO () checkServers cmdline = do