packages feed

clientsession 0.7.3 → 0.7.3.1

raw patch · 4 files changed

+116/−11 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

+ bench.hs view
@@ -0,0 +1,19 @@+import qualified Data.ByteString as B+import Web.ClientSession+import Data.Maybe+import Data.Serialize++import Criterion.Main+import Text.Printf++Right key = initKey (B.replicate 96 0xFE)+Just iv = mkIV (B.replicate 16 0xB0)++main :: IO ()+main =+  defaultMain+    [ bgroup "encrypt then decrypt"+        [ bench (printf "Message length = %d bytes" len) $+          whnf (fromJust . decrypt key . encrypt key iv) (B.replicate len 0xAA)+        | len <- [0, 50, 100, 400, 2000, 80000]]+    ]
clientsession.cabal view
@@ -1,5 +1,5 @@ name:            clientsession-version:         0.7.3+version:         0.7.3.1 license:         BSD3 license-file:    LICENSE author:          Michael Snoyman <michael@snoyman.com>, Felipe Lessa <felipe.lessa@gmail.com>@@ -13,6 +13,8 @@ cabal-version:   >= 1.8 build-type:      Simple homepage:        http://github.com/snoyberg/clientsession/tree/master+data-files:      bench.hs+extra-source-files: tests/runtests.hs  flag test   description: Build the executable to run unit tests
src/Web/ClientSession.hs view
@@ -20,12 +20,12 @@ -- you to store sensitive information on the client side without -- worrying about eavesdropping. ----- * Sign the encrypted cookie data using Skein-MAC-512-256.--- Besides detecting potential errors in storage or transmission--- of the cookies (integrity), the MAC also avoids malicious--- modifications of the cookie data by assuring you that the--- cookie data really was generated by this server--- (authenticity).+-- * Authenticate the encrypted cookie data using+-- Skein-MAC-512-256.  Besides detecting potential errors in+-- storage or transmission of the cookies (integrity), the MAC+-- also avoids malicious modifications of the cookie data by+-- assuring you that the cookie data really was generated by this+-- server (authenticity). -- -- * Encode everything using Base64.  Thus we avoid problems with -- non-printable characters by giving the browser a simple@@ -54,6 +54,8 @@  -- from base import Control.Monad (guard)+import Data.Bits ((.|.), xor)+import Data.List (foldl')  -- from directory import System.Directory (doesFileExist)@@ -172,9 +174,9 @@     iv <- randomIV     return $ encrypt key iv x --- | Encrypt (AES-CTR), sign (Skein-MAC-512-256) and encode--- (Base64) the given cookie data.  The returned byte string is--- ready to be used in a response header.+-- | Encrypt (AES-CTR), authenticate (Skein-MAC-512-256) and+-- encode (Base64) the given cookie data.  The returned byte+-- string is ready to be used in a response header. encrypt :: Key          -- ^ Key of the server.         -> IV           -- ^ New, random initialization vector (see 'randomIV').         -> S.ByteString -- ^ Serialized cookie data.@@ -199,8 +201,15 @@     guard (S.length dataBS >= 48) -- 16 bytes of IV + 32 bytes of Skein-MAC-512-256     let (auth, toBeAuthed) = S.splitAt 32 dataBS         auth' = macKey key toBeAuthed-    guard (encode auth' == auth)+    guard (encode auth' `compareHash` auth)     let (iv_e, encrypted) = S.splitAt 16 toBeAuthed     iv <- either (const Nothing) Just $ decode iv_e     let (x, _) = Modes.unCtr' Modes.incIV (aesKey key) iv encrypted     return x++-- | Compare two bytestrings.  Always takes the same ammount of+-- time, avoiding timing attacks.+compareHash :: S.ByteString -> S.ByteString -> Bool+compareHash s1 s2 =+    S.length s1 == S.length s2 &&+    foldl' (.|.) 0 (S.zipWith xor s1 s2) == 0
+ tests/runtests.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+import Test.HUnit+import Test.Hspec.Monadic+import Test.QuickCheck hiding (property)+import Test.Hspec.QuickCheck+import Test.Hspec.HUnit ()+import Control.Monad (replicateM)++import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as S8++import Web.ClientSession+import System.IO.Unsafe++main :: IO ()+main = hspecX $ describe "client session" $ do+    it "encrypt/decrypt success" $ property propEncDec+    it "encrypt/decrypt failure" $ property propEncDecFailure+    it "AES encrypt/decrypt success" $ property propAES+    it "AES encryption changes bs" $ property propAESChanges+    it "specific values" caseSpecific++propEncDec :: S.ByteString -> Bool+propEncDec bs = unsafePerformIO $ do+    key <- getDefaultKey+    s <- encryptIO key bs+    let bs' = decrypt key s+    return $ Just bs == bs'++propEncDecFailure :: S.ByteString -> Bool+propEncDecFailure bs = unsafePerformIO $ do+    key <- getDefaultKey+    s <- encryptIO key bs+    let bs' = decrypt key $ (S.head s + 1) `S.cons` S.drop 1 s+    return $ Just bs /= bs'++propAES :: MyKey -> MyIV -> S.ByteString -> Bool+propAES (MyKey key) (MyIV iv) bs = decrypt key (encrypt key iv bs) == Just bs++propAESChanges :: MyKey -> MyIV -> S.ByteString -> Bool+propAESChanges (MyKey key) (MyIV iv) bs = encrypt key iv bs /= bs++caseSpecific :: Assertion+caseSpecific = do+    let s = S8.pack $ show [("lo\ENQ\143XAq","\DC2\207\226\DC1;.z56|\203\222"),("\USnu#\139\ETXB\201 ","l"),("\RS\b,zM2U\184\191F)\EOT\220S\NUL","O\\\GSd\247\246\n\EOT\SYN\182U2G"),("\219\NAK\217\CAN\252","ym\STX\188\232?\\\145"),("\239k","\vRZP\a\DC2F>"),("\FS\180P &\RS\174zSL\\?@","p\170\237vZ|\GS>\SYNk\176n\r"),("","\199D\DC3\200m)"),("6\152tVhB\246)9","\ENQdfU\SUB"),("I\ACK\181\NUL","\129\&6s\130q\US)oR1\197\FSp\US\SYN0"),("\183\200<\250","\211  \131g4\207N\155"),("\248O6k\CANK\135\234.","`\205!+&Z&9\DLE\244\214HP\SI\161"),("\"I'\ACK\149 \CAN\197","\141N\201\SO\204\\o.\128\148")]+    key <- getDefaultKey+    iv <- randomIV+    Just s @=? decrypt key (encrypt key iv s)+    let s' = S.concat $ replicate 500 s+    Just s' @=? decrypt key (encrypt key iv s')++instance Arbitrary S.ByteString where+    arbitrary = S.pack `fmap` arbitrary++newtype MyKey = MyKey Key++instance Arbitrary MyKey where+    arbitrary = do+        ws <- replicateM 96 arbitrary+        either error (return . MyKey) $ initKey $ S.pack ws++instance Show MyKey where+    show _ = "<Key>"++newtype MyIV = MyIV IV++instance Arbitrary MyIV where+    arbitrary = do+        ws <- replicateM 16 arbitrary+        maybe (error "Invalid IV") (return . MyIV) $ mkIV $ S.pack ws++instance Show MyIV where+    show _ = "<Iv>"