packages feed

clientsession 0.7.3.4 → 0.7.3.5

raw patch · 2 files changed

+56/−27 lines, 2 filesdep +cprng-aesdep ~hspecPVP ok

version bump matches the API change (PVP)

Dependencies added: cprng-aes

Dependency ranges changed: hspec

API changes (from Hackage documentation)

Files

clientsession.cabal view
@@ -1,5 +1,5 @@ name:            clientsession-version:         0.7.3.4+version:         0.7.3.5 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>, Felipe Lessa <felipe.lessa@gmail.com>@@ -30,6 +30,7 @@                    , skein               >= 0.1        && < 0.2                    , base64-bytestring   >= 0.1.0.3    && < 0.2                    , entropy             >= 0.2.1+                   , cprng-aes           >= 0.2     exposed-modules: Web.ClientSession     ghc-options:     -Wall     hs-source-dirs:  src@@ -39,7 +40,7 @@     build-depends:   base                >=4           && < 5                    , bytestring          >= 0.9        && < 0.10                    , cryptocipher        >= 0.2.5      && < 0.3-                   , hspec               == 0.6.*+                   , hspec               >= 0.6        && < 0.10                    , QuickCheck          >= 2          && < 3                    , HUnit                    , transformers
src/Web/ClientSession.hs view
@@ -59,7 +59,6 @@ import qualified Data.IORef as I import System.IO.Unsafe (unsafePerformIO) import Control.Concurrent (forkIO)-import Control.Applicative ((<$>))  -- from directory import System.Directory (doesFileExist)@@ -72,8 +71,8 @@ import Data.Serialize (encode, decode)  -- from crypto-api-import Crypto.Classes (buildKey, encryptBlock)-import Crypto.Random (newGenIO, genBytes, SystemRandom)+import Crypto.Classes (buildKey)+import Crypto.Random (reseed) import qualified Crypto.Modes as Modes  -- from cryptocipher@@ -85,6 +84,9 @@ -- from entropy import System.Entropy (getEntropy) +-- from cprng-aes+import Crypto.Random.AESCtr (AESRNG, makeSystem, genRandomBytes)+ -- | The keys used to store the cookies.  We have an AES key used -- to encrypt the cookie and a Skein-MAC-512-256 key used verify -- the authencity and integrity of the cookie.  The AES key needs@@ -145,18 +147,12 @@         S.writeFile keyFile bs         return key' --- | Generate the given number of random bytes.-randomBytes :: Int -> IO S.ByteString-randomBytes len = do-    g <- newGenIO-    either (error . show) (return . fst) $ genBytes len (g :: SystemRandom)- -- | Generate a random 'Key'.  Besides the 'Key', the -- 'ByteString' passed to 'initKey' is returned so that it can be -- saved for later use. randomKey :: IO (S.ByteString, Key) randomKey = do-    bs <- randomBytes 96+    bs <- getEntropy 96     case initKey bs of         Left e -> error $ "Web.ClientSession.randomKey: never here, " ++ e         Right key -> return (bs, key)@@ -221,31 +217,63 @@     S.length s1 == S.length s2 &&     foldl' (.|.) 0 (S.zipWith xor s1 s2) == 0 --- Significantly more efficien random IV generation. Initial benchmarks placed--- it at 7.144764 us versus 1.686288 ms for Modes.getIVIO, since it does not--- require /dev/urandom I/O for every call.+-- Significantly more efficient random IV generation. Initial+-- benchmarks placed it at 6.06 us versus 1.69 ms for Modes.getIVIO,+-- since it does not require /dev/urandom I/O for every call. -data AESState = ASt {-# UNPACK #-} !A.AES256-                    {-# UNPACK #-} !(Modes.IV A.AES256)+data AESState =+    ASt {-# UNPACK #-} !AESRNG -- Our CPRNG using AES on CTR mode+        {-# UNPACK #-} !Int    -- How many IVs were generated with this+                               -- AESRNG.  Used to control reseeding. +-- | Construct initial state of the CPRNG. aesSeed :: IO AESState aesSeed = do-  Just key <- buildKey <$> getEntropy 32-  return $! ASt key Modes.zeroIV+  rng <- makeSystem+  return $! ASt rng 0 +-- | Reseed the CPRNG with new entropy from the system pool.+aesReseed :: IO ()+aesReseed = do+  ent <- getEntropy 64 -- XXX: Is it possible for getEntropy+                       --      to return less entropy than+                       --      than we asked it?  I assume "no",+                       --      but there's a check here just+                       --      in case.+  if S.length ent < 64+    then I.atomicModifyIORef aesRef $+             -- Use the old RNG, but force a reseed+             -- after another 'threshold' uses of it.+             \(ASt rng _) -> (ASt rng 0, ())+    else I.atomicModifyIORef aesRef $+             \(ASt rng _) ->+                 let Right rng' = reseed ent rng+                 in (ASt rng' 0, ())++-- | 'IORef' that keeps the current state of the CPRNG.  Yep,+-- global state.  Used in thread-safe was only, though. aesRef :: I.IORef AESState aesRef = unsafePerformIO $ aesSeed >>= I.newIORef+{-# NOINLINE aesRef #-} +-- | Construct a new 16-byte IV using our CPRNG.  Forks another+-- thread to reseed the CPRNG should its usage count reach a+-- hardcoded threshold. aesRNG :: IO IV aesRNG = do-  ASt key count <--      I.atomicModifyIORef aesRef $ \t@(ASt key' count') ->-          (ASt key' (Modes.incIV count'), t)-  when (count == threshold) $ void $ forkIO $ aesSeed >>= I.writeIORef aesRef-  let nextiv = encryptBlock key $ encode count-  either (error . show) return $ decode nextiv+  (bs, count) <-+      I.atomicModifyIORef aesRef $ \(ASt rng count) ->+          let (bs', rng') = genRandomBytes rng 16+          in (ASt rng' (succ count), (bs', count))+  when (count == threshold) $ void $ forkIO aesReseed+  either (error . show) return $ decode bs  where   void f = f >> return () -threshold :: Modes.IV A.AES256-threshold = iterate Modes.incIV Modes.zeroIV !! 1000+-- | How many IVs should be generated before reseeding the CPRNG.+-- This number depends basically on how paranoid you are.  We+-- think 100.000 is a good compromise: larger numbers give only a+-- small performance advantage, while it still is a small number+-- since we only generate 1.5 MiB of random data between reseeds.+threshold :: Int+threshold = 100000