diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Oz Haskell Implementation
 
-[![Build Status](https://travis-ci.org/rvl/hsoz.svg?branch=master)](https://travis-ci.org/rvl/hsoz) [![Hackage](https://img.shields.io/hackage/v/hsoz.svg)]()
+[![Build Status](https://travis-ci.org/rvl/hsoz.svg?branch=master)](https://travis-ci.org/rvl/hsoz) [![Hackage](https://img.shields.io/hackage/v/hsoz.svg)](http://hackage.haskell.org/package/hsoz)
 
 *hsoz* is a Haskell implementation of the Iron, Hawk, and Oz web
 authentication protocols. These protocols originate from the OAuth2
diff --git a/example/HawkClient.hs b/example/HawkClient.hs
--- a/example/HawkClient.hs
+++ b/example/HawkClient.hs
@@ -11,7 +11,8 @@
 import qualified Data.Map                  as M
 import qualified Data.Text                 as T
 import           Data.Text.Encoding        (decodeUtf8, encodeUtf8)
-import           Network.HTTP.Client       (HttpException (..))
+import           Network.HTTP.Client       (HttpException(..), HttpExceptionContent(..))
+import           Network.HTTP.Client       (responseStatus, responseHeaders)
 import           Network.HTTP.Types.Header (ResponseHeaders, hAuthorization, hWWWAuthenticate)
 import           Network.HTTP.Types.Status (Status(..))
 import           Network.HTTP.Simple
@@ -47,12 +48,18 @@
   where
     withHawk = Hawk.withHawk creds ext (Just payload) Hawk.ServerAuthorizationRequired
     handlers = [E.Handler handleHTTP, E.Handler handleHawk]
-    handleHTTP e@(StatusCodeException s hdrs _)
-      | statusCode s == 401 = S8.putStrLn $ errMessage s hdrs
-      | otherwise           = throwIO e
+    handleHTTP e@(HttpExceptionRequest _ (StatusCodeException res _))
+      | unauthorized res = S8.putStrLn $ errMessage res
+      | otherwise        = throwIO e
+      where code = statusCode (responseStatus res)
     handleHawk (Hawk.HawkServerAuthorizationException e)
       = putStrLn $ "Invalid server response: " ++ e
 
-errMessage :: Status -> ResponseHeaders -> ByteString
-errMessage s hdrs = statusMessage s <> maybe "" (": " <>) authHdr
-  where authHdr = lookup hWWWAuthenticate hdrs
+unauthorized :: Response a -> Bool
+unauthorized = (== 401) . statusCode . responseStatus
+
+errMessage :: Response a -> ByteString
+errMessage res = statusMessage s <> maybe "" (": " <>) authHdr
+  where
+    authHdr = lookup hWWWAuthenticate $ responseHeaders res
+    s = responseStatus res
diff --git a/example/Iron.hs b/example/Iron.hs
--- a/example/Iron.hs
+++ b/example/Iron.hs
@@ -1,6 +1,8 @@
 import Options.Applicative
+import Data.Monoid ((<>))
+import Data.Bifunctor (bimap)
 import Control.Monad (join, unless)
-import           Data.Time.Clock        (NominalDiffTime)
+import Data.Time.Clock (NominalDiffTime)
 import Text.Read (readEither)
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Lazy.Char8 as L8
@@ -67,6 +69,18 @@
             <> help "Encryption algorithm: AES128CTR or AES256CBC (default)"
             <> value AES256CBC
             )
+      <*> option auto
+            ( long "salt-bits"
+            <> metavar "INTEGER"
+            <> help "Number of salt bits for key generation."
+            <> value 256
+            )
+      <*> option auto
+            ( long "iterations"
+            <> metavar "INTEGER"
+            <> help "Number of iterations of key derivation function."
+            <> value 100000
+            )
 
 ttl :: ReadM NominalDiffTime
 ttl = eitherReader (fmap fromInteger . readEither)
@@ -74,12 +88,11 @@
 data Action = Seal | Unseal
 data Format = JSONFormat | StringFormat
 
-iron :: Either String String -> Maybe Action -> Format -> NominalDiffTime -> IronCipher -> IO ()
-iron p a j ttl c = do
+iron :: Either String String -> Maybe Action -> Format -> NominalDiffTime
+     -> IronCipher -> Int -> Int -> IO ()
+iron p a j ttl c s i = do
   p' <- password <$> readPassword p
-  let opts = def { ironEncryption = def { ieAlgorithm = c }
-                 , ironTTL = ttl
-                 }
+  let opts = (options c SHA256 s i) { ironTTL = ttl }
   L8.hGetContents stdin >>= mapM_ (processLine opts p' a j) . L8.lines
 
 readPassword :: Either FilePath String -> IO ByteString
@@ -115,23 +128,13 @@
 
 conv :: Format -> L8.ByteString -> Either String Value
 conv JSONFormat   = eitherDecode'
-conv StringFormat = mapEither show (String . TL.toStrict) . decodeUtf8'
+conv StringFormat = bimap show (String . TL.toStrict) . decodeUtf8'
 
 doSeal :: ToJSON a => Options -> Password -> a -> IO (Either String ByteString)
-doSeal o p a = justRight "Failed to seal" <$> sealWith o p a
+doSeal o p a = justRight "Failed to seal" <$> seal o p a
 
 doUnseal :: FromJSON a => Options -> Password -> L8.ByteString -> IO (Either String a)
-doUnseal o p s = unsealWith o (const (Just p)) (L8.toStrict s)
-
-
--- | Modifies the left branch of an 'Either'.
-mapLeft :: (a -> a') -> Either a b -> Either a' b
-mapLeft f (Left a) = Left (f a)
-mapLeft _ (Right b) = Right b
-
--- | Modifies both branches of an 'Either'.
-mapEither :: (a -> a') -> (b -> b') -> Either a b -> Either a' b'
-mapEither f g = mapLeft f . fmap g
+doUnseal o p s = unseal o (const (Just p)) (L8.toStrict s)
 
 -- | Converts 'Maybe' to 'Either'.
 justRight :: e -> Maybe a -> Either e a
diff --git a/example/OzServer.hs b/example/OzServer.hs
--- a/example/OzServer.hs
+++ b/example/OzServer.hs
@@ -126,8 +126,10 @@
                  otherwise -> False
 
 openTicket :: S8.ByteString -> IO (Either String OzTicket)
-openTicket = Iron.unseal (password sharedKey)
-  where password (Hawk.Key p) = Iron.onePassword p
+openTicket = Iron.unseal opts (password sharedKey)
+  where
+    opts = ticketOptsIron defaultTicketOpts
+    password (Hawk.Key p) = Iron.onePassword p
 
 -- | Example apps registry
 apps = [OzApp "app123" Nothing False sharedKey (Hawk.HawkAlgo Hawk.SHA256)]
diff --git a/hsoz.cabal b/hsoz.cabal
--- a/hsoz.cabal
+++ b/hsoz.cabal
@@ -1,5 +1,5 @@
 name:                hsoz
-version:             0.0.0.4
+version:             0.0.1.0
 synopsis:            Iron, Hawk, Oz: Web auth protocols
 description:
   hsoz is a Haskell implementation of the Iron, Hawk, and Oz web
@@ -25,8 +25,12 @@
 cabal-version:       >=1.10
 stability:           experimental
 bug-reports:         https://github.com/rvl/hsoz/issues
-Tested-With:         GHC == 8.0.1
+Tested-With:         GHC == 8.0.2
 
+source-repository head
+  type:     git
+  location: https://github.com/rvl/hsoz
+
 flag example
   description: Build the example applications
   default: True
@@ -34,6 +38,7 @@
 library
   hs-source-dirs:      src
   exposed-modules:     Network.Iron
+                     , Network.Iron.Util
                      , Network.Hawk
                      , Network.Hawk.Client
                      , Network.Hawk.Middleware
@@ -55,45 +60,40 @@
                      , Network.Oz.Server
                      , Network.Oz.Ticket
                      , Network.Oz.Types
-  other-modules:       Network.Iron.Util
-                     , Network.Hawk.Algo
+  other-modules:       Network.Hawk.Algo
                      , Network.Hawk.Util
                      , Network.Hawk.Internal.JSON
                      , Network.Oz.JSON
                      , Network.Oz.Internal.Types
                      , Network.Oz.Boom
   build-depends:       base >= 4.7 && < 5
-                     , aeson
-                     , attoparsec
-                     , base16-bytestring
-                     , base64-bytestring
-                     , byteable
-                     , bytestring
-                     , case-insensitive
-                     , containers
-                     , cryptonite
-                     , data-default
-                     , either
-                     , errors
-                     , exceptions
-                     , hashable
-                     , http-client >= 0.4 && < 0.5
-                     , http-types
-                     , lens
-                     , memory
-                     , mtl
-                     , network
-                     , scientific
-                     , scotty
-                     , securemem
-                     , text
-                     , time
-                     , transformers
-                     , unordered-containers
-                     , uri-bytestring
-                     , vault
-                     , wai
-                     , warp
+                     , aeson                >= 1.0.2  && < 1.1
+                     , attoparsec           >= 0.13.1 && < 0.14
+                     , bytestring           >= 0.10.8 && < 0.11
+                     , case-insensitive     >= 1.2.0  && < 1.3
+                     , containers           >= 0.5.7  && < 0.6
+                     , cryptonite           >= 0.21   && < 0.22
+                     , data-default         >= 0.7.1  && < 0.8
+                     , either               >= 4.4.1  && < 4.5
+                     , errors               >= 2.1.3  && < 2.2
+                     , exceptions           >= 0.8.3  && < 0.9
+                     , hashable             >= 1.2.5  && < 1.3
+                     , http-client          >= 0.5.5  && < 0.6
+                     , http-types           >= 0.9.1  && < 0.10
+                     , lens                 >= 4.15.1 && < 4.16
+                     , memory               >= 0.14.1 && < 0.15
+                     , mtl                  >= 2.2.1  && < 2.3
+                     , network              >= 2.6.3  && < 2.7
+                     , scientific           >= 0.3.4  && < 0.4
+                     , scotty               >= 0.11.0 && < 0.12
+                     , text                 >= 1.2.2  && < 1.3
+                     , time                 >= 1.6.0  && < 1.7
+                     , transformers         >= 0.5.2  && < 0.6
+                     , unordered-containers >= 0.2.7  && < 0.3
+                     , uri-bytestring       >= 0.2.2  && < 0.3
+                     , vault                >= 0.3.0  && < 0.4
+                     , wai                  >= 3.2.1  && < 3.3
+                     , warp                 >= 3.2.11 && < 3.3
   default-language:    Haskell2010
   default-extensions:  OverloadedStrings
 
@@ -121,8 +121,8 @@
                      , containers
                      , cryptonite
                      , data-default
-                     , http-client >= 0.4 && < 0.5
-                     , http-conduit >= 2.1 && < 2.2
+                     , http-client >= 0.5 && < 0.6
+                     , http-conduit >= 2.2 && < 2.3
                      , http-types
                      , lens
                      , lucid
@@ -151,7 +151,7 @@
                      , containers
                      , cryptonite
                      , data-default
-                     , optparse-applicative
+                     , optparse-applicative >= 0.12
                      , text
                      , time
   default-language:    Haskell2010
@@ -183,7 +183,3 @@
   ghc-options:         -threaded -rtsopts -with-rtsopts=-N
   default-language:    Haskell2010
   default-extensions:  OverloadedStrings
-
-source-repository head
-  type:     git
-  location: https://github.com/rvl/hsoz
diff --git a/src/Network/Hawk/Internal.hs b/src/Network/Hawk/Internal.hs
--- a/src/Network/Hawk/Internal.hs
+++ b/src/Network/Hawk/Internal.hs
@@ -28,7 +28,7 @@
 import qualified Data.ByteString.Char8     as S8
 import qualified Data.ByteString.Lazy      as BL
 import           Data.Text.Encoding        (encodeUtf8)
-import           Data.Byteable             (constEqBytes)
+import           Data.ByteArray            (constEq)
 import           Data.Char                 (toLower, toUpper)
 import           Data.List                 (intercalate)
 import           Data.Monoid               ((<>))
@@ -66,7 +66,7 @@
 checkPayload :: HawkAlgoCls a => Maybe ByteString -> a -> ContentType -> BL.ByteString -> Either String ()
 checkPayload (Just hash) algo ct payload = if good then Right () else Left "Bad payload hash"
   where
-    good = hash `constEqBytes` (calculatePayloadHash algo payloadInfo)
+    good = hash `constEq` (calculatePayloadHash algo payloadInfo)
     payloadInfo = PayloadInfo ct payload
 checkPayload Nothing algo ct payload = Left "Missing required payload hash"
 
diff --git a/src/Network/Hawk/Internal/Client.hs b/src/Network/Hawk/Internal/Client.hs
--- a/src/Network/Hawk/Internal/Client.hs
+++ b/src/Network/Hawk/Internal/Client.hs
@@ -16,10 +16,9 @@
 import qualified Data.ByteArray            as BA (unpack)
 import           Data.ByteString           (ByteString)
 import qualified Data.ByteString           as BS
-import qualified Data.ByteString.Base64    as B64
 import qualified Data.ByteString.Char8     as S8
 import qualified Data.ByteString.Lazy      as BL
-import           Data.Byteable             (constEqBytes)
+import           Data.ByteArray            (constEq)
 import           Data.CaseInsensitive      (CI (..))
 import qualified Data.Map                  as M
 import           Data.Maybe                (catMaybes, fromMaybe)
@@ -32,9 +31,9 @@
 import           Network.HTTP.Types.Method (Method)
 import           Network.HTTP.Types.Status (Status, statusCode)
 import           Network.HTTP.Types.URI    (extractPath)
-import           Network.HTTP.Client       (Response, responseHeaders)
+import           Network.HTTP.Client       (Response, responseHeaders, responseStatus)
 import           Network.HTTP.Client       (Request, requestHeaders, requestBody, getUri, method, secure)
-import           Network.HTTP.Client       (HttpException(..))
+import           Network.HTTP.Client       (HttpException(..), HttpExceptionContent(..))
 import           URI.ByteString            (authorityHost, authorityPort,
                                             hostBS, laxURIParserOptions,
                                             parseURI, portNumber, uriAuthority,
@@ -254,7 +253,7 @@
       where tsm = calculateTsMac (ccAlgorithm creds) <$> wahTs h
 
     tsmEq :: Maybe ByteString -> Maybe ByteString -> Bool
-    tsmEq (Just a) (Just b) = a `constEqBytes` b
+    tsmEq (Just a) (Just b) = a `constEq` b
     tsmEq (Just _) Nothing  = False
     tsmEq _        _        = True
 
@@ -266,7 +265,7 @@
 checkServerAuthorizationHeader _ _ ServerAuthorizationRequired _ Nothing = Left "Missing Server-Authorization header"
 checkServerAuthorizationHeader creds arts _ now (Just sa) =
   parseServerAuthorizationHeader sa >>= check
-  where check sah | sahMac sah `constEqBytes` mac = Right (Just sah)
+  where check sah | sahMac sah `constEq` mac = Right (Just sah)
                   | otherwise = Left "Bad response mac"
           where
             arts' = responseArtifacts sah arts
@@ -380,8 +379,8 @@
                   -> m a -> m (Either NominalDiffTime a)
 makeExpiryHandler creds req = E.handle handler . fmap Right
   where
-    handler e@(StatusCodeException s h _) =
-      case wasStale req creds h s of
+    handler e@(HttpExceptionRequest req (StatusCodeException res _)) =
+      case wasStale req res creds of
         Just ts -> return $ Left ts
         Nothing -> throwM e
 
@@ -411,10 +410,12 @@
       liftIO $ authenticate resp creds arts body ck
     ServerAuthorizationNotRequired -> return (Right Nothing)
 
-wasStale :: Request -> Credentials -> ResponseHeaders -> Status -> Maybe NominalDiffTime
-wasStale req creds hdrs s
-  | secure req && statusCode s == 401 = hawkTs creds hdrs
-  | otherwise                         = Nothing
+wasStale :: Request -> Response () -> Credentials -> Maybe NominalDiffTime
+wasStale req res creds | secure req && unauthorized = serverTs
+                       | otherwise                  = Nothing
+  where
+    unauthorized = statusCode (responseStatus res) == 401
+    serverTs = hawkTs creds (responseHeaders res)
 
 -- | Gets the WWW-Authenticate header value and returns the server
 -- timestamp, if the response contains an authenticated timestamp.
diff --git a/src/Network/Hawk/Server.hs b/src/Network/Hawk/Server.hs
--- a/src/Network/Hawk/Server.hs
+++ b/src/Network/Hawk/Server.hs
@@ -43,7 +43,7 @@
 import qualified Data.ByteString           as BS
 import qualified Data.ByteString.Char8     as S8
 import qualified Data.ByteString.Lazy      as BL
-import           Data.Byteable             (constEqBytes)
+import           Data.ByteArray            (constEq)
 import           Data.CaseInsensitive      (CI (..))
 import           Data.Maybe                (fromMaybe)
 import           Data.Monoid               ((<>))
@@ -51,6 +51,7 @@
 import qualified Data.Text                 as T
 import           Data.Text.Encoding        (decodeUtf8, decodeUtf8')
 import           Control.Error.Safe        (rightMay)
+import           Data.Bifunctor            (first)
 import           Data.Default              (Default(..))
 import           Data.Time.Clock           (NominalDiffTime)
 import           Data.Time.Clock.POSIX
@@ -68,7 +69,7 @@
 import           Network.Hawk.Internal.Server.Types
 import           Network.Hawk.Internal.Server.Header
 import           Network.Hawk.Util
-import           Network.Iron.Util         (b64urldec, justRight, mapLeft)
+import           Network.Iron.Util         (b64urldec, justRight)
 
 -- | Bundle of parameters for 'authenticateRequest'. Provides
 -- information about what the public URL of the server would be. If
@@ -119,7 +120,7 @@
     else authenticate (saOpts opts) creds hreq
 
 authenticateBewit' (creds, t) req bewit
-  | mac `constEqBytes` (bewitMac bewit) = Right (AuthSuccess creds arts t)
+  | mac `constEq` (bewitMac bewit) = Right (AuthSuccess creds arts t)
   | otherwise = Left (AuthFailUnauthorized "Bad mac" (Just creds) (Just arts))
   where
     arts = bewitArtifacts req bewit
@@ -146,7 +147,7 @@
   now <- getServerTime opts
   case checkBewit hrq now of
     Right bewit -> do
-      mcreds <- mapLeft unauthorized <$> getCreds (bewitId bewit)
+      mcreds <- first unauthorized <$> getCreds (bewitId bewit)
       return $ case mcreds of
         Right creds -> authenticateBewit' creds hrq bewit
         Left e -> undefined
@@ -159,7 +160,7 @@
       checkLength hrqUrl
       encBewit <- checkEmpty hrqBewit
       checkHeader hrqAuthorization
-      bewit <- mapLeft unauthorized $ decodeBewit encBewit
+      bewit <- first unauthorized $ decodeBewit encBewit
       checkAttrs bewit
       checkExpiry bewit now
       return bewit
@@ -294,7 +295,7 @@
   let doCheck = authResult creds arts t
       doCheckExp = authResultExp now creds arts t
       mac = serverMac creds ty arts
-  if mac `constEqBytes` sahMac then do
+  if mac `constEq` sahMac then do
     doCheck $ checkPayloadHash (scAlgorithm creds) sahHash payload
     doCheck $ checkNonce nonce
     doCheckExp $ checkExpiration now (saTimestampSkew opts) sahTs
@@ -399,7 +400,7 @@
     bewit' (id, exp, mac, ext) = Bewit <$> decodeId id
                                  <*> readTsMaybe exp
                                  <*> pure mac <*> pure ext
-    fixMsg = mapLeft (const "Invalid bewit encoding")
+    fixMsg = first (const "Invalid bewit encoding")
     decodeId = rightMay . decodeUtf8'
 
 ----------------------------------------------------------------------------
diff --git a/src/Network/Iron.hs b/src/Network/Iron.hs
--- a/src/Network/Iron.hs
+++ b/src/Network/Iron.hs
@@ -23,9 +23,10 @@
 -- >>> import Data.ByteString (ByteString)
 -- >>> import Data.Aeson
 -- >>> import qualified Network.Iron as Iron
+-- >>> let opts = Iron.options Iron.AES256CBC Iron.SHA256 256 66666
 -- >>> let Just obj = decode "{\"a\":1,\"d\":{\"e\":\"f\"},\"b\":2,\"c\":[3,4,5]}" :: Maybe Object
 -- >>> let secret = "some_not_random_password" :: ByteString
--- >>> s <- Iron.seal (Iron.password secret) obj
+-- >>> Just s <- Iron.seal opts (Iron.password secret) obj
 -- >>> print s
 -- "Fe26.2**3976da2bc627b3551c1ebfe40376bb791efb17f4425facc648038fdaaa2f67b2
 -- *voiPExJrXAxmTWyQr7-Hvw*r_Ok7NOgy9sD2fS61t_u9z8qoszwBRze3NnA6PFmjnd06sLh0
@@ -37,7 +38,7 @@
 --
 -- To unseal the string:
 --
--- >>> Iron.unseal (onePassword secret) s :: IO (Either String Object)
+-- >>> Iron.unseal opts (onePassword secret) s :: IO (Either String Object)
 -- Right (Object (fromList [("a",Number 1.0),
 -- ("d",Object (fromList [("e",String "f")])),
 -- ("b",Number 2.0),
@@ -45,9 +46,8 @@
 
 module Network.Iron
   ( seal
-  , sealWith
   , unseal
-  , unsealWith
+  , options
   , password
   , passwords
   , passwordWithId
@@ -60,11 +60,8 @@
   , EncryptionOpts(..)
   , IntegrityOpts(..)
   , IronCipher(..)
-  , IronMAC(..)
-  , SHA256(SHA256)
-  , IronSalt(..)
-  , urlSafeBase64
-  , def
+  , IronHMAC(..)
+  , Salt(..)
   ) where
 
 import           Control.Monad          (liftM, when)
@@ -72,8 +69,8 @@
 import           Crypto.Cipher.Types
 import           Crypto.Data.Padding
 import           Crypto.Error           (CryptoFailable (..), maybeCryptoError)
-import           Crypto.Hash.Algorithms (SHA256 (..))
-import           Crypto.Hash.Algorithms (SHA1 (..))
+import qualified Crypto.Hash.Algorithms as C (SHA256 (..))
+import           Crypto.Hash.Algorithms (HashAlgorithm(..), SHA1 (..))
 import qualified Crypto.KDF.PBKDF2      as PBKDF2
 import           Crypto.MAC.HMAC        (Context, HMAC, finalize, hmac,
                                          hmacGetDigest, initialize, updates)
@@ -82,15 +79,13 @@
 import qualified Data.Aeson             as JSON (eitherDecode', encode)
 import           Data.ByteString        (ByteString)
 import qualified Data.ByteString        as BS
-import qualified Data.ByteString.Base16 as B16
 import qualified Data.ByteString.Char8  as S8
 import qualified Data.ByteString.Lazy   as BL
-import           Data.SecureMem         (SecureMem(..), ToSecureMem(..))
-import           Data.Byteable          (Byteable(..), constEqBytes)
+import qualified Data.ByteArray         as BA
+import           Data.ByteArray         (ScrubbedBytes, ByteArrayAccess)
 import qualified Data.Map               as M
 import           Data.Maybe             (fromJust)
 import           Data.Monoid            ((<>))
-import           Data.Default           (Default(..))
 import           Data.Text              (Text)
 import           Data.Text.Encoding     (decodeUtf8, encodeUtf8)
 import           Data.Char              (isAscii, isAlphaNum)
@@ -99,14 +94,7 @@
 import           Network.Iron.Util
 import           Numeric                (showHex)
 
--- | Iron options used by 'sealWith' and 'unsealWith'. The
--- default options are:
---
--- * Encryption: 'Crypto.Cipher.AES.AES256' using CBC mode
--- * Integrity HMAC: 'Crypto.Hash.Algorithms.SHA256'
--- * Infinite message lifetime
--- * Timestamp skew: 60 seconds either way
--- * Local time offset: 0
+-- | Iron options used by 'sealWith' and 'unsealWith'.
 data Options = Options
   { ironEncryption      :: EncryptionOpts  -- ^ Encryption options
   , ironIntegrity       :: IntegrityOpts   -- ^ Message integrity verification options
@@ -117,6 +105,7 @@
 
 -- | Encryption algorithms supported by Iron.
 data IronCipher = AES128CTR | AES256CBC  deriving (Show, Read, Eq, Enum)
+data IronHMAC = SHA256 deriving (Show, Read, Eq, Enum)
 
 class IsIronCipher a where
   ivSize :: a -> Int
@@ -128,20 +117,13 @@
   macKeySize :: a -> Int
   ironMac :: a -> ByteString -> ByteString -> ByteString
 
--- | Integrity checking algorithm supported by Iron. At present, there
--- is only one. Use @IronMAC SHA256@.
-data IronMAC = forall alg . (IsIronMAC alg, Show alg) => IronMAC alg
-
-instance Show IronMAC where
-  show (IronMAC alg) = show alg
-
-instance IsIronMAC IronMAC where
-  macKeySize (IronMAC alg) = macKeySize alg
-  ironMac (IronMAC alg) = ironMac alg
+instance IsIronMAC IronHMAC where
+  macKeySize SHA256 = 32
+  ironMac SHA256 key text = b64url $ hmacGetDigest (hmac key text :: HMAC C.SHA256)
 
 -- | Specifies the salt for password-based key generation.
-data IronSalt = IronSalt ByteString -- ^ Supply pre-generated salt
-              | IronGenSalt Int -- ^ Generate salt of given size, in bits
+data Salt = Salt ByteString -- ^ Supply pre-generated salt
+          | GenSalt Int     -- ^ Generate salt of given size, in bits
   deriving Show
 
 {-
@@ -152,7 +134,7 @@
 
 -- | Options controlling encryption of Iron messages.
 data EncryptionOpts = EncryptionOpts
-  { ieSalt       :: IronSalt -- ^ Salt for password-based key generation
+  { ieSalt       :: Salt -- ^ Salt for password-based key generation
   , ieAlgorithm  :: IronCipher -- ^ Encryption algorithm
   , ieIterations :: Int -- ^ Number of iterations for password-based key generation
   , ieIV         :: Maybe ByteString -- ^ Pre-generated initial value block
@@ -160,42 +142,50 @@
 
 -- | Options controlling cryptographic verification of Iron messages.
 data IntegrityOpts = IntegrityOpts
-  { iiSalt       :: IronSalt -- ^ Salt for MAC key generation
-  , iiAlgorithm  :: IronMAC -- ^ Hash-based MAC algorithm
+  { iiSalt       :: Salt -- ^ Salt for MAC key generation
+  , iiAlgorithm  :: IronHMAC -- ^ Hash-based MAC algorithm
   , iiIterations :: Int -- ^ Number of iterations for MAC key generation
   } deriving Show
 
-defaultsEncrypt :: IronCipher -> EncryptionOpts
-defaultsEncrypt algo = EncryptionOpts
-                       { ieSalt = IronGenSalt 256
-                       , ieAlgorithm = algo
-                       , ieIterations = 1
+encryptOptions :: IronCipher -- ^ Cipher algorithm
+               -> Int -- ^ Number of salt bits for key generation
+               -> Int -- ^ Number of iterations of key derivation function
+               -> EncryptionOpts
+encryptOptions a s n = EncryptionOpts
+                       { ieSalt = GenSalt s
+                       , ieAlgorithm = a
+                       , ieIterations = n
                        , ieIV = Nothing }
 
-defaultsIntegrity :: IronMAC -> IntegrityOpts
-defaultsIntegrity algo = IntegrityOpts
-                         { iiSalt = IronGenSalt 256
-                         , iiAlgorithm = algo
-                         , iiIterations = 1 }
+integrityOptions :: IronHMAC -- ^ Cryptographic hash algorithm
+                 -> Int -- ^ Number of salt bits for key generation
+                 -> Int -- ^ Number of iterations of key derivation function
+                 -> IntegrityOpts
+integrityOptions a s n = IntegrityOpts
+                         { iiSalt = GenSalt s
+                         , iiAlgorithm = a
+                         , iiIterations = n }
 
-defaults :: Options
-defaults = Options
-  { ironEncryption = def
-  , ironIntegrity = def
+-- | A set of basic options. You need to choose a cipher and
+-- parameters for key generation.
+--
+-- There are also some default options chosen, which are:
+-- * Infinite message lifetime
+-- * Timestamp skew: 60 seconds either way
+-- * Local time offset: 0
+options :: IronCipher -- ^ Encryption algorithm.
+        -> IronHMAC    -- ^ Integrity check algorithm (use @SHA256@).
+        -> Int        -- ^ Number of salt bits for key generation.
+        -> Int        -- ^ Number of iterations of key derivation function.
+        -> Options
+options e i s n = Options
+  { ironEncryption = encryptOptions e s n
+  , ironIntegrity = integrityOptions i s n
   , ironTTL = 0
   , ironTimestampSkew = 60
   , ironLocaltimeOffset = 0
   }
 
-instance Default EncryptionOpts where
-  def = defaultsEncrypt AES256CBC
-
-instance Default IntegrityOpts where
-  def = defaultsIntegrity (IronMAC SHA256)
-
-instance Default Options where
-  def = defaults
-
 -- | Identifies the password to use when unsealing the message.
 type PasswordId = ByteString
 
@@ -210,25 +200,25 @@
 
 -- | Represents a key used for the cipher or message authentication
 -- code, or a password from which a key will be generated.
-data KeyPass = Key SecureMem      -- ^ Pre-generated key
-             | Password SecureMem -- ^ Key derived from password
+data KeyPass = Key ScrubbedBytes      -- ^ Pre-generated key
+             | Password ScrubbedBytes -- ^ Key derived from password
              deriving (Show, Eq)
-             -- note: SecureMem Show doesn't actually show any content
+             -- note: ScrubbedBytes Show doesn't actually show any content
 
 -- | Constructs a 'Password'.
-password :: ToSecureMem a => a -> Password
+password :: ByteArrayAccess a => a -> Password
 password p = passwords p p
 
 -- | Constructs a 'Password', with different encryption and integrity
 -- verification passwords.
-passwords :: ToSecureMem a => a -> a -> Password
+passwords :: ByteArrayAccess a => a -> a -> Password
 passwords e i = password' mempty e i
 
 -- | Constructs a 'Password'. The given identifier will be included as
 -- the second component of the the sealed @Fe26@ string. The
 -- identifier must only include alphanumeric characters and the
 -- underscore, otherwise nothing will be returned.
-passwordWithId :: ToSecureMem a => PasswordId -> a -> Maybe Password
+passwordWithId :: ByteArrayAccess a => PasswordId -> a -> Maybe Password
 passwordWithId k p = passwordsWithId k p p
 
 -- | Constructs a 'Password', with different encryption and integrity
@@ -236,7 +226,7 @@
 -- the second component of the the sealed @Fe26@ string. The
 -- identifier must only include alphanumeric characters and the
 -- underscore, otherwise nothing will be returned.
-passwordsWithId :: ToSecureMem a => PasswordId -> a -> a -> Maybe Password
+passwordsWithId :: ByteArrayAccess a => PasswordId -> a -> a -> Maybe Password
 passwordsWithId k e i | validId k = Just $ password' k e i
                       | otherwise = Nothing
 
@@ -244,12 +234,12 @@
 validId k = not (S8.null k) && S8.all inRange k
   where inRange c = isAscii c && isAlphaNum c || c == '_'
 
-passwordValid :: Byteable a => EncryptionOpts -> a -> Bool
-passwordValid EncryptionOpts{..} sec = keySize ieAlgorithm <= byteableLength sec
+passwordValid :: ByteArrayAccess a => EncryptionOpts -> a -> Bool
+passwordValid EncryptionOpts{..} sec = keySize ieAlgorithm <= BA.length sec
 
-password' :: ToSecureMem a => PasswordId -> a -> a -> Password
+password' :: ByteArrayAccess a => PasswordId -> a -> a -> Password
 password' k e i = MkPassword k (passwd e) (passwd i)
-  where passwd = Password . toSecureMem
+  where passwd = Password . BA.convert
 
 -- | User-supplied function to get the password corresponding to the
 -- identifier from the sealed message.
@@ -257,19 +247,14 @@
 
 -- | The simple case of LookupPassword, where there is the same
 -- password for encryption and verification of all messages.
-onePassword :: ToSecureMem a => a -> LookupPassword
+onePassword :: ByteArrayAccess a => a -> LookupPassword
 onePassword = const . Just . password
 
 -- | Encodes and encrypts a 'Data.Aeson.Value' using the given
--- password.
-seal :: ToJSON a => Password -> a -> IO ByteString
-seal password = liftM fromJust <$> sealWith defaults password
-
--- | Encodes and encrypts a 'Data.Aeson.Value' using the given
 -- password and 'Options'. Encryption may fail if the supplied
 -- options are wrong.
-sealWith :: ToJSON a => Options -> Password -> a -> IO (Maybe ByteString)
-sealWith opts p v = do
+seal :: ToJSON a => Options -> Password -> a -> IO (Maybe ByteString)
+seal opts p v = do
   s <- getSealStuff opts
   return $ seal' opts s p v
 
@@ -373,23 +358,19 @@
 expTime Options{ironTTL} now | ironTTL > 0 = Just ((now + ironTTL) * 1000)
                               | otherwise = Nothing
 
-instance IsIronMAC SHA256 where
-  macKeySize _ = 32
-  ironMac _ key text = b64 $ hmacGetDigest (hmac key text :: HMAC SHA256)
-
 -- | Calculates the MAC of a message. The result is encoded in the
 -- URL-friendly variant of Base64.
-macWithKey :: IronMAC -> ByteString -> ByteString -> ByteString
-macWithKey algo key text = urlSafeBase64 (ironMac algo key text)
+macWithKey :: IronHMAC -> ByteString -> ByteString -> ByteString
+macWithKey algo key text = ironMac algo key text
 
 generateKey :: Int -> Int -> ByteString -> KeyPass -> Either String ByteString
-generateKey _ s _ (Key k) | byteableLength k >= s = Right (toBytes k)
+generateKey _ s _ (Key k) | BA.length k >= s = Right (BA.convert k)
                           | otherwise = Left "Key buffer (password) too small"
 generateKey n s l (Password p) | BS.null l = Left "Missing salt"
                                | otherwise = Right (generateKey' n s l p)
 
-generateKey' :: Byteable p => Int -> Int -> ByteString -> p -> ByteString
-generateKey' iterations size salt p = PBKDF2.generate prf params (toBytes p) salt
+generateKey' :: BA.ByteArrayAccess p => Int -> Int -> ByteString -> p -> ByteString
+generateKey' iterations size salt p = PBKDF2.generate prf params p salt
   where
     prf = PBKDF2.prfHMAC SHA1
     params = PBKDF2.Parameters iterations size
@@ -443,14 +424,9 @@
     unpad p text'
 
 -- | Decrypts an Iron-encoded message 'Data.Aeson.Value' with the
--- given password.
-unseal :: FromJSON a => LookupPassword -> ByteString -> IO (Either String a)
-unseal p = unsealWith defaults p
-
--- | Decrypts an Iron-encoded message 'Data.Aeson.Value' with the
 -- given password and 'Options'.
-unsealWith :: FromJSON a => Options -> LookupPassword -> ByteString -> IO (Either String a)
-unsealWith opts p t = do
+unseal :: FromJSON a => Options -> LookupPassword -> ByteString -> IO (Either String a)
+unseal opts p t = do
   now <- getPOSIXTime
   return $ unseal' opts now p t
 
@@ -475,7 +451,7 @@
     verify :: Cookie -> KeyPass -> Either String ()
     verify Cookie{..} sec = do
       digest <- hmacWithPassword (ironIntegrity opts) sec ckIntSalt ckEnc
-      if constEqBytes ckIntDigest digest
+      if BA.constEq ckIntDigest digest
         then Right ()
         else Left "Bad hmac value"
 
@@ -494,14 +470,14 @@
 isExpired now skew (Just exp) = exp <= (now - skew)
 
 genSalt :: DRG gen => Int -> gen -> (ByteString, gen)
-genSalt saltBits gen = withRandomBytes gen (saltBits `quot` 8) B16.encode
+genSalt saltBits gen = withRandomBytes gen (saltBits `quot` 8) b16
 
 genIV :: DRG gen => Int -> gen -> (ByteString, gen)
 genIV size gen = withRandomBytes gen size id
 
-genSaltMaybe :: DRG gen => IronSalt -> gen -> (ByteString, gen)
-genSaltMaybe (IronSalt salt)   = \gen -> (salt, gen)
-genSaltMaybe (IronGenSalt len) = genSalt len
+genSaltMaybe :: DRG gen => Salt -> gen -> (ByteString, gen)
+genSaltMaybe (Salt salt)   = \gen -> (salt, gen)
+genSaltMaybe (GenSalt len) = genSalt len
 
 genIVMaybe :: DRG gen => IronCipher -> Maybe ByteString -> gen -> (ByteString, gen)
 genIVMaybe _ (Just iv)  = \gen -> (iv, gen)
diff --git a/src/Network/Iron/Util.hs b/src/Network/Iron/Util.hs
--- a/src/Network/Iron/Util.hs
+++ b/src/Network/Iron/Util.hs
@@ -6,53 +6,38 @@
   , b64dec
   , b64url
   , b64urldec
-  , urlSafeBase64
-  , unUrlSafeBase64
+  , b16
   -- * Time parsing
   , parseExpMsec
   -- * Error handling
   , justRight
   , rightJust
-  , mapLeft
   ) where
 
-import           Crypto.Hash
 import           Data.ByteArray          (ByteArrayAccess)
 import qualified Data.ByteArray.Encoding as B (Base (..), convertToBase, convertFromBase)
 import           Data.ByteString         (ByteString)
-import qualified Data.ByteString         as BS (pack, unpack)
 import qualified Data.ByteString.Char8   as S8
 import           Data.Monoid             ((<>))
 import           Data.Time.Clock         (NominalDiffTime)
 import           Text.Read               (readMaybe)
 
+-- | Shorthand for hex encode
+b16 :: ByteString -> ByteString
+b16 = B.convertToBase B.Base16
+
 -- | Shorthand for encode in Base64.
 b64 :: ByteArrayAccess a => a -> ByteString
 b64 = B.convertToBase B.Base64
 
 b64url :: ByteArrayAccess a => a -> ByteString
-b64url = urlSafeBase64 . b64
+b64url = B.convertToBase B.Base64URLUnpadded
 
 b64dec :: ByteArrayAccess a => a -> Either String ByteString
 b64dec = B.convertFromBase B.Base64
 
 b64urldec :: ByteString -> Either String ByteString
-b64urldec = b64dec . unUrlSafeBase64
-
--- | Fixes up a Base64 encoded string so that it's more convenient to
--- include in URLs. The padding @=@ signs are removed, and the
--- characters @+@ and @/@ are replaced with @-@ and @_@.
-urlSafeBase64 :: ByteString -> ByteString
-urlSafeBase64 = S8.filter (/= '=') . S8.map (tr '+' '-' . tr '/' '_')
-  where
-    tr a b c = if c == a then b else c
-
--- | The inverse of 'urlSafeBase64'.
-unUrlSafeBase64 :: ByteString -> ByteString
-unUrlSafeBase64 = pad . S8.map (tr '-' '+' . tr '_' '/')
-  where
-    tr a b c = if c == a then b else c
-    pad s = s <> S8.replicate (S8.length s `mod` 4) '='
+b64urldec = B.convertFromBase B.Base64URLUnpadded
 
 -- | Reads a positive integer time value in milliseconds. This is for
 -- parsing ttls or expiry times written as milliseconds since the unix
@@ -75,12 +60,3 @@
 justRight :: e -> Maybe a -> Either e a
 justRight _ (Just a) = Right a
 justRight e Nothing = Left e
-
--- | Modifies the left branch of an 'Either'.
-mapLeft :: (a -> a') -> Either a b -> Either a' b
-mapLeft f (Left a) = Left (f a)
-mapLeft _ (Right b) = Right b
-
--- | Modifies both branches of an 'Either'.
-mapEither :: (a -> a') -> (b -> b') -> Either a b -> Either a' b'
-mapEither f g = mapLeft f . fmap g
diff --git a/src/Network/Oz/JSON.hs b/src/Network/Oz/JSON.hs
--- a/src/Network/Oz/JSON.hs
+++ b/src/Network/Oz/JSON.hs
@@ -18,7 +18,7 @@
 import           Network.Oz.Types
 
 fieldModifier :: String -> String
-fieldModifier = drop 1 . dropWhile (/= '_') . dropWhile (== '_') . camelTo '_'
+fieldModifier = drop 1 . dropWhile (/= '_') . dropWhile (== '_') . camelTo2 '_'
 
 opts = defaultOptions { JSON.fieldLabelModifier = fieldModifier }
 
diff --git a/src/Network/Oz/Ticket.hs b/src/Network/Oz/Ticket.hs
--- a/src/Network/Oz/Ticket.hs
+++ b/src/Network/Oz/Ticket.hs
@@ -17,12 +17,13 @@
 import           Control.Monad.IO.Class (MonadIO (..), liftIO)
 import           Control.Applicative    ((<|>))
 import           Data.Monoid            ((<>))
+import           Data.Bifunctor         (first)
 import           Crypto.Random
 import           Data.Aeson             (Object (..), Value (..), object,
                                          toJSON)
 import           Data.ByteString        (ByteString)
 import qualified Data.ByteString        as BS
-import qualified Data.ByteString.Base64 as B64
+import qualified Data.ByteArray.Encoding as B (Base (..), convertToBase, convertFromBase)
 import           Data.List              (isInfixOf, nub)
 import           Data.Maybe             (catMaybes, fromMaybe, isJust)
 import           Data.Text              (Text)
@@ -44,7 +45,7 @@
 rsvp :: MonadIO m => OzAppId -> Maybe OzGrantId -> Key -> TicketOpts -> m (Maybe ByteString)
 rsvp app grant (Key p) TicketOpts{..} = liftIO $ do
   now <- getPOSIXTime
-  Iron.sealWith ticketOptsIron (Iron.password p) (envelope now)
+  Iron.seal ticketOptsIron (Iron.password p) (envelope now)
   where
     envelope now = OzTicket
                    { ozTicketExp = now + ticketOptsRsvpTtl
@@ -131,11 +132,11 @@
 
 -- | Validate a grant scope in comparison to an app scope.
 checkGrantScope :: Maybe OzScope -> Maybe OzScope -> Either String (Maybe OzScope)
-checkGrantScope app grant = mapLeft (const msg) (checkScopes app grant)
+checkGrantScope app grant = first (const msg) (checkScopes app grant)
   where msg = "Grant scope is not a subset of the application scope"
 
 checkParentScope :: Maybe OzScope -> Maybe OzScope -> Either String (Maybe OzScope)
-checkParentScope parent scope = mapLeft (const msg) (checkScopes parent scope)
+checkParentScope parent scope = first (const msg) (checkScopes parent scope)
   where msg = "New scope is not a subset of the parent ticket scope"
 
 checkScopes :: Maybe OzScope -> Maybe OzScope -> Either String (Maybe OzScope)
@@ -151,10 +152,6 @@
                  | length (nub scope) /= length scope = Left "scope includes duplicated item"
                  | otherwise = Right scope
 
-mapLeft :: (a -> c) -> Either a b -> Either c b
-mapLeft f (Left a) = Left (f a)
-mapLeft _ (Right b) = Right b
-
 randomKey :: TicketOpts -> IO ByteString
 randomKey TicketOpts{..} = do
   -- fixme: check that this is seeded properly
@@ -162,7 +159,7 @@
   return (fst $ withRandomBytes drg ticketOptsKeyBytes base64)
 
 base64 :: ByteString -> ByteString
-base64 = Iron.urlSafeBase64 . B64.encode
+base64 = B.convertToBase B.Base64URLUnpadded
 
 -- | Adds the cryptographic properties to a ticket and prepares it for
 -- sending.
@@ -171,7 +168,7 @@
   key <- randomKey opts
   let Object ext = toJSON ticketOptsExt
   let sealed = OzSealedTicket t (Key key) ticketOptsHmacAlgorithm ext ""
-  mid <- Iron.sealWith ticketOptsIron (Iron.password p) sealed
+  mid <- Iron.seal ticketOptsIron (Iron.password p) sealed
   return (finishSeal ticketOptsExt sealed <$> mid)
 
 -- | Removes the private ext part and adds the ticket ID.
@@ -182,5 +179,5 @@
 
 -- | Decodes a Hawk "app" string into an Oz Ticket.
 parse :: TicketOpts -> Key -> ByteString -> IO (Either String OzSealedTicket)
-parse TicketOpts{..} (Key p) = Iron.unsealWith ticketOptsIron lookup
+parse TicketOpts{..} (Key p) = Iron.unseal ticketOptsIron lookup
   where lookup = Iron.onePassword p
diff --git a/src/Network/Oz/Types.hs b/src/Network/Oz/Types.hs
--- a/src/Network/Oz/Types.hs
+++ b/src/Network/Oz/Types.hs
@@ -34,7 +34,7 @@
 
 import           Network.Hawk           (HawkAlgo)
 import           Network.Hawk.Types
-import qualified Network.Iron           as Iron (Options(..))
+import qualified Network.Iron           as Iron
 
 -- | Identifies an Oz Application
 type OzAppId = Text
@@ -171,7 +171,8 @@
   }
 
 defaultTicketOpts :: TicketOpts
-defaultTicketOpts = TicketOpts 3600 60 True def 32 (HawkAlgo SHA256) mempty
+defaultTicketOpts = TicketOpts 3600 60 True iron 32 (HawkAlgo SHA256) mempty
+  where iron = Iron.options Iron.AES256CBC Iron.SHA256 256 100000
 
 instance Default TicketOpts where
   def = defaultTicketOpts
diff --git a/test/Network/Iron/Tests.hs b/test/Network/Iron/Tests.hs
--- a/test/Network/Iron/Tests.hs
+++ b/test/Network/Iron/Tests.hs
@@ -13,7 +13,6 @@
 import Data.Either (isLeft)
 import Data.Aeson
 import Data.Time.Clock (NominalDiffTime)
-import Data.Default (def)
 
 import Test.QuickCheck
 import Test.QuickCheck.Monadic
@@ -114,15 +113,15 @@
 instance Arbitrary IntegrityOpts where
   arbitrary = IntegrityOpts <$> arbitrary <*> arbitrary <*> choose (1, 3)
 
-instance Arbitrary IronSalt where
-  -- arbitrary = oneof [IronSalt <$> arbitrary, pure $ IronGenSalt 256]
-  arbitrary = pure (IronGenSalt 256)
+instance Arbitrary Salt where
+  -- arbitrary = oneof [Salt <$> arbitrary, pure $ GenSalt 256]
+  arbitrary = pure (GenSalt 256)
 
 instance Arbitrary IronCipher where
   arbitrary = oneof (map pure [AES128CTR, AES256CBC])
 
-instance Arbitrary IronMAC where
-  arbitrary = pure (IronMAC SHA256)
+instance Arbitrary IronHMAC where
+  arbitrary = pure SHA256
 
 data Test1 a = Test1
   { test1Obj :: a
@@ -136,26 +135,29 @@
 prop_test :: (ToJSON a, FromJSON a, Eq a) => Test1 a -> Property
 prop_test Test1{..} = monadicIO $ do
   obj' <- run $ do
-    s <- seal test1Password test1Obj
-    Right m <- unseal (onePassword' test1Password) s
+    Just s <- seal testOpts test1Password test1Obj
+    Right m <- unseal testOpts (onePassword' test1Password) s
     return m
   assert (obj' == obj)
 
+testOpts :: Options
+testOpts = options AES256CBC SHA256 256 1
+
 -- turns object into a ticket than parses the ticket successfully
 prop_test1 :: Object -> Property
 prop_test1 o = monadicIO $ do
   obj' <- run $ do
-    s <- seal defaultPassword o
-    unseal lookupPassword s
+    Just s <- seal testOpts defaultPassword o
+    unseal testOpts lookupPassword s
   assert (obj' == Right obj)
 
 -- unseal and sealed object with expiration
 prop_test2 :: NominalDiffTime -> Property
 prop_test2 ttl = monadicIO $ do
-  let opts = def { ironTTL = ttl }
+  let opts = testOpts { ironTTL = ttl }
   obj' <- run $ do
-    Just s <- sealWith opts defaultPassword obj
-    unseal lookupPassword s
+    Just s <- seal opts defaultPassword obj
+    unseal opts lookupPassword s
   assert (obj' == Right obj)
 
 -- unseal and sealed object with expiration and time offset
@@ -166,8 +168,8 @@
              { ironLocaltimeOffset = negate (testTTL + 100)
              , ironTTL = testTTL }
   mobj' <- run $ do
-    Just s <- sealWith opts test1Password test1Obj
-    unseal (onePassword' test1Password) s
+    Just s <- seal opts test1Password test1Obj
+    unseal opts (onePassword' test1Password) s
   assert (testTTL == 0 || isErr mobj')
   assert (testTTL /= 0 || mobj' == Right test1Obj)
 
@@ -186,8 +188,8 @@
 prop_test4 :: ToJSON a => Test1 a -> Property
 prop_test4 Test1{..} = monadicIO $ do
   mobj' <- run $ do
-    Just s <- sealWith test1Opts defaultPassword test1Obj
-    unseal (const Nothing) s :: IO (Either String Object)
+    Just s <- seal test1Opts defaultPassword test1Obj
+    unseal test1Opts (const Nothing) s :: IO (Either String Object)
   assert (mobj' == Left "Cannot find password: default")
 
 -- ## generateKey
@@ -240,13 +242,13 @@
 -- unseals a ticket
 testUnseal01 :: Assertion
 testUnseal01 = do
-  r <- unseal lookupPassword ticket01
+  r <- unseal testOpts lookupPassword ticket01
   r @?= Right obj
 
 -- | Asserts that unsealing a ticket fails with the given message
 unsealFail :: ByteString -> String -> Assertion
 unsealFail ticket msg = do
-  r <- unseal lookupPassword ticket :: IO (Either String Object)
+  r <- unseal testOpts lookupPassword ticket :: IO (Either String Object)
   r @?= Left msg
 
 -- returns an error when number of sealed components is wrong
@@ -265,12 +267,12 @@
 
 -- returns an error when decryption fails
 testUnseal05 :: Assertion
-testUnseal05 = unsealFail ticket "base64: input: invalid encoding at offset: 64"
+testUnseal05 = unsealFail ticket "base64URL unpadded: input: invalid encoding at offset: 64"
   where ticket = "Fe26.2**a6dc6339e5ea5dfe7a135631cf3b7dcf47ea38246369d45767c928ea81781694*D3DLEoi-Hn3c972TPpZXqw*mCBhmhHhRKk9KtBjwu3h-1lx1MHKkgloQPKRkQZxpnDwYnFkb3RqdVTQRcuhGf4M??**ff2bf988aa0edf2b34c02d220a45c4a3c572dac6b995771ed20de58da919bfa5*n04AwdA-1wOnGusZJVjoZC9sbAPfBRCnd4iVyX2yM2Y"
 
 -- returns an error when iv base64 decoding fails
 testUnseal06 :: Assertion
-testUnseal06 = unsealFail ticket "base64: input: invalid encoding at offset: 22"
+testUnseal06 = unsealFail ticket "base64URL unpadded: input: invalid encoding at offset: 22"
   where ticket = "Fe26.2**a6dc6339e5ea5dfe7a135631cf3b7dcf47ea38246369d45767c928ea81781694*D3DLEoi-Hn3c972TPpZXqw??*mCBhmhHhRKk9KtBjwu3h-1lx1MHKkgloQPKRkQZxpnDwYnFkb3RqdVTQRcuhGf4M**ff2bf988aa0edf2b34c02d220a45c4a3c572dac6b995771ed20de58da919bfa5*iF6pSFeSD8iYRlYIfD6VRwADFjFR3fX6hM_kIjN3_ew"
 
 -- returns an error when decrypted object is invalid
