From 7db612b232a0f8a98fa695da6f14853284def681 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 11 Aug 2016 22:13:05 -0400 Subject: simplify by using the IV as the puzzle --- Encryption.hs | 77 +++++++++++++++++++++++++---------------------------------- 1 file changed, 32 insertions(+), 45 deletions(-) (limited to 'Encryption.hs') diff --git a/Encryption.hs b/Encryption.hs index 29935ac..c712d98 100644 --- a/Encryption.hs +++ b/Encryption.hs @@ -11,7 +11,6 @@ import Types import Tunables import Cost import ExpensiveHash -import Data.Bits import Data.Monoid import Data.Maybe import qualified Raaz @@ -56,16 +55,20 @@ decrypt kek (EncryptedSecretKey b _) = SecretKey <$> fromPaddedBytes pbs where pbs = PaddedBytes $ Raaz.unsafeDecrypt cipher (keyEncryptionKey kek) b --- | The ExpensiveHash of the Password is combined with a --- RandomObstacle to form the AES key. Combination method is logical OR. --- +-- | The ExpensiveHash of the Password used as the AES key. -- Name is used as a salt, to prevent rainbow table attacks. +-- +-- The DecryptionPuzzleTunable is used to alter the AES key +-- in some way that requires significant work to determine at +-- decryption time. genKeyEncryptionKey :: Tunables -> Name -> Password -> IO KeyEncryptionKey genKeyEncryptionKey tunables name (Password password) = case decryptionPuzzleTunable tunables of - KeyBlindingLeftSide puzzlecost -> do - ob@(RandomObstacle ok) <- genRandomObstacle tunables - let k = hashToAESKey ok hash - let strongk = mixinRandomObstacle ob k + UsePuzzleIV puzzlecost -> do + prg <- Raaz.newPRG () :: IO Raaz.SystemPRG + samplekey <- Raaz.random prg :: IO AesKey + let basek = hashToAESKey samplekey hash + (PuzzleIV iv) <- genPuzzleIV tunables + let strongk = (basek, iv) let decryptcost = CombinedCost puzzlecost (castCost hashcost) -- To brute force data encrypted with this key, -- an attacker needs to pay the decryptcost for @@ -90,64 +93,48 @@ hashToAESKey (samplekey, _iv) (ExpensiveHash _ t) = b = B.take (B.length (Raaz.toByteString samplekey)) $ Raaz.toByteString $ Raaz.sha256 (E.encodeUtf8 t) --- | A random value which can be mixed into an AES key to --- require decrypting it to perform some brute-force work. --- --- The random value is left-padded with NULL bytes, so ORing it with an AES --- key varies the initial bytes of the key. --- --- The AesKey also includes a random IV. -data RandomObstacle = RandomObstacle AesKey +-- | A puzzle IV starts with some number of random bytes of IV data, +-- and is right-padded with NULL bytes. +data PuzzleIV = PuzzleIV Raaz.IV --- | Length of the random obstacle, in bytes, that will satisfy the +-- | Length of the puzzle IV, in bytes, that will satisfy the -- decryptionPuzzleCost. -- -- AES can be calculated more efficiently by a GPU, so the cost must be -- a GPU cost. -- -- This depends on the objectSize, because to brute force the --- RandomObstable, AES decryptions must be done repeatedly, and the +-- RandomIV, AES decryptions must be done repeatedly, and the -- time needed for an AES decryption depends on the amount of data. -sizeRandomObstacle :: Tunables -> Int -sizeRandomObstacle tunables = ceiling $ nbits / 8 +sizePuzzleIV :: Tunables -> Int +sizePuzzleIV tunables = ceiling $ nbits / 8 where -- in 2016, a GPU can run AES at 10 GB/s. bytespersecond = 10*1024*1024*1024 triespersecond = bytespersecond `div` fromIntegral (objectSize tunables) targetseconds = case decryptionPuzzleTunable tunables of - KeyBlindingLeftSide cost -> case cost of + UsePuzzleIV cost -> case cost of GPUCost (Seconds n) -> n - _ -> error "decryptionPuzzleCost must be a GPUCost" + _ -> error "decryptionPuzzleTunable must be a GPUCost" -- Add one bit of entropy, because a brute-force attack will -- on average succeed half-way through the search space. nbits :: Double nbits = logBase 2 (fromIntegral $ targetseconds * triespersecond) + 1 -mkRandomObstacle :: AesKey -> Int -> AesKey -mkRandomObstacle (k, iv) nbytes = (k', iv) +mkPuzzleIV :: Raaz.IV -> Int -> PuzzleIV +mkPuzzleIV randomiv nbytes = PuzzleIV $ + fromMaybe (error "mkRandomIV fromByteString failed") $ + Raaz.fromByteString $ B.take nbytes b <> padding where - k' = fromMaybe (error "mkRandomObstacle fromByteString failed") $ - Raaz.fromByteString ob - kb = Raaz.toByteString k - padding = B.replicate (B.length kb - nbytes) 0 - ob = padding <> B.take nbytes kb - -genRandomObstacle :: Tunables -> IO RandomObstacle -genRandomObstacle tunables = do - prg <- Raaz.newPRG () :: IO Raaz.SystemPRG - randomkey <- Raaz.random prg :: IO AesKey - let size = sizeRandomObstacle tunables - return $ RandomObstacle $ mkRandomObstacle randomkey size - -mixinRandomObstacle :: RandomObstacle -> Raaz.KEY256 -> AesKey -mixinRandomObstacle (RandomObstacle (r, iv)) k = (k', iv) - where - k' = fromMaybe (error "mixinRandomObstacle fromByteString failed") $ - Raaz.fromByteString $ - Raaz.toByteString r `orBytes` Raaz.toByteString k + b = Raaz.toByteString randomiv + padding = B.replicate (B.length b - nbytes) 0 -orBytes :: B.ByteString -> B.ByteString -> B.ByteString -orBytes a b = B.pack $ map (uncurry (.|.)) $ zip (B.unpack a) (B.unpack b) +genPuzzleIV :: Tunables -> IO PuzzleIV +genPuzzleIV tunables = do + prg <- Raaz.newPRG () :: IO Raaz.SystemPRG + randomiv <- Raaz.random prg :: IO Raaz.IV + let size = sizePuzzleIV tunables + return $ mkPuzzleIV randomiv size newtype PaddedBytes = PaddedBytes { getPaddedBytes :: B.ByteString } deriving (Show) -- cgit v1.2.3