summaryrefslogtreecommitdiffhomepage
path: root/Encryption.hs
diff options
context:
space:
mode:
authorJoey Hess <joeyh@joeyh.name>2016-08-11 22:13:05 -0400
committerJoey Hess <joeyh@joeyh.name>2016-08-11 22:13:05 -0400
commit7db612b232a0f8a98fa695da6f14853284def681 (patch)
tree4c7c7b641f313c0bcf0106e19b4c42c73f41356f /Encryption.hs
parent73d1b3d2dfb0f225132ab31a701e6378422e2a37 (diff)
downloadkeysafe-7db612b232a0f8a98fa695da6f14853284def681.tar.gz
simplify by using the IV as the puzzle
Diffstat (limited to 'Encryption.hs')
-rw-r--r--Encryption.hs77
1 files changed, 32 insertions, 45 deletions
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)