summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar guilhem <guilhem@fripost.org>2013-04-05 21:06:16 +0200
committerGravatar Joey Hess <joey@kitenet.net>2013-04-06 16:09:51 -0400
commita7f50205bb1ccd41d4a9ab4e11d984e643be755f (patch)
tree519c7148a87575896450b7dc43fc58e8b34dfe02
parentf758f6d5cbef989bff75fcd140edb8e0b8899b84 (diff)
Generate ciphers with a better entropy.
Unless highRandomQuality=false (or --fast) is set, use Libgcypt's 'GCRY_VERY_STRONG_RANDOM' level by default for cipher generation, like it's done for OpenPGP key generation. On the assistant side, the random quality is left to the old (lower) level, in order not to scare the user with an enless page load due to the blocking PRNG waiting for IO actions.
-rw-r--r--Assistant/MakeRemote.hs8
-rw-r--r--Crypto.hs11
-rw-r--r--Remote/Helper/Encryptable.hs11
-rw-r--r--Test.hs1
-rw-r--r--Utility/Gpg.hs16
-rw-r--r--doc/design/encryption.mdwn13
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'
diff --git a/Crypto.hs b/Crypto.hs
index be326bf4c..21b1ae41b 100644
--- a/Crypto.hs
+++ b/Crypto.hs
@@ -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.
-
diff --git a/Test.hs b/Test.hs
index 56c70573d..ec578f591 100644
--- a/Test.hs
+++ b/Test.hs
@@ -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