diff --git a/AES.cabal b/AES.cabal
--- a/AES.cabal
+++ b/AES.cabal
@@ -1,7 +1,7 @@
 Name: AES
 Synopsis: Fast AES encryption/decryption for bytestrings
 Description: A zero-copy binding to Brian Gladman's AES implementation, including a copy of that implementation
-Version: 0.0.3
+Version: 0.1.0
 License: BSD3
 License-file: COPYING
 Copyright: Copyright (c) 2009 University of Tromsø
@@ -14,7 +14,7 @@
 Build-Type: Simple
 Extra-source-files: cbits/aes.h, cbits/aesopt.h, cbits/aestab.h,
                     cbits/brg_endian.h, cbits/brg_types.h, cbits/aes.txt,
-                    cbits/aes_via_ace.h
+                    cbits/aes_via_ace.h, cbits/ctr_inc.h
 
 Library
   Build-Depends:
@@ -30,7 +30,8 @@
         Codec.Crypto.AES.IO
 
   ghc-options: -Wall
-
-  C-sources: cbits/aescrypt.c, cbits/aeskey.c, cbits/aestab.c, cbits/aes_modes.c
+  
+  C-sources: cbits/aescrypt.c, cbits/aeskey.c, cbits/aestab.c,
+             cbits/aes_modes.c, cbits/ctr_inc.c
   Include-Dirs: cbits
   
diff --git a/Codec/Crypto/AES/IO.hsc b/Codec/Crypto/AES/IO.hsc
--- a/Codec/Crypto/AES/IO.hsc
+++ b/Codec/Crypto/AES/IO.hsc
@@ -16,10 +16,12 @@
 #include "aes.h"
 #include "aestab.h"
 #include "brg_endian.h"
+#include "ctr_inc.h"
 
 newtype AESKey = AESKey B.ByteString
                deriving(Show)
 
+
 toKey :: B.ByteString -- ^ Must be 16, 24 or 32 bytes
         -> AESKey
 toKey bs | B.length bs `elem` [16,24,32] = AESKey bs
@@ -34,9 +36,6 @@
 
 data Direction = Encrypt | Decrypt
 
--- FIXME: CTR is slower than it has to be due to using safe foreign
--- calls, and could be sped up.
-
 -- | Modes ECB and CBC can only handle full 16-byte frames. This means
 -- the length of every strict bytestring passed in must be a multiple
 -- of 16; when using lazy bytestrings, its /component/ strict
@@ -46,15 +45,15 @@
 -- overflow for later. However, the total length of bytestrings passed
 -- in must still be a multiple of 16, or the overflow will be lost.
 --
--- In addition to the existing modes, a small amount of extra code
--- could add support for CTR
-data Mode = ECB | CBC | CFB --  | OFB --  | CTR
+-- For OFB and CTR, Encrypt and Decrypt are the same operation. For
+-- CTR, the IV is the initial value of the counter.
+data Mode = ECB | CBC | CFB  | OFB  | CTR
 
 data Context = ECBCtx DirectionalCtx
              | CBCCtx IV DirectionalCtx
              | CFBCtx IV Direction EncryptCtxP
---             | OFBCtx IV Direction EncryptCtxP
---             | CTRCtx Direction EncryptCtxP IV (ForeignPtr Int)
+             | OFBCtx IV EncryptCtxP
+             | CTRCtx IV EncryptCtxP
 
 
 
@@ -80,8 +79,12 @@
 newCtx' key iv CBC Encrypt = CBCCtx iv . EncryptCtx <$> encryptCtx key
 newCtx' key iv CBC Decrypt = CBCCtx iv . DecryptCtx <$> decryptCtx key
 newCtx' key iv CFB dir     = CFBCtx iv dir <$> encryptCtx key
--- newCtx' key iv OFB dir     = OFBCtx iv dir <$> encryptCtx key
+newCtx' key iv OFB _       = OFBCtx iv <$> encryptCtx key
+newCtx' key iv CTR _       = CTRCtx iv <$> encryptCtx key
 
+wrapCtr :: Context -> IO AESCtx
+wrapCtr ctx = AESCtx ctx <$> newIORef 0
+
 -- | Create a context for ECB, which doesn't need an IV
 newECBCtx :: B.ByteString -- ^ A 16, 24 or 32-byte AES key
             -> Direction -> IO AESCtx
@@ -91,9 +94,6 @@
 newECBCtx' key Encrypt = ECBCtx . EncryptCtx <$> encryptCtx key
 newECBCtx' key Decrypt = ECBCtx . DecryptCtx <$> decryptCtx key
 
-wrapCtr :: Context -> IO AESCtx
-wrapCtr ctx = AESCtx ctx <$> newIORef 0
-
 -- | Incrementally encrypt/decrypt bytestrings
 --
 -- crypt is definitely not thread-safe. Don't even think about
