diff --git a/clientsession.cabal b/clientsession.cabal
--- a/clientsession.cabal
+++ b/clientsession.cabal
@@ -1,12 +1,12 @@
 name:            clientsession
-version:         0.7.2
+version:         0.7.3
 license:         BSD3
 license-file:    LICENSE
-author:          Michael Snoyman <michael@snoyman.com>
+author:          Michael Snoyman <michael@snoyman.com>, Felipe Lessa <felipe.lessa@gmail.com>
 maintainer:      Michael Snoyman <michael@snoyman.com>
-synopsis:        Store session data in a cookie.
-description:     Achieves security through AES-CBC encryption and
-                 HMAC-SHA256 authentication.  Uses Base64
+synopsis:        Securely store session data in a client-side cookie.
+description:     Achieves security through AES-CTR encryption and
+                 Skein-MAC-512-256 authentication.  Uses Base64
                  encoding to avoid any issues with characters.
 category:        Web
 stability:       stable
@@ -25,7 +25,7 @@
                    , directory           >= 1          && < 1.2
                    , crypto-api          >= 0.6.4      && < 0.7
                    , cryptocipher        >= 0.2.5      && < 0.3
-                   , cryptohash          >= 0.7.1      && < 0.8
+                   , skein               >= 0.1        && < 0.2
                    , base64-bytestring   >= 0.1.0.3    && < 0.2
     exposed-modules: Web.ClientSession
     ghc-options:     -Wall
diff --git a/src/Web/ClientSession.hs b/src/Web/ClientSession.hs
--- a/src/Web/ClientSession.hs
+++ b/src/Web/ClientSession.hs
@@ -16,16 +16,16 @@
 -- Stores session data in a client cookie.  In order to do so,
 -- we:
 --
--- * Encrypt the cookie data using AES in CBC mode.  This allows
+-- * Encrypt the cookie data using AES in CTR mode.  This allows
 -- you to store sensitive information on the client side without
 -- worrying about eavesdropping.
 --
--- * Sign the encrypted cookie data using HMAC-SHA256.  Besides
--- detecting potential errors in storage or transmission of the
--- cookies (integrity), the HMAC-SHA256 code also avoids
--- malicious modifications of the cookie data by assuring you
--- that the cookie data really was generated by this server
--- (authentication).
+-- * 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).
 --
 -- * Encode everything using Base64.  Thus we avoid problems with
 -- non-printable characters by giving the browser a simple
@@ -52,46 +52,64 @@
     , decrypt
     ) where
 
-import Control.Arrow (second)
+-- from base
 import Control.Monad (guard)
-import Data.Bits (xor)
+
+-- from directory
 import System.Directory (doesFileExist)
+
+-- from bytestring
 import qualified Data.ByteString as S
