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.
This commit is contained in:
parent
602baae12e
commit
00fc21bfec
6 changed files with 41 additions and 19 deletions
|
@ -69,11 +69,15 @@ makeRsyncRemote name location = makeRemote name location $
|
||||||
, ("type", "rsync")
|
, ("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 :: String -> RemoteType -> R.RemoteConfig -> Annex ()
|
||||||
makeSpecialRemote name remotetype config = do
|
makeSpecialRemote name remotetype config = do
|
||||||
(u, c) <- Command.InitRemote.findByName name
|
(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
|
describeUUID u name
|
||||||
configSet u c'
|
configSet u c'
|
||||||
|
|
||||||
|
|
11
Crypto.hs
11
Crypto.hs
|
@ -67,15 +67,16 @@ cipherMac :: Cipher -> String
|
||||||
cipherMac (Cipher c) = take cipherBeginning c
|
cipherMac (Cipher c) = take cipherBeginning c
|
||||||
|
|
||||||
{- Creates a new Cipher, encrypted to the specified key id. -}
|
{- Creates a new Cipher, encrypted to the specified key id. -}
|
||||||
genEncryptedCipher :: String -> IO StorableCipher
|
genEncryptedCipher :: String -> Bool -> IO StorableCipher
|
||||||
genEncryptedCipher keyid = do
|
genEncryptedCipher keyid highQuality = do
|
||||||
ks <- Gpg.findPubKeys keyid
|
ks <- Gpg.findPubKeys keyid
|
||||||
random <- Gpg.genRandom cipherSize
|
random <- Gpg.genRandom highQuality cipherSize
|
||||||
encryptCipher (Cipher random) ks
|
encryptCipher (Cipher random) ks
|
||||||
|
|
||||||
{- Creates a new, shared Cipher. -}
|
{- Creates a new, shared Cipher. -}
|
||||||
genSharedCipher :: IO StorableCipher
|
genSharedCipher :: Bool -> IO StorableCipher
|
||||||
genSharedCipher = SharedCipher <$> Gpg.genRandom cipherSize
|
genSharedCipher highQuality =
|
||||||
|
SharedCipher <$> Gpg.genRandom highQuality cipherSize
|
||||||
|
|
||||||
{- Updates an existing Cipher, re-encrypting it to add a keyid. -}
|
{- Updates an existing Cipher, re-encrypting it to add a keyid. -}
|
||||||
updateEncryptedCipher :: String -> StorableCipher -> IO StorableCipher
|
updateEncryptedCipher :: String -> StorableCipher -> IO StorableCipher
|
||||||
|
|
|
@ -31,15 +31,20 @@ encryptionSetup c = case (M.lookup "encryption" c, extractCipher c) of
|
||||||
(Just "none", Just _) -> cannotchange
|
(Just "none", Just _) -> cannotchange
|
||||||
(Just "shared", Just (EncryptedCipher _ _)) -> cannotchange
|
(Just "shared", Just (EncryptedCipher _ _)) -> cannotchange
|
||||||
(Just _, Just (SharedCipher _)) -> cannotchange
|
(Just _, Just (SharedCipher _)) -> cannotchange
|
||||||
(Just "shared", Nothing) -> use "encryption setup" $ genSharedCipher
|
(Just "shared", Nothing) -> use "encryption setup" . genSharedCipher
|
||||||
(Just keyid, Nothing) -> use "encryption setup" $ genEncryptedCipher keyid
|
=<< highRandomQuality
|
||||||
|
(Just keyid, Nothing) -> use "encryption setup" . genEncryptedCipher keyid
|
||||||
|
=<< highRandomQuality
|
||||||
(Just keyid, Just v) -> use "encryption updated" $ updateEncryptedCipher keyid v
|
(Just keyid, Just v) -> use "encryption updated" $ updateEncryptedCipher keyid v
|
||||||
where
|
where
|
||||||
cannotchange = error "Cannot change encryption type of existing remote."
|
cannotchange = error "Cannot change encryption type of existing remote."
|
||||||
use m a = do
|
use m a = do
|
||||||
cipher <- liftIO a
|
cipher <- liftIO a
|
||||||
showNote $ m ++ " " ++ describeCipher cipher
|
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.
|
{- Modifies a Remote to support encryption.
|
||||||
-
|
-
|
||||||
|
|
1
Test.hs
1
Test.hs
|
@ -735,6 +735,7 @@ test_crypto = "git-annex crypto" ~: intmpclonerepo $ when Build.SysConfig.gpg $
|
||||||
, "type=directory"
|
, "type=directory"
|
||||||
, "encryption=" ++ Utility.Gpg.testKeyId
|
, "encryption=" ++ Utility.Gpg.testKeyId
|
||||||
, "directory=dir"
|
, "directory=dir"
|
||||||
|
, "highRandomQuality=false"
|
||||||
]
|
]
|
||||||
initremote @? "initremote failed"
|
initremote @? "initremote failed"
|
||||||
initremote @? "initremote failed when run twice in a row"
|
initremote @? "initremote failed when run twice in a row"
|
||||||
|
|
|
@ -85,7 +85,8 @@ feedRead params passphrase feeder reader = do
|
||||||
reader from
|
reader from
|
||||||
|
|
||||||
{- Finds gpg public keys matching some string. (Could be an email address,
|
{- 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 :: String -> IO KeyIds
|
||||||
findPubKeys for = KeyIds . parse <$> readStrict params
|
findPubKeys for = KeyIds . parse <$> readStrict params
|
||||||
where
|
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.
|
{- 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
|
- It is armored, to avoid newlines, since gpg only reads ciphers up to the
|
||||||
- first newline. -}
|
- first newline. -}
|
||||||
genRandom :: Int -> IO String
|
genRandom :: Bool -> Int -> IO String
|
||||||
genRandom size = checksize <$> readStrict
|
genRandom highQuality size = checksize <$> readStrict
|
||||||
[ Params params
|
[ Params params
|
||||||
, Param $ show randomquality
|
, Param $ show randomquality
|
||||||
, Param $ show size
|
, Param $ show size
|
||||||
|
@ -106,8 +107,13 @@ genRandom size = checksize <$> readStrict
|
||||||
where
|
where
|
||||||
params = "--gen-random --armor"
|
params = "--gen-random --armor"
|
||||||
|
|
||||||
-- 1 is /dev/urandom; 2 is /dev/random
|
-- See http://www.gnupg.org/documentation/manuals/gcrypt/Quality-of-random-numbers.html
|
||||||
randomquality = 1 :: Int
|
-- 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
|
{- 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
|
- base64 encoded, so needs 8 bits to represent every 6 bytes of
|
||||||
|
|
|
@ -23,10 +23,15 @@ The basis of this scheme was originally developed by Lars Wirzenius et al
|
||||||
[for Obnam](http://liw.fi/obnam/encryption/).
|
[for Obnam](http://liw.fi/obnam/encryption/).
|
||||||
"""]]
|
"""]]
|
||||||
|
|
||||||
Data is encrypted by gpg, using a symmetric cipher.
|
Data is encrypted by GnuPG, using a symmetric cipher. The cipher is
|
||||||
The cipher is itself checked into your git repository, encrypted using one or
|
generated by GnuPG when the special remote is created. By default the
|
||||||
more gpg public keys. This scheme allows new gpg private keys to be given
|
best entropy pool is used, hence the generation may take a while; One
|
||||||
access to content that has already been stored in the remote.
|
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.
|
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
|
Allowing multiple ciphers to be used within a single remote would add a lot
|
||||||
|
|
Loading…
Add table
Reference in a new issue