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.1.0
+Version: 0.2.0
 License: BSD3
 License-file: COPYING
 Copyright: Copyright (c) 2009 University of Tromsø
@@ -18,15 +18,16 @@
 
 Library
   Build-Depends:
-        base >= 3 && < 5 , bytestring, monads-tf >= 0.0.0.1 && < 0.1, transformers >= 0.1.4.0 && < 0.2
+        base >= 4 && < 5 , bytestring, monads-tf >= 0.0.0.1 && < 0.1, transformers >= 0.1.4.0 && < 0.2
   Extensions:
         ForeignFunctionInterface,
         ViewPatterns,
         Rank2Types,
         EmptyDataDecls
   Exposed-Modules:
+        Control.Monad.UnsafeIO,
         Codec.Crypto.AES,
-        Codec.Crypto.AES.ST,
+        Codec.Crypto.AES.Monad,
         Codec.Crypto.AES.IO
 
   ghc-options: -Wall
diff --git a/Codec/Crypto/AES.hs b/Codec/Crypto/AES.hs
--- a/Codec/Crypto/AES.hs
+++ b/Codec/Crypto/AES.hs
@@ -3,8 +3,8 @@
   Mode(..), Direction(..), crypt, crypt'
   ) where
 
-import qualified Codec.Crypto.AES.ST as AES
-import Codec.Crypto.AES.ST(Mode(..), Direction(..))
+import qualified Codec.Crypto.AES.Monad as AES
+import Codec.Crypto.AES.Monad(Mode(..), Direction(..))
 import qualified Data.ByteString as B
 import qualified Data.ByteString.Lazy as BL
 
@@ -15,7 +15,7 @@
         -> Direction 
         -> BL.ByteString -- ^ Bytestring to encrypt/decrypt
         -> BL.ByteString
-crypt mode key iv dir bs = AES.execAES mode key iv dir (AES.crypt bs)
+crypt mode key iv dir bs = snd $ AES.runAES mode key iv dir (AES.crypt bs)
 
 -- | Encryption/decryption for strict bytestrings
 crypt' :: Mode
@@ -24,4 +24,4 @@
          -> Direction 
          -> B.ByteString -- ^ Bytestring to encrypt/decrypt
          -> B.ByteString