-import qualified Crypto.Cipher.AES as A
-import Crypto.Hash.SHA256 (SHA256)
-import Crypto.HMAC (MacKey(..), hmac')
 import qualified Data.ByteString.Base64 as B
+
+-- from cereal
+import Data.Serialize (encode, decode)
+
+-- from crypto-api
+import Crypto.Classes (buildKey)
 import Crypto.Random (newGenIO, genBytes, SystemRandom)
-import Data.Serialize (encode)
+import qualified Crypto.Modes as Modes
 
+-- from cryptocipher
+import qualified Crypto.Cipher.AES as A
+
+-- from skein
+import Crypto.Skein (skeinMAC', Skein_512_256)
+
 -- | The keys used to store the cookies.  We have an AES key used
--- to encrypt the cookie and a HMAC-SHA256 key used verify the
--- authencity and integrity of the cookie.  The AES key needs to
--- have exactly 32 bytes (256 bits).  The HMAC-SHA256 should have
--- 64 bytes (512 bits), which is the block size of SHA256, but
--- any size may be 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
+-- to have exactly 32 bytes (256 bits) while Skein-MAC-512-256
+-- should have 64 bytes (512 bits).
 --
 -- See also 'getDefaultKey' and 'initKey'.
-data Key = Key { aesKey  :: A.Key
-               , hmacKey :: MacKey }
-         deriving (Eq, Show)
+data Key = Key { aesKey :: A.AES256
+                 -- ^ AES key with 32 bytes.
+               , macKey :: S.ByteString -> Skein_512_256
+                 -- ^ Skein-MAC key.  Instead of storing the key
+                 -- data, we store a partially applied function
+                 -- for calculating the MAC (see 'skeinMAC'').
+               }
 
--- | The initialization vector used by AES in CBC mode.  Should
--- be exactly 16 bytes long.
-newtype IV = IV S.ByteString
-    deriving Show
+-- | Dummy 'Show' instance.
+instance Show Key where
+    show _ = "<Web.ClientSession.Key>"
 
+-- | The initialization vector used by AES.  Should be exactly 16
+-- bytes long.
+type IV = Modes.IV A.AES256
+
 -- | Construct an initialization vector from a 'S.ByteString'.
 -- Fails if there isn't exactly 16 bytes.
 mkIV :: S.ByteString -> Maybe IV
-mkIV bs
-    | S.length bs == 16 = Just $ IV bs
-    | otherwise = Nothing
+mkIV bs = case (S.length bs, decode bs) of
+            (16, Right iv) -> Just iv
+            _              -> Nothing
 
 -- | Randomly construct a fresh initialization vector.  You
 -- /should not/ reuse initialization vectors.
 randomIV :: IO IV
-randomIV = fmap IV $ randomBytes 16
+randomIV = Modes.getIVIO
 
 -- | The default key file.
 defaultKeyFile :: FilePath
@@ -129,26 +147,23 @@
 -- saved for later use.
 randomKey :: IO (S.ByteString, Key)
 randomKey = do
-    bs <- randomBytes 64
+    bs <- randomBytes 96
     case initKey bs of
         Left e -> error $ "Web.ClientSession.randomKey: never here, " ++ e
         Right key -> return (bs, key)
 
--- | Initializes a 'Key' from a random 'S.ByteString'.  It's
--- better to give a 'S.ByteString' with exactly 64 bytes, but
--- anything with at least 32 bytes will work.
+-- | Initializes a 'Key' from a random 'S.ByteString'.  Fails if
+-- there isn't exactly 96 bytes (256 bits for AES and 512 bits
+-- for Skein-MAC-512-512).
 initKey :: S.ByteString -> Either String Key
-initKey bs | S.length bs < 32 = Left $ "Web.ClientSession.initKey: length of " ++
-                                       show (S.length bs) ++ " too small."
-initKey bs = fmap mk $ A.initKey256 preAesKey
+initKey bs | S.length bs /= 96 = Left $ "Web.ClientSession.initKey: length of " ++
+                                         show (S.length bs) ++ " /= 96."
+initKey bs = case buildKey preAesKey of
+               Nothing -> Left $ "Web.ClientSession.initKey: unknown error with buildKey."
+               Just k  -> Right $ Key { aesKey = k
+                                      , macKey = skeinMAC' preMacKey }
     where
-      preAesKey | S.length bs >= 64 = S.pack $ uncurry (S.zipWith xor) $ S.splitAt 32 bs
-                | otherwise         = S.take 32 bs
-      mk k = Key { aesKey  = k
-                 , hmacKey = MacKey bs }
-                 -- It's okay to have a MacKey where bs doesn't
-                 -- have exactly 512 bits, the size of the block
-                 -- used in SHA-256.  hmac' already deals with it.
+      (preMacKey, preAesKey) = S.splitAt 64 bs
 
 -- | Same as 'encrypt', however randomly generates the
 -- initialization vector for you.
@@ -157,39 +172,35 @@
     iv <- randomIV
     return $ encrypt key iv x
 
--- | Encrypt (AES-CBC), sign (HMAC-SHA256) and encode (Base64)
--- the given cookie data.  The returned byte string is ready to
--- be used in a response header.
+-- | 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 :: Key          -- ^ Key of the server.
         -> IV           -- ^ New, random initialization vector (see 'randomIV').
         -> S.ByteString -- ^ Serialized cookie data.
         -> S.ByteString -- ^ Encoded cookie data to be given to
                         -- the client browser.
-encrypt key (IV iv) x =
-    B.encode $ S.concat [iv, encode auth, encrypted]
+encrypt key iv x = B.encode final
   where
-    toPad = 16 - S.length x `mod` 16
-    pad = S.replicate toPad $ fromIntegral toPad
-    y = pad `S.append` x
-    encrypted = A.encryptCBC (aesKey key) iv y
-    auth = hmac' (hmacKey key) encrypted :: SHA256
+    (encrypted, _) = Modes.ctr' Modes.incIV (aesKey key) iv x
+    toBeAuthed     = encode iv `S.append` encrypted
+    auth           = macKey key toBeAuthed
+    final          = encode auth `S.append` toBeAuthed
 
 -- | Decode (Base64), verify the integrity and authenticity
--- (HMAC-SHA256) and decrypt (AES-CBC) the given encoded cookie
--- data.  Returns the original serialized cookie data.  Fails if
--- the data is corrupted.
+-- (Skein-MAC-512-256) and decrypt (AES-CTR) the given encoded
+-- cookie data.  Returns the original serialized cookie data.
+-- Fails if the data is corrupted.
 decrypt :: Key                -- ^ Key of the server.
         -> S.ByteString       -- ^ Encoded cookie data given by the browser.
         -> Maybe S.ByteString -- ^ Serialized cookie data.
 decrypt key dataBS64 = do
     dataBS <- either (const Nothing) Just $ B.decode dataBS64
-    if S.length dataBS `mod` 16 /= 0 || S.length dataBS < 48
-        then Nothing
-        else do
-            let (iv, (auth, encrypted)) = second (S.splitAt 32) $ S.splitAt 16 dataBS
-                auth' = hmac' (hmacKey key) encrypted :: SHA256
-            guard (encode auth' == auth)
-            let x = A.decryptCBC (aesKey key) iv encrypted
-            (td, _) <- S.uncons x
-            guard (td > 0 && td <= 16)
-            return $ S.drop (fromIntegral td) x
+    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)
+    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
