diff --git a/changes.md b/changes.md
--- a/changes.md
+++ b/changes.md
@@ -1,3 +1,7 @@
+# 0.1.0
+    - Switch to using 'MonadThrow' instead of 'MonadError'
+    - Introduce 'readKeyFile'
+
 # 0.0.0
 
 First published version
diff --git a/cryptoids.cabal b/cryptoids.cabal
--- a/cryptoids.cabal
+++ b/cryptoids.cabal
@@ -1,5 +1,5 @@
 name: cryptoids
-version: 0.0.0
+version: 0.1.0
 cabal-version: >=1.10
 build-type: Simple
 license: BSD3
@@ -26,7 +26,9 @@
         bytestring >=0.10.8.1 && <0.11,
         binary >=0.8.3.0 && <0.9,
         memory >=0.14.6 && <0.15,
-        mtl >=2.2.1 && <2.3
+        exceptions >=0.8.3 && <0.9,
+        filepath >=1.4.1.1 && <1.5,
+        directory >=1.3.0.0 && <1.4
     default-language: Haskell2010
     default-extensions: RankNTypes DataKinds GeneralizedNewtypeDeriving
                         ViewPatterns RecordWildCards FlexibleContexts
diff --git a/src/Data/CryptoID/Poly.hs b/src/Data/CryptoID/Poly.hs
--- a/src/Data/CryptoID/Poly.hs
+++ b/src/Data/CryptoID/Poly.hs
@@ -16,7 +16,7 @@
 module Data.CryptoID.Poly
   ( CryptoID(..)
   , CryptoIDKey
-  , genKey
+  , genKey, readKeyFile
   , encrypt
   , decrypt
   , CryptoIDError(..)
@@ -42,8 +42,10 @@
 import qualified Data.ByteArray as ByteArray
 
 import Data.Foldable (asum)
-import Control.Monad.Except
+import Control.Monad.Catch (MonadThrow(..))
+import Control.Monad.IO.Class
 import Control.Exception
+import System.IO.Error
 
 import Data.Typeable
 import GHC.TypeLits
@@ -56,7 +58,10 @@
 
 import Crypto.Random.Entropy
 
+import System.Directory
+import System.FilePath
 
+
 -- | The symmetric cipher 'BlockCipher' this module uses 
 type CryptoCipher = Blowfish
 -- | The cryptographic 'HashAlgorithm' this module uses
@@ -92,7 +97,7 @@
       -- that parses)
       getKey (KeySizeFixed n) = getByteString n
       getKey (KeySizeEnum ns) = asum [ getKey $ KeySizeFixed n | n <- sortOn Down ns ]
-      getKey (KeySizeRange min max) = getKey $ KeySizeEnum [max .. min]
+      getKey (KeySizeRange min max) = getKey $ KeySizeEnum [min .. max]
 
 
 -- | Error cases that can be encountered during 'encrypt' and 'decrypt'
@@ -140,6 +145,21 @@
       | KeySizeFixed n <- keySize' = n
       | KeySizeEnum ns <- keySize' = maximum ns
       | KeySizeRange _ max <- keySize' = max
+
+-- | Try to read a 'CryptoIDKey' from a file.
+--   If the file does not exist, securely generate a key (using 'genKey') and
+--   save it to the file. 
+readKeyFile :: MonadIO m => FilePath -> m CryptoIDKey
+readKeyFile keyFile = liftIO $ decodeFile keyFile `catch` generateInstead
+  where
+    generateInstead e
+      | isDoesNotExistError e = do
+          createDirectoryIfMissing True $ takeDirectory keyFile
+          key <- genKey
+          encodeFile keyFile key
+          return key
+      | otherwise = throw e
+
   
   
 -- | @pad err size src@ appends null bytes to @src@ until it has length that is
@@ -151,23 +171,23 @@
 
 -- | Use 'CryptoHash' to generate a 'Digest' of the Symbol passed as proxy type
 namespace' :: forall proxy namespace m.
-              ( KnownSymbol namespace, MonadError CryptoIDError m
+              ( KnownSymbol namespace, MonadThrow m
               ) => proxy namespace -> m (IV CryptoCipher)
 namespace' p = case makeIV namespaceHash of
-                 Nothing -> throwError . NamespaceHashIsWrongLength $ ByteArray.convert namespaceHash
+                 Nothing -> throwM . NamespaceHashIsWrongLength $ ByteArray.convert namespaceHash
                  Just iv -> return iv
   where
     namespaceHash :: Digest CryptoHash
     namespaceHash = hash . ByteString.Char.pack $ symbolVal p
 
 -- | Wrap failure of one of the cryptographic algorithms as a 'CryptoIDError'
-cryptoFailable :: MonadError CryptoIDError m => CryptoFailable a -> m a
-cryptoFailable = either (throwError . AlgorithmError) return . eitherCryptoError
+cryptoFailable :: MonadThrow m => CryptoFailable a -> m a
+cryptoFailable = either (throwM . AlgorithmError) return . eitherCryptoError
 
 -- | Encrypt an arbitrary serializable value
 encrypt :: forall m namespace.
            ( KnownSymbol namespace
-           , MonadError CryptoIDError m
+           , MonadThrow m
            ) => CryptoIDKey -> ByteString -> m (CryptoID namespace ByteString)
 encrypt (keyMaterial -> key) plaintext = do
   cipher <- cryptoFailable (cipherInit key :: CryptoFailable CryptoCipher)
@@ -178,7 +198,7 @@
 -- | Decrypt an arbitrary serializable value
 decrypt :: forall m namespace.
            ( KnownSymbol namespace
-           , MonadError CryptoIDError m
+           , MonadThrow m
            ) => CryptoIDKey -> CryptoID namespace ByteString -> m ByteString
 decrypt (keyMaterial -> key) CryptoID{..} = do
   cipher <- cryptoFailable (cipherInit key :: CryptoFailable CryptoCipher)
