diff --git a/Crypto/Cipher/Tests.hs b/Crypto/Cipher/Tests.hs
--- a/Crypto/Cipher/Tests.hs
+++ b/Crypto/Cipher/Tests.hs
@@ -9,6 +9,7 @@
 {-# LANGUAGE ViewPatterns #-}
 module Crypto.Cipher.Tests
     ( testBlockCipher
+    , testBlockCipherIO
     , testStreamCipher
     -- * KATs
     , defaultKATs
@@ -26,6 +27,7 @@
 import Test.Framework (Test, testGroup)
 
 import Crypto.Cipher.Types
+import Crypto.Cipher.Types.Unsafe
 import Crypto.Cipher.Tests.KATs
 import Crypto.Cipher.Tests.Properties
 
@@ -34,6 +36,13 @@
 testBlockCipher kats cipher = testGroup (cipherName cipher)
     (  (if kats == defaultKATs  then [] else [testKATs kats cipher])
     ++ testModes cipher
+    )
+
+-- | Return test for a specific blockcipher and a list of KATs
+testBlockCipherIO :: BlockCipherIO a => KATs -> a -> Test
+testBlockCipherIO _ cipher = testGroup ("mutable " ++ cipherName cipher)
+    ( []
+    ++ testIOModes cipher
     )
 
 -- | Return tests for a specific streamcipher and a list of KATs
diff --git a/Crypto/Cipher/Tests/KATs.hs b/Crypto/Cipher/Tests/KATs.hs
--- a/Crypto/Cipher/Tests/KATs.hs
+++ b/Crypto/Cipher/Tests/KATs.hs
@@ -95,7 +95,10 @@
 defaultStreamKATs = []
 
 -- | tests related to KATs
-testKATs :: BlockCipher cipher => KATs -> cipher -> Test
+testKATs :: BlockCipher cipher
+         => KATs
+         -> cipher
+         -> Test
 testKATs kats cipher = testGroup "KAT"
     (   maybeGroup makeECBTest "ECB" (kat_ECB kats)
      ++ maybeGroup makeCBCTest "CBC" (kat_CBC kats)
@@ -149,9 +152,6 @@
                 etag = aeadFinalize aeadEFinal (aeadTaglen d)
                 dtag = aeadFinalize aeadDFinal (aeadTaglen d)
                
-        cipherMakeIV :: BlockCipher cipher => cipher -> ByteString -> IV cipher
-        cipherMakeIV _ bs = fromJust $ makeIV bs
-
 testStreamKATs :: StreamCipher cipher => [KAT_Stream] -> cipher -> Test
 testStreamKATs kats cipher = testGroup "KAT" $ maybeGroup makeStreamTest "Stream" kats
   where makeStreamTest i d =
@@ -164,6 +164,10 @@
 cipherMakeKey c bs = case makeKey bs of
                         Left e -> error ("invalid key " ++ show bs ++ " for " ++ show (cipherName c) ++ " " ++ show e)
                         Right k  -> k
+
+cipherMakeIV :: BlockCipher cipher => cipher -> ByteString -> IV cipher
+cipherMakeIV _ bs = fromJust $ makeIV bs
+
 
 maybeGroup :: (String -> t -> [Test]) -> TestName -> [t] -> [Test]
 maybeGroup mkTest groupName l
diff --git a/Crypto/Cipher/Tests/Properties.hs b/Crypto/Cipher/Tests/Properties.hs
--- a/Crypto/Cipher/Tests/Properties.hs
+++ b/Crypto/Cipher/Tests/Properties.hs
@@ -10,39 +10,56 @@
 import Test.QuickCheck
 
 import Crypto.Cipher.Types
+import Crypto.Cipher.Types.Unsafe
 import qualified Data.ByteString as B
+import qualified Data.ByteString.Internal as B
 import Data.Byteable
 import Data.Maybe
 
+-- | any sized bytestring
+newtype Plaintext a = Plaintext B.ByteString
+    deriving (Show,Eq)
+
+instance Byteable (Plaintext a) where
+    toBytes (Plaintext b) = b
+
+-- | A multiple of blocksize bytestring
+newtype PlaintextBS a = PlaintextBS B.ByteString
+    deriving (Show,Eq)
+
+instance Byteable (PlaintextBS a) where
+    toBytes (PlaintextBS b) = b
+
 -- | a ECB unit test
-data ECBUnit a = ECBUnit (Key a) B.ByteString
+data ECBUnit a = ECBUnit (Key a) (PlaintextBS a)
     deriving (Eq)
 
 -- | a CBC unit test
-data CBCUnit a = CBCUnit (Key a) (IV a) B.ByteString
+data CBCUnit a = CBCUnit (Key a) (IV a) (PlaintextBS a)
     deriving (Eq)
 
 -- | a CBC unit test
-data CFBUnit a = CFBUnit (Key a) (IV a) B.ByteString
+data CFBUnit a = CFBUnit (Key a) (IV a) (PlaintextBS a)
     deriving (Eq)
 
 -- | a CFB unit test
-data CFB8Unit a = CFB8Unit (Key a) (IV a) B.ByteString
+data CFB8Unit a = CFB8Unit (Key a) (IV a) (Plaintext a)
     deriving (Eq)
 
 -- | a CTR unit test
-data CTRUnit a = CTRUnit (Key a) (IV a) B.ByteString
+data CTRUnit a = CTRUnit (Key a) (IV a) (Plaintext a)
     deriving (Eq)
 
 -- | a XTS unit test
-data XTSUnit a = XTSUnit (Key a) (Key a) (IV a) B.ByteString
+data XTSUnit a = XTSUnit (Key a) (Key a) (IV a) (PlaintextBS a)
     deriving (Eq)
 
 -- | a AEAD unit test
-data AEADUnit a = AEADUnit (Key a) B.ByteString B.ByteString B.ByteString
+data AEADUnit a = AEADUnit (Key a) B.ByteString (Plaintext a) (Plaintext a)
     deriving (Eq)
 
-data StreamUnit a = StreamUnit (Key a) B.ByteString
+-- | Stream cipher unit test
+data StreamUnit a = StreamUnit (Key a) (Plaintext a)
     deriving (Eq)
 
 instance Show (ECBUnit a) where
@@ -83,27 +100,27 @@
 generateIvAEAD :: Gen B.ByteString
 generateIvAEAD = choose (12,90) >>= \sz -> (B.pack <$> replicateM sz arbitrary)
 
--- | Generate a plaintext multiple of 16 bytes. TODO replace by one function that use the blockSize
--- cipher instance
-generatePlaintextMultiple16 :: Gen B.ByteString
-generatePlaintextMultiple16 = choose (1,128) >>= \size -> replicateM (size*16) arbitrary >>= return . B.pack
+-- | Generate a plaintext multiple of blocksize bytes
+generatePlaintextMultipleBS :: BlockCipher a => Gen (PlaintextBS a)
+generatePlaintextMultipleBS = choose (1,128) >>= \size -> replicateM (size * 16) arbitrary >>= return . PlaintextBS . B.pack
 
-generatePlaintext :: Gen B.ByteString
-generatePlaintext = choose (0,324) >>= \size -> replicateM size arbitrary >>= return . B.pack
+-- | Generate any sized plaintext
+generatePlaintext :: Gen (Plaintext a)
+generatePlaintext = choose (0,324) >>= \size -> replicateM size arbitrary >>= return . Plaintext . B.pack
 
 instance BlockCipher a => Arbitrary (ECBUnit a) where
     arbitrary = ECBUnit <$> generateKey
-                        <*> generatePlaintextMultiple16
+                        <*> generatePlaintextMultipleBS
 
 instance BlockCipher a => Arbitrary (CBCUnit a) where
     arbitrary = CBCUnit <$> generateKey
                         <*> generateIv
-                        <*> generatePlaintextMultiple16
+                        <*> generatePlaintextMultipleBS
 
 instance BlockCipher a => Arbitrary (CFBUnit a) where
     arbitrary = CFBUnit <$> generateKey
                         <*> generateIv
-                        <*> generatePlaintextMultiple16
+                        <*> generatePlaintextMultipleBS
 
 instance BlockCipher a => Arbitrary (CFB8Unit a) where
     arbitrary = CFB8Unit <$> generateKey <*> generateIv <*> generatePlaintext
@@ -117,7 +134,7 @@
     arbitrary = XTSUnit <$> generateKey
                         <*> generateKey
                         <*> generateIv
-                        <*> generatePlaintextMultiple16
+                        <*> generatePlaintextMultipleBS
 
 instance BlockCipher a => Arbitrary (AEADUnit a) where
     arbitrary = AEADUnit <$> generateKey
@@ -129,62 +146,54 @@
     arbitrary = StreamUnit <$> generateKey
                            <*> generatePlaintext
 
--- | Test a generic block cipher for properties
--- related to block cipher modes.
-testModes :: BlockCipher a => a -> [Test]
-testModes cipher =
-    [ testGroup "decrypt.encrypt==id"
-        [ testProperty "ECB" ecbProp
-        , testProperty "CBC" cbcProp
-        , testProperty "CFB" cfbProp
-        , testProperty "CFB8" cfb8Prop
-        , testProperty "CTR" ctrProp
-        , testProperty "XTS" xtsProp
-        , testProperty "OCB" (aeadProp AEAD_OCB)
-        , testProperty "CCM" (aeadProp AEAD_CCM)
-        , testProperty "EAX" (aeadProp AEAD_EAX)
-        , testProperty "CWC" (aeadProp AEAD_CWC)
-        , testProperty "GCM" (aeadProp AEAD_GCM)
-        ]
+testBlockCipherBasic :: BlockCipher a => a -> [Test]
+testBlockCipherBasic cipher = [ testProperty "ECB" ecbProp ]
+  where ecbProp = toTests cipher
+        toTests :: BlockCipher a => a -> (ECBUnit a -> Bool)
+        toTests _ = testProperty_ECB
+        testProperty_ECB (ECBUnit (cipherInit -> ctx) (toBytes -> plaintext)) =
+            plaintext `assertEq` ecbDecrypt ctx (ecbEncrypt ctx plaintext)
+
+testBlockCipherModes :: BlockCipher a => a -> [Test]
+testBlockCipherModes cipher =
+    [ testProperty "CBC" cbcProp
+    , testProperty "CFB" cfbProp
+    , testProperty "CFB8" cfb8Prop
+    , testProperty "CTR" ctrProp
     ]
-  where (ecbProp,cbcProp,cfbProp,cfb8Prop,ctrProp,xtsProp,aeadProp) = toTests cipher
+  where (cbcProp,cfbProp,cfb8Prop,ctrProp) = toTests cipher
         toTests :: BlockCipher a
                 => a
-                -> ((ECBUnit a -> Bool),
-                    (CBCUnit a -> Bool),
-                    (CFBUnit a -> Bool),
-                    (CFB8Unit a -> Bool),
-                    (CTRUnit a -> Bool),
-                    (XTSUnit a -> Bool),
-                    (AEADMode -> AEADUnit a -> Bool))
-        toTests _ = (testProperty_ECB
-                    ,testProperty_CBC
+                -> ((CBCUnit a -> Bool), (CFBUnit a -> Bool), (CFB8Unit a -> Bool), (CTRUnit a -> Bool))
+        toTests _ = (testProperty_CBC
                     ,testProperty_CFB
                     ,testProperty_CFB8
                     ,testProperty_CTR
-                    ,testProperty_XTS
-                    ,testProperty_AEAD
                     )
-        testProperty_ECB (ECBUnit (cipherInit -> ctx) plaintext) =
-            plaintext `assertEq` ecbDecrypt ctx (ecbEncrypt ctx plaintext)
-
-        testProperty_CBC (CBCUnit (cipherInit -> ctx) testIV plaintext) =
+        testProperty_CBC (CBCUnit (cipherInit -> ctx) testIV (toBytes -> plaintext)) =
             plaintext `assertEq` cbcDecrypt ctx testIV (cbcEncrypt ctx testIV plaintext)
 
-        testProperty_CFB (CFBUnit (cipherInit -> ctx) testIV plaintext) =
+        testProperty_CFB (CFBUnit (cipherInit -> ctx) testIV (toBytes -> plaintext)) =
             plaintext `assertEq` cfbDecrypt ctx testIV (cfbEncrypt ctx testIV plaintext)
 
-        testProperty_CFB8 (CFB8Unit (cipherInit -> ctx) testIV plaintext) =
+        testProperty_CFB8 (CFB8Unit (cipherInit -> ctx) testIV (toBytes -> plaintext)) =
             plaintext `assertEq` cfb8Decrypt ctx testIV (cfb8Encrypt ctx testIV plaintext)
 
-        testProperty_CTR (CTRUnit (cipherInit -> ctx) testIV plaintext) =
+        testProperty_CTR (CTRUnit (cipherInit -> ctx) testIV (toBytes -> plaintext)) =
             plaintext `assertEq` ctrCombine ctx testIV (ctrCombine ctx testIV plaintext)
 
-        testProperty_XTS (XTSUnit (cipherInit -> ctx1) (cipherInit -> ctx2) testIV plaintext)
-            | blockSize ctx1 == 16 = plaintext `assertEq` xtsDecrypt (ctx1, ctx2) testIV 0 (xtsEncrypt (ctx1, ctx2) testIV 0 plaintext)
-            | otherwise            = True
-
-        testProperty_AEAD mode (AEADUnit (cipherInit -> ctx) testIV aad plaintext) =
+testBlockCipherAEAD :: BlockCipher a => a -> [Test]
+testBlockCipherAEAD cipher =
+    [ testProperty "OCB" (aeadProp AEAD_OCB)
+    , testProperty "CCM" (aeadProp AEAD_CCM)
+    , testProperty "EAX" (aeadProp AEAD_EAX)
+    , testProperty "CWC" (aeadProp AEAD_CWC)
+    , testProperty "GCM" (aeadProp AEAD_GCM)
+    ]
+  where aeadProp = toTests cipher
+        toTests :: BlockCipher a => a -> (AEADMode -> AEADUnit a -> Bool)
+        toTests _ = testProperty_AEAD
+        testProperty_AEAD mode (AEADUnit (cipherInit -> ctx) testIV (toBytes -> aad) (toBytes -> plaintext)) =
             case aeadInit mode ctx testIV of
                 Just iniAead ->
                     let aead           = aeadAppendHeader iniAead aad
@@ -195,10 +204,54 @@
                      in (plaintext `assertEq` dText) && (toBytes eTag `assertEq` toBytes dTag)
                 Nothing -> True
 
+testBlockCipherXTS :: BlockCipher a => a -> [Test]
+testBlockCipherXTS cipher = [testProperty "XTS" xtsProp]
+  where xtsProp = toTests cipher
+        toTests :: BlockCipher a => a -> (XTSUnit a -> Bool)
+        toTests _ = testProperty_XTS
+
+        testProperty_XTS (XTSUnit (cipherInit -> ctx1) (cipherInit -> ctx2) testIV (toBytes -> plaintext))
+            | blockSize ctx1 == 16 = plaintext `assertEq` xtsDecrypt (ctx1, ctx2) testIV 0 (xtsEncrypt (ctx1, ctx2) testIV 0 plaintext)
+            | otherwise            = True
+
+-- | Test a generic block cipher for properties
+-- related to block cipher modes.
+testModes :: BlockCipher a => a -> [Test]
+testModes cipher =
+    [ testGroup "decrypt.encrypt==id"
+        (testBlockCipherBasic cipher ++ testBlockCipherModes cipher ++ testBlockCipherAEAD cipher ++ testBlockCipherXTS cipher)
+    ]
+
+-- | Test a generic block cipher for properties
+-- related to BlockCipherIO cipher modes.
+testIOModes :: BlockCipherIO a => a -> [Test]
+testIOModes cipher =
+    [ testGroup "mutable"
+        [ testProperty "ECB" (testProperty_ECB cipher)
+        , testProperty "CBC" (testProperty_CBC cipher) ]
+    ]
+  where testProperty_ECB :: BlockCipherIO a => a -> (ECBUnit a) -> Bool
+        testProperty_ECB _ (ECBUnit (cipherInit -> ctx) (toBytes -> plaintext)) =
+            plaintext == B.unsafeCreate (B.length plaintext) encryptDecryptMutable
+          where encryptDecryptMutable buf = withBytePtr plaintext $ \src -> do
+                    ecbEncryptMutable ctx buf src (fromIntegral $ B.length plaintext)
+                    ecbDecryptMutable ctx buf buf (fromIntegral $ B.length plaintext)
+
+        testProperty_CBC :: BlockCipherIO a => a -> (CBCUnit a) -> Bool
+        testProperty_CBC _ (CBCUnit (cipherInit -> ctx) testIV (toBytes -> plaintext)) =
+            plaintext == B.unsafeCreate (B.length plaintext) encryptDecryptMutable
+          where encryptDecryptMutable buf =
+                    void $ B.create (B.length plaintext) $ \tmp ->
+                    withBytePtr plaintext $ \src ->
+                    withBytePtr testIV $ \iv -> do
+                        cbcEncryptMutable ctx iv tmp src (fromIntegral $ B.length plaintext)
+                        cbcDecryptMutable ctx iv buf tmp (fromIntegral $ B.length plaintext)
+                    
+-- | Test stream mode
 testStream :: StreamCipher a => a -> [Test]
 testStream cipher = [testProperty "combine.combine==id" (testStreamUnit cipher)]
   where testStreamUnit :: StreamCipher a => a -> (StreamUnit a -> Bool)
-        testStreamUnit _ (StreamUnit (cipherInit -> ctx) plaintext) =
+        testStreamUnit _ (StreamUnit (cipherInit -> ctx) (toBytes -> plaintext)) =
             let cipherText = fst $ streamCombine ctx plaintext
              in fst (streamCombine ctx cipherText) `assertEq` plaintext
 
diff --git a/crypto-cipher-tests.cabal b/crypto-cipher-tests.cabal
--- a/crypto-cipher-tests.cabal
+++ b/crypto-cipher-tests.cabal
@@ -1,5 +1,5 @@
 Name:                crypto-cipher-tests
-Version:             0.0.10
+Version:             0.0.11
 Synopsis:            Generic cryptography cipher tests
 Description:         Generic cryptography cipher tests
 License:             BSD3
@@ -27,7 +27,7 @@
                    , bytestring
                    , byteable >= 0.1.1 && < 0.2
                    , securemem >= 0.1.1 && < 0.2
-                   , crypto-cipher-types >= 0.0.7 && < 0.1
+                   , crypto-cipher-types >= 0.0.8 && < 0.1
   ghc-options:       -Wall -fwarn-tabs
 
 Test-Suite test-crypto-cipher-dummy
@@ -37,7 +37,7 @@
   Build-Depends:     base >= 3 && < 5
                    , bytestring
                    , byteable
-                   , crypto-cipher-types >= 0.0.7
+                   , crypto-cipher-types
                    , crypto-cipher-tests
                    , mtl
                    , QuickCheck >= 2
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -3,6 +3,7 @@
 
 import Test.Framework (defaultMain)
 import Crypto.Cipher.Types
+import Crypto.Cipher.Types.Unsafe
 import Crypto.Cipher.Tests
 import qualified Data.ByteString as B
 import Data.Bits (xor)
@@ -18,15 +19,25 @@
 
 instance BlockCipher XorCipher where
     blockSize  _   = 16
-    ecbEncrypt _ b = B.pack $ B.zipWith xor (B.replicate (B.length b) 0xa5) b
-    ecbDecrypt _ b = B.pack $ B.zipWith xor (B.replicate (B.length b) 0xa5) b
+    ecbEncrypt _ s = xorBS s
+    ecbDecrypt _ s = xorBS s
 
+instance BlockCipherIO XorCipher where
+    ecbEncryptMutable cipher d s len = onBlock cipher xorBS d s len
+    ecbDecryptMutable cipher d s len = onBlock cipher xorBS d s len
+
 instance StreamCipher XorCipher where
     streamCombine _ b = (B.pack $ B.zipWith xor (B.replicate (B.length b) 0x12) b, XorCipher)
 
+xorBS :: B.ByteString -> B.ByteString
+xorBS b = B.pack $ B.zipWith xor (B.replicate (B.length b) 0xa5) b
+
 tests =
-    [ testBlockCipher defaultKATs (undefined :: XorCipher)
-    , testStreamCipher defaultStreamKATs (undefined :: XorCipher)
+    [ testBlockCipher defaultKATs cipher
+    , testBlockCipherIO defaultKATs cipher
+    , testStreamCipher defaultStreamKATs cipher
     ]
+  where cipher :: XorCipher
+        cipher = undefined
 
 main = defaultMain tests