-crypt' mode key iv dir bs = B.concat $ BL.toChunks $ AES.execAES mode key iv dir (AES.crypt bs)
+crypt' mode key iv dir bs = B.concat $ BL.toChunks $ snd $ AES.runAES mode key iv dir (AES.crypt bs)
diff --git a/Codec/Crypto/AES/Monad.hs b/Codec/Crypto/AES/Monad.hs
new file mode 100644
--- /dev/null
+++ b/Codec/Crypto/AES/Monad.hs
@@ -0,0 +1,56 @@
+-- | An occasionally pure, monadic interface to AES
+module Codec.Crypto.AES.Monad(
+  AES, Mode(..), Direction(..), Cryptable(..), runAEST, runAES
+  ) where
+
+import qualified Codec.Crypto.AES.IO as AES
+import Codec.Crypto.AES.IO(Mode(..), Direction(..), newCtx, AESCtx)
+import Control.Applicative
+import Control.Monad.ST.Lazy
+import Control.Monad.Reader
+import Control.Monad.Writer
+import Control.Monad.UnsafeIO
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Lazy as BL
+
+type AEST m a = ReaderT AESCtx (WriterT BL.ByteString m) a
+
+type AES s a = AEST (ST s) a
+
+-- | Run an AES computation
+runAEST :: MonadUnsafeIO m =>
+          Mode
+          -> B.ByteString -- ^ The AES key - 16, 24 or 32 bytes
+          -> B.ByteString -- ^ The IV, 16 bytes
+          -> Direction
+          -> AEST m a
+          -> m (a, BL.ByteString)
+runAEST mode key iv dir aes = do
+  ctx <- liftUnsafeIO $ newCtx mode key iv dir
+  runWriterT $ runReaderT aes ctx
+
+-- | Run an AES computation
+runAES ::  Mode
+          -> B.ByteString -- ^ The AES key - 16, 24 or 32 bytes
+          -> B.ByteString -- ^ The IV, 16 bytes
+          -> Direction
+          -> (forall s. AES s a)
+          -> (a, BL.ByteString)
+runAES mode key iv dir aes = runST $ runAEST mode key iv dir aes
+
+-- | A class of things that can be crypted
+--
+-- The crypt function returns incremental results as well as
+-- appending them to the result bytestring.
+class Cryptable a where
+  crypt :: a -> AES s a
+
+instance Cryptable B.ByteString where
+  crypt bs = do
+    ctx <- ask
+    crypted <- liftUnsafeIO $ AES.crypt ctx bs
+    tell $ BL.fromChunks [crypted]
+    return crypted
+
+instance Cryptable BL.ByteString where
+  crypt (BL.toChunks -> chunks) = snd <$> listen (mapM_ crypt chunks)
diff --git a/Codec/Crypto/AES/ST.hs b/Codec/Crypto/AES/ST.hs
deleted file mode 100644
--- a/Codec/Crypto/AES/ST.hs
+++ /dev/null
@@ -1,57 +0,0 @@
--- | A pure interface to AES, in the lazy ST monad.
-module Codec.Crypto.AES.ST(
-  AES, Mode(..), Direction(..), Cryptable(..), execAES, runAES, liftST
-  ) where
-
-import qualified Codec.Crypto.AES.IO as AES
-import Codec.Crypto.AES.IO(Mode(..), Direction(..), newCtx, AESCtx)
-import Control.Applicative
-import Control.Monad.ST.Lazy
-import Control.Monad.Reader
-import Control.Monad.Writer
-import qualified Data.ByteString as B
-import qualified Data.ByteString.Lazy as BL
-
-type AES s a = ReaderT AESCtx (WriterT BL.ByteString (ST s)) a
-
--- | Before you use this, recall that AES uses the lazy ST monad.
-liftST :: ST s a -> AES s a
-liftST = lift . lift
-
--- | Compute an AES computation, returning the ST return value along
--- with the crypted data
-runAES :: Mode
-         -> B.ByteString -- ^ The AES key - 16, 24 or 32 bytes
-         -> B.ByteString -- ^ The IV, 16 bytes
-         -> Direction
-         -> (forall s. AES s a)
-         -> (a, BL.ByteString)
-runAES mode key iv dir aes = runST $ do
-  ctx <- unsafeIOToST $ newCtx mode key iv dir
-  runWriterT $ runReaderT aes ctx
-
--- | Compute an AES computation, discarding the ST return value
-execAES :: Mode
-          -> B.ByteString -- ^ The AES key - 16, 24 or 32 bytes
-          -> B.ByteString -- ^ The IV, 16 bytes
-          -> Direction
-          -> (forall s. AES s a)
-          -> BL.ByteString
-execAES mode key iv dir aes = snd $ runAES mode key iv dir aes
-
--- | A class of things that can be crypted
---
--- The crypt function returns incremental results as well as
--- appending them to the result bytestring.
-class Cryptable a where
-  crypt :: a -> AES s a
-
-instance Cryptable B.ByteString where
-  crypt bs = do
-    ctx <- ask
-    crypted <- liftST $ unsafeIOToST $ AES.crypt ctx bs
-    tell $ BL.fromChunks [crypted]
-    return crypted
-
-instance Cryptable BL.ByteString where
-  crypt (BL.toChunks -> chunks) = snd <$> listen (mapM_ crypt chunks)
diff --git a/Control/Monad/UnsafeIO.hs b/Control/Monad/UnsafeIO.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/UnsafeIO.hs
@@ -0,0 +1,23 @@
+-- | Just like MonadIO, but codifying /unsafe/ IO execution. Exists for safety.
+module Control.Monad.UnsafeIO where
+
+import qualified Control.Monad.ST as S
+import qualified Control.Monad.ST.Lazy as L
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.Writer
+import Control.Monad.Trans
+import Data.Monoid
+
+class Monad m => MonadUnsafeIO m where
+  liftUnsafeIO :: IO a -> m a
+
+instance MonadUnsafeIO IO where
+  liftUnsafeIO = id
+instance MonadUnsafeIO (S.ST s) where
+  liftUnsafeIO = S.unsafeIOToST
+instance MonadUnsafeIO (L.ST s) where
+  liftUnsafeIO = L.unsafeIOToST
+instance MonadUnsafeIO m => MonadUnsafeIO (ReaderT r m) where
+  liftUnsafeIO = lift . liftUnsafeIO
+instance (Monoid w, MonadUnsafeIO m) => MonadUnsafeIO (WriterT w m) where
+  liftUnsafeIO = lift . liftUnsafeIO
