packages feed

clientsession 0.9.1.2 → 0.9.2.0

raw patch · 3 files changed

+63/−71 lines, 3 filesdep +cryptonitedep −cipher-aesdep −cprng-aesdep −crypto-randomdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: cryptonite

Dependencies removed: cipher-aes, cprng-aes, crypto-random

Dependency ranges changed: base

API changes (from Hackage documentation)

Files

ChangeLog.md view
@@ -1,3 +1,9 @@+# ChangeLog for clientsession++## 0.9.2.0++* Migrate crypto-aes and cprng-aes to cryptonite. [#36](https://github.com/yesodweb/clientsession/pull/36)+ ## 0.9.1.2  * Clarify that we're using MIT license
clientsession.cabal view
@@ -1,5 +1,5 @@ name:            clientsession-version:         0.9.1.2+version:         0.9.2.0 license:         MIT license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>, Felipe Lessa <felipe.lessa@gmail.com>@@ -10,7 +10,7 @@                  encoding to avoid any issues with characters. category:        Web stability:       stable-cabal-version:   >= 1.8+cabal-version:   >= 1.10 build-type:      Simple homepage:        http://github.com/yesodweb/clientsession/tree/master extra-source-files: tests/runtests.hs bench.hs ChangeLog.md README.md@@ -20,6 +20,7 @@   default: False  executable clientsession-generate+    default-language: Haskell2010     main-is: generate.hs     build-depends:   base                    , clientsession@@ -27,6 +28,7 @@     hs-source-dirs: bin  library+    default-language: Haskell2010     build-depends:   base                >=4           && < 5                    , bytestring          >= 0.9                    , cereal              >= 0.3@@ -36,9 +38,7 @@                    , skein               == 1.0.*                    , base64-bytestring   >= 0.1.1.1                    , entropy             >= 0.2.1-                   , cprng-aes           >= 0.2-                   , cipher-aes          >= 0.1.7-                   , crypto-random+                   , cryptonite          >= 0.15                    , setenv     exposed-modules: Web.ClientSession     other-modules:   System.LookupEnv@@ -46,6 +46,7 @@     hs-source-dirs:  src  test-suite runtests+    default-language: Haskell2010     type: exitcode-stdio-1.0     build-depends:   base                    , bytestring          >= 0.9
src/Web/ClientSession.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE CPP #-} {-# LANGUAGE PackageImports #-}@@ -61,6 +62,7 @@ import Control.Applicative ((<$>)) import Control.Concurrent (forkIO) import Control.Monad (guard, when)+import Data.Bifunctor (first) import Data.Function (on)  #if MIN_VERSION_base(4,7,0)@@ -92,11 +94,12 @@  -- from crypto-api import Crypto.Classes (constTimeEq)-import "crypto-api" Crypto.Random (genSeedLength, reseed)-import Crypto.Types (ByteLength) --- from cipher-aes+-- from cryptonite import qualified Crypto.Cipher.AES as A+import Crypto.Cipher.Types(Cipher(..),BlockCipher(..),makeIV)+import Crypto.Error (eitherCryptoError)+import "cryptonite" Crypto.Random (ChaChaDRG,drgNew,randomBytesGenerate)  -- from skein import Crypto.Skein (skeinMAC', Skein_512_256)@@ -104,15 +107,7 @@ -- from entropy import System.Entropy (getEntropy) --- from cprng-aes-#if MIN_VERSION_cprng_aes(0,5,0)-import Crypto.Random.AESCtr (AESRNG, makeSystem)-import "crypto-random" Crypto.Random (cprgGenerate)-#else-import Crypto.Random.AESCtr (AESRNG, makeSystem, genRandomBytes)-#endif - -- | 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 must@@ -121,11 +116,7 @@ -- -- See also 'getDefaultKey' and 'initKey'. data Key = Key { aesKey ::-#if MIN_VERSION_cipher_aes(0, 2, 0)-                    !A.AES-#else-                    !A.Key-#endif+                    !A.AES256                  -- ^ AES key with 32 bytes.                , macKey :: !(S.ByteString -> Skein_512_256)                  -- ^ Skein-MAC key.  Instead of storing the key@@ -182,7 +173,7 @@ -- | Randomly construct a fresh initialization vector.  You -- /MUST NOT/ reuse initialization vectors. randomIV :: IO IV-randomIV = aesRNG+randomIV = chaChaRNG  -- | The default key file. defaultKeyFile :: FilePath@@ -264,12 +255,13 @@ initKey :: S.ByteString -> Either String Key initKey bs | S.length bs /= 96 = Left $ "Web.ClientSession.initKey: length of " ++                                          show (S.length bs) ++ " /= 96."-initKey bs = Right $ Key { aesKey = A.initKey preAesKey-                         , macKey = skeinMAC' preMacKey-                         , keyRaw = bs-                         }-    where-      (preMacKey, preAesKey) = S.splitAt 64 bs+initKey bs = do+  let (preMacKey, preAesKey) = S.splitAt 64 bs+  aesKey <- first show $ eitherCryptoError (cipherInit preAesKey)+  Right $ Key { aesKey+              , macKey = skeinMAC' preMacKey+              , keyRaw = bs+              }  -- | Same as 'encrypt', however randomly generates the -- initialization vector for you.@@ -286,16 +278,14 @@         -> S.ByteString -- ^ Serialized cookie data.         -> S.ByteString -- ^ Encoded cookie data to be given to                         -- the client browser.-encrypt key (IV iv) x = B.encode final-  where-#if MIN_VERSION_cipher_aes(0, 2, 0)-    encrypted  = A.encryptCTR (aesKey key) iv x-#else-    encrypted  = A.encryptCTR (aesKey key) (A.IV iv) x-#endif-    toBeAuthed = iv `S.append` encrypted-    auth       = macKey key toBeAuthed-    final      = encode auth `S.append` toBeAuthed+encrypt key (IV b) x = case makeIV b of+    Nothing -> error "Web.ClientSession.encrypt: Failed to makeIV"+    Just iv -> B.encode final+      where+        encrypted  = ctrCombine (aesKey key) iv x+        toBeAuthed = b `S.append` encrypted+        auth       = macKey key toBeAuthed+        final      = encode auth `S.append` toBeAuthed  -- | Decode (Base64), verify the integrity and authenticity -- (Skein-MAC-512-256) and decrypt (AES-CTR) the given encoded@@ -311,58 +301,53 @@         auth' = macKey key toBeAuthed     guard (encode auth' `constTimeEq` auth)     let (iv, encrypted) = S.splitAt 16 toBeAuthed-#if MIN_VERSION_cipher_aes(0, 2, 0)-    let iv' = iv-#else-    let iv' = A.IV iv-#endif-    return $! A.decryptCTR (aesKey key) iv' encrypted+    iv' <- makeIV iv+    return $! ctrCombine (aesKey key) iv' encrypted  +-- [from when the code used cprng-aes.AESRNG] -- Significantly more efficient random IV generation. Initial -- benchmarks placed it at 6.06 us versus 1.69 ms for -- Crypto.Modes.getIVIO, since it does not require /dev/urandom -- I/O for every call. -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.+-- [now with cryptonite.ChaChaDRG]+-- I haven't run any benchmark; this conversion is a case of “code+-- that doesn't crash trumps performance.” +data ChaChaState =+    CCSt {-# UNPACK #-} !ChaChaDRG -- Our CPRNG using ChaCha+         {-# UNPACK #-} !Int       -- How many IVs were generated with this+                                   -- CPRNG.  Used to control reseeding.+ -- | Construct initial state of the CPRNG.-aesSeed :: IO AESState-aesSeed = do-  rng <- makeSystem-  return $! ASt rng 0+chaChaSeed :: IO ChaChaState+chaChaSeed = do+  drg <- drgNew+  return $! CCSt drg 0  -- | Reseed the CPRNG with new entropy from the system pool.-aesReseed :: IO ()-aesReseed = do-  rng' <- makeSystem-  I.writeIORef aesRef $ ASt rng' 0+chaChaReseed :: IO ()+chaChaReseed = do+  drg' <- drgNew+  I.writeIORef chaChaRef $ CCSt drg' 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 #-}+chaChaRef :: I.IORef ChaChaState+chaChaRef = unsafePerformIO $ chaChaSeed >>= I.newIORef+{-# NOINLINE chaChaRef #-}  -- | 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+chaChaRNG :: IO IV+chaChaRNG = do   (bs, count) <--      I.atomicModifyIORef aesRef $ \(ASt rng count) ->-#if MIN_VERSION_cprng_aes(0, 5, 0)-          let (bs', rng') = cprgGenerate 16 rng-#elif MIN_VERSION_cprng_aes(0, 3, 2)-          let (bs', rng') = genRandomBytes 16 rng-#else-          let (bs', rng') = genRandomBytes rng 16-#endif-          in (ASt rng' (succ count), (bs', count))-  when (count == threshold) $ void $ forkIO aesReseed+      I.atomicModifyIORef chaChaRef $ \(CCSt drg count) ->+          let (bs', drg') = randomBytesGenerate 16 drg+          in (CCSt drg' (succ count), (bs', count))+  when (count == threshold) $ void $ forkIO chaChaReseed   return $! unsafeMkIV bs  where   void f = f >> return ()