diff --git a/clientsession.cabal b/clientsession.cabal
--- a/clientsession.cabal
+++ b/clientsession.cabal
@@ -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
diff --git a/src/Web/ClientSession.hs b/src/Web/ClientSession.hs
--- a/src/Web/ClientSession.hs
+++ b/src/Web/ClientSession.hs
@@ -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