@@ -113,10 +113,8 @@
 crypt' (CBCCtx iv (DecryptCtx ctx)) = calliv _aes_cbc_decrypt iv ctx
 crypt' (CFBCtx iv Encrypt ctx)      = calliv _aes_cfb_encrypt iv ctx
 crypt' (CFBCtx iv Decrypt ctx)      = calliv _aes_cfb_decrypt iv ctx
--- crypt' (OFBCtx iv Encrypt ctx)      = calliv _aes_ofb_encrypt iv ctx
--- crypt' (OFBCtx iv Decrypt ctx)      = calliv _aes_ofb_decrypt iv ctx
--- crypt' (CTRCtx Encrypt ctx iv ctr) = crypt' (ctr_wrap _aes_ctr_encrypt ctr) ctx iv
--- crypt' (CTRCtx Decrypt ctx iv ctr) = crypt' (ctr_wrap _aes_ctr_decrypt ctr) ctx iv
+crypt' (OFBCtx iv ctx)              = calliv _aes_ofb_crypt iv ctx
+crypt' (CTRCtx iv ctx)              = aes_ctr_crypt iv ctx
 
 call :: (Ptr b -> Ptr Word8 -> Int -> Ptr a -> IO Int)
        -> ForeignPtr a -> B.ByteString -> Int -> IO B.ByteString
@@ -135,6 +133,14 @@
 addiv :: (t1 -> t2 -> t3 -> t -> t4 -> t5) -> t -> t1 -> t2 -> t3 -> t4 -> t5
 addiv f iv ibuf obuf len ctx = f ibuf obuf len iv ctx
 
+aes_ctr_crypt :: IV -> EncryptCtxP -> B.ByteString -> Int -> IO B.ByteString
+aes_ctr_crypt (IV ctr) ctx (BI.toForeignPtr -> (bs,offset,len)) retLen =
+  withForeignPtr ctx $ \ctxp ->
+  withForeignPtr bs $ \bsp ->
+  withForeignPtr ctr $ \ctrp ->
+  BI.create retLen $ \obuf ->
+  ensure $ _aes_ctr_crypt (bsp `plusPtr` offset) obuf len ctrp _ctr_inc ctxp
+
 foreign import ccall unsafe "aes_ecb_encrypt" _aes_ecb_encrypt
   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr EncryptCtxStruct -> IO Int
 foreign import ccall unsafe "aes_ecb_decrypt" _aes_ecb_decrypt
@@ -147,14 +153,11 @@
   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
 foreign import ccall unsafe "aes_cfb_decrypt" _aes_cfb_decrypt
   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
--- foreign import ccall unsafe "aes_ofb_encrypt" _aes_ofb_encrypt
---   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
--- foreign import ccall unsafe "aes_ofb_decrypt" _aes_ofb_decrypt
---   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
--- foreign import ccall safe "aes_ctr_encrypt" _aes_ctr_encrypt
---   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Int -> FunPtr (Ptr Int -> IO ()) -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
--- foreign import ccall safe "aes_ctr_decrypt" _aes_ctr_decrypt
---   :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Int -> FunPtr (Ptr Int -> IO ()) -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
+foreign import ccall unsafe "aes_ofb_crypt" _aes_ofb_crypt
+  :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Word8 -> Ptr EncryptCtxStruct -> IO Int
+foreign import ccall unsafe "aes_ctr_crypt" _aes_ctr_crypt
+  :: Ptr Word8 -> Ptr Word8 -> Int -> Ptr Word8 -> FunPtr (Ptr Word8 -> IO ()) -> Ptr EncryptCtxStruct -> IO Int
+foreign import ccall unsafe "&ctr_inc" _ctr_inc :: FunPtr (Ptr Word8 -> IO ())
 
 type EncryptCtxP = ForeignPtr EncryptCtxStruct
 
diff --git a/cbits/ctr_inc.c b/cbits/ctr_inc.c
new file mode 100644
--- /dev/null
+++ b/cbits/ctr_inc.c
@@ -0,0 +1,15 @@
+#include "aesopt.h"
+#include "ctr_inc.h"
+
+#if AES_BLOCK_SIZE != 16
+# error AES block size wrong ?!
+#endif
+
+void ctr_inc(unsigned char *cbuf) {
+  uint_64t *ctr = (uint_64t*)cbuf;
+  int word;
+  for (word = 0; word++; word < 2) {
+    ctr[word]++;
+    if (ctr[word]) break;
+  }
+}
diff --git a/cbits/ctr_inc.h b/cbits/ctr_inc.h
new file mode 100644
--- /dev/null
+++ b/cbits/ctr_inc.h
@@ -0,0 +1,1 @@
+void ctr_inc(unsigned char *);
