diff --git a/Benchmark/bench.hs b/Benchmark/bench.hs
new file mode 100644
--- /dev/null
+++ b/Benchmark/bench.hs
@@ -0,0 +1,13 @@
+import Crypto.Cipher.AES128
+import Crypto.Classes
+import Crypto.Modes (zeroIV)
+import Criterion
+import Criterion.Main
+import System.Entropy
+
+main = do
+    let iv = zeroIV
+    pt <- getEntropy (2^20)
+    k  <- buildKeyIO :: IO AESKey
+    defaultMain
+        [ bench "aes-ctr" $ nf (fst . ctr k iv) pt ]
diff --git a/Crypto/Cipher/AES128.hs b/Crypto/Cipher/AES128.hs
--- a/Crypto/Cipher/AES128.hs
+++ b/Crypto/Cipher/AES128.hs
@@ -4,9 +4,12 @@
 
 import Crypto.Cipher.AES128.Internal
 import Crypto.Classes
+import Crypto.Types
+import Control.Monad (when)
 import Data.Serialize
 import Data.Tagged
 import Foreign.Ptr
+import Foreign.ForeignPtr
 import System.IO.Unsafe
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Internal as B
@@ -41,6 +44,17 @@
         B.unsafeUseAsCStringLen b $ \(inP,len) -> do
          B.create (B.length b) $ \outP -> do
             decryptECB k (castPtr outP) (castPtr inP) (len`div`blkSize)
+    ctr k (IV bs) pt = unsafePerformIO $ do
+        B.unsafeUseAsCStringLen pt $ \(inP, len) -> do
+         B.unsafeUseAsCStringLen bs $ \(ivP, ivLen) -> do
+            when (ivLen /= (blockSizeBytes .::. k))
+                (error "Cipher-AES128: IV wrong length!  They type system would have/should have caught this if you didn't use the IV constructor...")
+            newIVFP <- B.mallocByteString ivLen
+            ct <- B.create len $ \outP -> withForeignPtr newIVFP $ \newIVP -> do
+                encryptCTR k (castPtr ivP) (castPtr newIVP) (castPtr outP) (castPtr inP) len
+            let newIV = B.fromForeignPtr newIVFP 0 ivLen
+            return (ct,IV newIV)
+    unCtr = ctr
 
 blkSize :: Int
 blkSize = 16
diff --git a/Crypto/Cipher/AES128/Internal.hs b/Crypto/Cipher/AES128/Internal.hs
--- a/Crypto/Cipher/AES128/Internal.hs
+++ b/Crypto/Cipher/AES128/Internal.hs
@@ -57,6 +57,7 @@
 foreign import ccall unsafe "aes/aes.h encrypt_ctr"
     c_encrypt_ctr :: AESKeyPtr
                   -> Ptr Word8 -- ^ 128 bit IV
+                  -> Ptr Word8 -- ^ 128 bit new IV
                   -> Ptr Word8 -- ^ Result
                   -> Ptr Word8 -- ^ Input
                   -> Word32    -- ^ Input length in bytes
@@ -64,6 +65,7 @@
 
 c_decrypt_ctr :: AESKeyPtr
               -> Ptr Word8 -- ^ 128 bit IV
+              -> Ptr Word8 -- ^ 128 bit new IV
               -> Ptr Word8 -- ^ Result
               -> Ptr Word8 -- ^ Input
               -> Word32    -- ^ Input length in bytes
@@ -145,21 +147,23 @@
 
 encryptCTR :: AESKey
            -> Ptr Word8 -- ^ IV
+           -> Ptr Word8 -- ^ NEW IV
            -> Ptr Word8 -- ^ CT
            -> Ptr Word8 -- ^ PT
            -> Int       -- ^ Length in bytes
            -> IO ()
