diff options
-rw-r--r-- | Assistant/MakeRemote.hs | 8 | ||||
-rw-r--r-- | Crypto.hs | 11 | ||||
-rw-r--r-- | Remote/Helper/Encryptable.hs | 11 | ||||
-rw-r--r-- | Test.hs | 1 | ||||
-rw-r--r-- | Utility/Gpg.hs | 16 | ||||
-rw-r--r-- | doc/design/encryption.mdwn | 13 |
6 files changed, 41 insertions, 19 deletions
diff --git a/Assistant/MakeRemote.hs b/Assistant/MakeRemote.hs index 448f7ad97..866585319 100644 --- a/Assistant/MakeRemote.hs +++ b/Assistant/MakeRemote.hs @@ -69,11 +69,15 @@ makeRsyncRemote name location = makeRemote name location $ , ("type", "rsync") ] -{- Inits a special remote. -} +{- Inits a special remote. Currently, only 'weak' ciphers can be + - generated from the assistant, because otherwise GnuPG may block once + - the entropy pool is drained, and as of now there's no way to tell the + - user to perform IO actions to refill the pool. -} makeSpecialRemote :: String -> RemoteType -> R.RemoteConfig -> Annex () makeSpecialRemote name remotetype config = do (u, c) <- Command.InitRemote.findByName name - c' <- R.setup remotetype u $ M.union config c + c' <- R.setup remotetype u $ + M.insert "highRandomQuality" "false" $ M.union config c describeUUID u name configSet u c' @@ -67,15 +67,16 @@ cipherMac :: Cipher -> String cipherMac (Cipher c) = take cipherBeginning c {- Creates a new Cipher, encrypted to the specified key id. -} -genEncryptedCipher :: String -> IO StorableCipher -genEncryptedCipher keyid = do +genEncryptedCipher :: String -> Bool -> IO StorableCipher +genEncryptedCipher keyid highQuality = do ks <- Gpg.findPubKeys keyid - random <- Gpg.genRandom cipherSize + random <- Gpg.genRandom highQuality cipherSize encryptCipher (Cipher random) ks {- Creates a new, shared Cipher. -} -genSharedCipher :: IO StorableCipher -genSharedCipher = SharedCipher <$> Gpg.genRandom cipherSize +genSharedCipher :: Bool -> IO StorableCipher +genSharedCipher highQuality = + SharedCipher <$> Gpg.genRandom highQuality cipherSize {- Updates an existing Cipher, re-encrypting it to add a keyid. -} updateEncryptedCipher :: String -> StorableCipher -> IO StorableCipher diff --git a/Remote/Helper/Encryptable.hs b/Remote/Helper/Encryptable.hs index f3b6bb787..ff7d4990b 100644 --- a/Remote/Helper/Encryptable.hs +++ b/Remote/Helper/Encryptable.hs @@ -31,15 +31,20 @@ encryptionSetup c = case (M.lookup "encryption" c, extractCipher c) of (Just "none", Just _) -> cannotchange (Just "shared", Just (EncryptedCipher _ _)) -> cannotchange (Just _, Just (SharedCipher _)) -> cannotchange - (Just "shared", Nothing) -> use "encryption setup" $ genSharedCipher - (Just keyid, Nothing) -> use "encryption setup" $ genEncryptedCipher keyid + (Just "shared", Nothing) -> use "encryption setup" . genSharedCipher + =<< highRandomQuality + (Just keyid, Nothing) -> use "encryption setup" . genEncryptedCipher keyid + =<< highRandomQuality (Just keyid, Just v) -> use "encryption updated" $ updateEncryptedCipher keyid v where cannotchange = error "Cannot change encryption type of existing remote." use m a = do cipher <- liftIO a showNote $ m ++ " " ++ describeCipher cipher - return $ M.delete "encryption" $ storeCipher c cipher + return $ M.delete "encryption" $ M.delete "highRandomQuality" $ + storeCipher c cipher + highRandomQuality = (&&) (maybe True (/="false") (M.lookup "highRandomQuality" c)) + <$> fmap not (Annex.getState Annex.fast) {- Modifies a Remote to support encryption. - @@ -735,6 +735,7 @@ test_crypto = "git-annex crypto" ~: intmpclonerepo $ when Build.SysConfig.gpg $ , "type=directory" , "encryption=" ++ Utility.Gpg.testKeyId , "directory=dir" + , "highRandomQuality=false" ] initremote @? "initremote failed" initremote @? "initremote failed when run twice in a row" diff --git a/Utility/Gpg.hs b/Utility/Gpg.hs index c31755d62..4a13d456c 100644 --- a/Utility/Gpg.hs +++ b/Utility/Gpg.hs @@ -85,7 +85,8 @@ feedRead params passphrase feeder reader = do reader from {- Finds gpg public keys matching some string. (Could be an email address, - - a key id, or a name. -} + - a key id, or a name; See the section 'HOW TO SPECIFY A USER ID' of + - GnuPG's manpage.) -} findPubKeys :: String -> IO KeyIds findPubKeys for = KeyIds . parse <$> readStrict params where @@ -97,8 +98,8 @@ findPubKeys for = KeyIds . parse <$> readStrict params {- Creates a block of high-quality random data suitable to use as a cipher. - It is armored, to avoid newlines, since gpg only reads ciphers up to the - first newline. -} -genRandom :: Int -> IO String -genRandom size = checksize <$> readStrict +genRandom :: Bool -> Int -> IO String +genRandom highQuality size = checksize <$> readStrict [ Params params , Param $ show randomquality , Param $ show size @@ -106,8 +107,13 @@ genRandom size = checksize <$> readStrict where params = "--gen-random --armor" - -- 1 is /dev/urandom; 2 is /dev/random - randomquality = 1 :: Int + -- See http://www.gnupg.org/documentation/manuals/gcrypt/Quality-of-random-numbers.html + -- for the meaning of random quality levels. + -- The highest available is 2, which is the default for OpenPGP + -- key generation; Note that it uses the blocking PRNG /dev/random + -- on the Linux kernel, hence the running time may take a while. + randomquality :: Int + randomquality = if highQuality then 2 else 1 {- The size is the number of bytes of entropy desired; the data is - base64 encoded, so needs 8 bits to represent every 6 bytes of diff --git a/doc/design/encryption.mdwn b/doc/design/encryption.mdwn index 45eb43cc9..6a380abe1 100644 --- a/doc/design/encryption.mdwn +++ b/doc/design/encryption.mdwn @@ -23,10 +23,15 @@ The basis of this scheme was originally developed by Lars Wirzenius et al [for Obnam](http://liw.fi/obnam/encryption/). """]] -Data is encrypted by gpg, using a symmetric cipher. -The cipher is itself checked into your git repository, encrypted using one or -more gpg public keys. This scheme allows new gpg private keys to be given -access to content that has already been stored in the remote. +Data is encrypted by GnuPG, using a symmetric cipher. The cipher is +generated by GnuPG when the special remote is created. By default the +best entropy pool is used, hence the generation may take a while; One +can use `initremote` with `highRandomQuality=false` or `--fast` options +to speed up things, but at the expense of using random numbers of a +lower quality. The generated cipher is then checked into your git +repository, encrypted using one or more OpenPGP public keys. This scheme +allows new OpenPGP private keys to be given access to content that has +already been stored in the remote. Different encrypted remotes need to be able to each use different ciphers. Allowing multiple ciphers to be used within a single remote would add a lot |