-encryptCTR (AESKey _ k) iv ct pt len = withForeignPtr k $ \p -> do
-    c_encrypt_ctr p iv ct pt (fromIntegral len)
+encryptCTR (AESKey _ k) iv niv ct pt len = withForeignPtr k $ \p -> do
+    c_encrypt_ctr p iv niv ct pt (fromIntegral len)
 {-# INLINE encryptCTR #-}
 
 decryptCTR :: AESKey
            -> Ptr Word8 -- ^ IV
+           -> Ptr Word8 -- ^ NEW IV
            -> Ptr Word8 -- ^ CT
            -> Ptr Word8 -- ^ PT
            -> Int       -- ^ Length in bytes
            -> IO ()
 
-decryptCTR (AESKey _ k) iv ct pt len = withForeignPtr k $ \p -> do
-    c_decrypt_ctr p iv ct pt (fromIntegral len)
+decryptCTR (AESKey _ k) iv niv ct pt len = withForeignPtr k $ \p -> do
+    c_decrypt_ctr p iv niv ct pt (fromIntegral len)
 {-# INLINE decryptCTR #-}
diff --git a/cbits/aes/aes.c b/cbits/aes/aes.c
--- a/cbits/aes/aes.c
+++ b/cbits/aes/aes.c
@@ -362,22 +362,27 @@
         a->q[1] = cpu_to_be64(a1);
 }
 
-void encrypt_ctr(AESKey *key, uint8_t *iv, uint8_t *output, uint8_t *input, uint32_t len)
+void encrypt_ctr(const AESKey *key, const uint8_t *iv, uint8_t *newIV, uint8_t *output, const uint8_t *input, uint32_t len)
 {
-        aes_block block, o;
+        aes_block *block, o;
         uint32_t nb_blocks = len / 16;
         int i;
 
         /* preload IV in block */
-        block128_copy(&block, (aes_block *)iv);
+        if(NULL != newIV)
+            block = (aes_block*) newIV;
+        else
+            block = alloca(sizeof(aes_block));
 
-        for ( ; nb_blocks-- > 0; block128_inc_be(&block), output += 16, input += 16) {
-                encrypt_ecb(key, (uint8_t *)&o, (uint8_t *)&block, 1);
+        block128_copy(block, (aes_block *)iv);
+
+        for ( ; nb_blocks-- > 0; block128_inc_be(block), output += 16, input += 16) {
+                encrypt_ecb(key, (uint8_t *)&o, (uint8_t *)block, 1);
                 block128_vxor((block128 *) output, &o, (block128 *) input);
         }
 
         if ((len % 16) != 0) {
-                encrypt_ecb(key, (uint8_t *)&o, (uint8_t *)&block, 1);
+                encrypt_ecb(key, (uint8_t *)&o, (uint8_t *)block, 1);
                 for (i = 0; i < (len % 16); i++) {
                         *output = ((uint8_t *) &o)[i] ^ *input;
                         output += 1;
diff --git a/cbits/include/aes.h b/cbits/include/aes.h
--- a/cbits/include/aes.h
+++ b/cbits/include/aes.h
@@ -20,10 +20,11 @@
                          , uint8_t *aad, uint32_t aadLen
                          , uint8_t *ct, uint32_t ctLen
                          , uint8_t *pt, uint8_t *tag);
-void encrypt_ctr( AESKey *key
-                    , uint8_t *iv
-                    , uint8_t *dst
-                    , uint8_t *src
-                    , uint32_t nr);
+void encrypt_ctr( const AESKey *key
+                , const uint8_t *iv  /* 16 bytes buffer with the count */
+                , uint8_t *newIV     /* the return buffer for the next IV (or NULL) */
+                , uint8_t *dst       /* 'len' byte buffer for output */
+                , const uint8_t *src /* 'len' bytes of input */
+                , uint32_t len);     /* Length in bytes */
 
 #endif
diff --git a/cipher-aes128.cabal b/cipher-aes128.cabal
--- a/cipher-aes128.cabal
+++ b/cipher-aes128.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                cipher-aes128
-version:             0.2.5
+version:             0.3
 synopsis:            AES128 using AES-NI when available.
 description:         AES128 with crypto-api instances and a trampoline between Vincent Hanquez's C-based and x86 NI-based AES.  Patches welcome to add additional high-performance backends (ARM?)
 license:             BSD3
@@ -29,7 +29,7 @@
   exposed-modules:     Crypto.Cipher.AES128, Crypto.Cipher.AES128.Internal
   build-depends:       base >=4.5 && < 5,
                        bytestring,
-                       crypto-api,
+                       crypto-api >= 0.11,
                        tagged,
                        cereal
   ghc-options:         -Wall -O2
@@ -43,3 +43,15 @@
 source-repository head
   type:         git
   location:     https://github.com/TomMD/cipher-aes128
+
+benchmark bench
+  type:         exitcode-stdio-1.0
+  hs-source-dirs:       . Benchmark
+  main-is:              bench.hs
+  build-depends:        base < 5, criterion, crypto-api, entropy, bytestring, tagged, cereal
+  ghc-options:          -O2
+  include-dirs:        cbits/include
+  c-sources:              ./cbits/aes/aes.c
+                        , ./cbits/aes/ni/aes_x86ni.c
+                        , ./cbits/aes/generic/aes_generic.c
+  cc-options:          -O3
