diff --git a/Crypto/Scrypt.hs b/Crypto/Scrypt.hs
--- a/Crypto/Scrypt.hs
+++ b/Crypto/Scrypt.hs
@@ -1,45 +1,64 @@
-{-# LANGUAGE ForeignFunctionInterface, RecordWildCards, NamedFieldPuns #-}
+{-# LANGUAGE ForeignFunctionInterface, OverloadedStrings,
+    RecordWildCards, NamedFieldPuns #-}
 
 -- |Scrypt is a sequential memory-hard key derivation function. This module
---  provides bindings to a fast C implementation of scrypt, written by Colin
---  Percival. For more information see <http://www.tarsnap.com/scrypt.html>.
-module Crypto.Scrypt ( 
+--  provides low-level bindings to the 'scrypt' key derivation function as
+--  well as a higher-level password-storage API. It is based on a fast C
+--  implementation of scrypt, written by Colin Percival. For further
+--  information see <http://www.tarsnap.com/scrypt.html>.
+--
+module Crypto.Scrypt (
     -- *Parameters to the @scrypt@ function
-     ScryptParams, params
-    -- * The @scrypt@ key derivation function
-    , Pass(..), Salt(..), PassHash(..)
-    , scrypt, scrypt', getSalt
+    -- $params
+     ScryptParams, scryptParams, defaultParams
+    -- * Password Storage
+    -- $password-storage
+    , EncryptedPass(..), encryptPass, encryptPass', verifyPass, verifyPass'
+    -- * Low-level bindings to the @scrypt@ key derivation function
+    -- $low-level
+    , Pass(..), Salt(..), PassHash(..), scrypt, scrypt'
     ) where
 
-import Control.Applicative ((<$>))
-import Data.ByteString (ByteString, useAsCStringLen, packCStringLen, hGet)
+import Control.Applicative
+import Data.ByteString.Base64 (encode)
+import qualified Data.ByteString.Base64 as Base64
+import Data.ByteString.Char8 hiding (map, concat)
 import Data.Maybe
 import Foreign
 import Foreign.C
 import System.IO
 
 
-newtype Pass = Pass { unPass :: ByteString } deriving (Show)
-newtype Salt = Salt { unSalt :: ByteString } deriving (Show)
-newtype PassHash = PassHash { unHash :: ByteString } deriving (Show,Eq)
+newtype Pass          = Pass     { unPass :: ByteString } deriving (Show, Eq)
+newtype Salt          = Salt     { unSalt :: ByteString } deriving (Show, Eq)
+newtype PassHash      = PassHash { unHash :: ByteString } deriving (Show,Eq)
+newtype EncryptedPass =
+    EncryptedPass { unEncryptedPass  :: ByteString } deriving (Show, Eq)
 
--- |Encapsulates the three tuning parameters to the 'scrypt' function: @N@,
---  @r@ and @p@. The parameters affect running time and memory usage:
+------------------------------------------------------------------------------
+-- $params
 --
---  /Memory usage/ is approximately @128*r*N@ bytes. Note that the
---  'params' function takes @log_2(N)@ as a parameter. As an example, the
---  default parameters used by 'scrypt''
---  
---  @   log_2(N) = 14, r = 8 and p = 1@
+-- Scrypt takes three tuning parameters: @N@, @r@ and @p@. The parameters
+-- affect running time and memory usage:
 --
+-- /Memory usage/ is approximately @128*r*N@ bytes. Note that the
+--  'scryptParams' function takes @log_2(N)@ as a parameter. As an example,
+--  the 'defaultParams'
+--
+--  >   log_2(N) = 14, r = 8 and p = 1
+--
 --  lead to 'scrypt' using @128 * 8 * 2^14 = 16M@ bytes of memory.
 --
 --  /Running time/ is proportional to all of @N@, @r@ and @p@. However
---  @p@ only as an insignificant influence on memory usage an can thus be
---  used to tune the running time of 'scrypt'.
+--  @p@ only has an insignificant influence on memory usage an can thus be
+--  used to independently tune the running time of 'scrypt'.
 --
-data ScryptParams = Params { logN, r, p, bufLen :: Integer}
 
+-- |Encapsulates the three tuning parameters to the 'scrypt' function: @N@,
+--  @r@ and @p@ (see above).
+--
+data ScryptParams = Params { logN, r, p, bufLen :: Integer} deriving (Eq)
+
 instance Show ScryptParams where
     show Params{..} = concat [ "ScryptParams "
         , "{ logN=", show logN
@@ -49,27 +68,145 @@
         ]
 
 -- |Constructor function for the 'ScryptParams' data type
-params :: Integer
-       -- ^ @log_2(N)@. Scrypt's @N@ parameter must be a power of two greater
-       -- than one, thus it's logarithm to base two must be greater than zero. 
-       -> Integer
-       -- ^ The parameter @r@, must be greater than zero.
-       -> Integer
-       -- ^ The parameter @p@, must be greater than zero. @r@ and @p@
-       --   must satisfy @r*p < 2^30@.
-       -> Maybe ScryptParams
-       -- ^ Returns 'Just' the parameter object for valid arguments,
-       --   otherwise 'Nothing'.
-params logN r p | valid     = Just ps
-                | otherwise = Nothing
+--
+scryptParams
+    :: Integer
+    -- ^ @log_2(N)@. Scrypt's @N@ parameter must be a power of two greater
+    --   than one, thus it's logarithm to base two must be greater than zero.
+    --   @128*r*N@ must be smaller than the available memory address space.
+    -> Integer
+    -- ^ The parameter @r@, must be greater than zero.
+    -> Integer
+    -- ^ The parameter @p@, must be greater than zero. @r@ and @p@
+    --   must satisfy @r*p < 2^30@.
+    -> Maybe ScryptParams
+    -- ^ Returns 'Just' the parameter object for valid arguments,
+    --   otherwise 'Nothing'.
+    --
+scryptParams logN r p | valid     = Just ps
+                      | otherwise = Nothing
   where
     ps    = Params { logN, r, p, bufLen = 64 }
     valid = and [ logN > 0, r > 0, p > 0
                 , r*p < 2^(30 :: Int)
                 , bufLen ps <= 2^(32 :: Int)-1 * 32
+                -- allocation fits into (virtual) memory
+                , 128*r*2^logN <= fromIntegral (maxBound :: CSize)
                 ]
 
+-- |Default parameters as recommended in the scrypt paper:
+--
+--  >   N = 2^14, r = 8, p = 1
+--
+--  Equivalent to @'fromJust' ('scryptParams' 14 8 1)@.
+--
+defaultParams :: ScryptParams
+defaultParams = fromJust (scryptParams 14 8 1)
+
+------------------------------------------------------------------------------
+-- $password-storage
+--
+-- To allow storing encrypted passwords conveniently in a single database
+-- column, the password storage API provides the data type 'EncryptedPass'. It
+-- combines a 'Pass' as well as the 'Salt' and 'ScryptParams' used to compute
+-- it into a single 'ByteString', separated by pipe (\"|\") characters. The
+-- 'Salt' and 'PassHash' are base64-encoded. Storing the 'ScryptParams' with 
+-- the password allows to gradually strengthen password encryption in case of
+-- changing security requirements.
+--
+-- A usage example is given below, showing encryption, verification and
+-- changing 'ScryptParams':
+--
+-- > >>> encrypted <- encryptPass defaultParams (Pass "secret")
+-- > >>> print encrypted
+-- > EncryptedPass {unEncryptedPass = "14|8|1|Wn5x[SNIP]nM=|Zl+p[SNIP]g=="}
+-- > >>> print $ verifyPass defaultParams (Pass "secret") encrypted
+-- > (True,Nothing)
+-- > >>> print $ verifyPass defaultParams (Pass "wrong") encrypted
+-- > (False,Nothing)
+-- > >>> let newParams = fromJust $ scryptParams 16 8 1
+-- > >>> print $ verifyPass newParams (Pass "secret") encrypted
+-- > (True,Just (EncryptedPass {unEncryptedPass = "16|8|1|Wn5x[SNIP]nM=|ZmWw[SNIP]Q=="}))
+--
+
+combine :: ScryptParams -> Salt -> PassHash -> EncryptedPass
+combine Params{..} (Salt salt) (PassHash passHash) =
+    EncryptedPass $ intercalate "|"
+        [showBS logN, showBS r, showBS p, encode salt, encode passHash]
+  where
+    showBS = pack . show
+
+separate :: EncryptedPass -> Maybe (ScryptParams, Salt, PassHash)
+separate = go . split '|' . unEncryptedPass
+  where
+    go [logN', r', p', salt', hash'] = do
+        [salt, hash] <- mapM decodeBase64 [salt', hash']
+        [logN, r, p] <- mapM (fmap fst . readInteger) [logN', r', p']
+        params       <- scryptParams logN r p
+        return (params, Salt salt, PassHash hash)
+    go _          = Nothing
+    decodeBase64  = either (const Nothing) Just . Base64.decode
+
+-- |Encrypt the password with the given parameters and a random 32-byte salt.
+-- The salt is read from @\/dev\/urandom@.
+--
+encryptPass :: ScryptParams -> Pass -> IO EncryptedPass
+encryptPass params pass = do
+    salt <- Salt <$> withBinaryFile "/dev/urandom" ReadMode (`hGet` 32)
+    return $ combine params salt (scrypt params salt pass)
+
+-- |Equivalent to @encryptPass defaultParams@.
+--
+encryptPass' :: Pass -> IO EncryptedPass
+encryptPass' = encryptPass defaultParams
+
+-- |Verify a 'Pass' against an 'EncryptedPass'. The function also takes
+--  'ScryptParams' meeting your current security requirements. In case the
+--  'EncryptedPass' was generated with different parameters, the function
+--  returns an updated 'EncryptedPass', generated with the given 
+--  'ScryptParams'. The 'Salt' is kept from the given 'EncryptedPass'.
+--
+verifyPass
+    :: ScryptParams
+    -- ^ Parameters to use for updating the 'EncryptedPass'.
+    -> Pass
+    -- ^ The candidate 'Pass'.
+    -> EncryptedPass
+    -- ^ The 'EncryptedPass' to check against.
+    -> (Bool, Maybe EncryptedPass)
+    -- ^ Returns a pair of
+    --
+    --     * 'Bool' indicating verification success or failure.
+    --
+    --     * 'Just' a /new/ 'EncryptedPass' if the given 'ScryptParams' are
+    --      different from those encapsulated in the /given/ 'EncryptedPass',
+    --      otherwise 'Nothing'.
+    --
+verifyPass newParams candidate encrypted =
+    maybe (False, Nothing) verify (separate encrypted)
+  where
+    verify (params,salt,hash) =
+        let valid   = scrypt params salt candidate == hash
+            newHash = scrypt newParams salt candidate
+            newEncr = if not valid || params == newParams
+                        then Nothing
+                        else Just (combine newParams salt newHash)
+        in (valid, newEncr)
+
+-- |Equivalent to @verifyPass defaultParams@.
+--
+verifyPass' :: Pass -> EncryptedPass -> (Bool, Maybe EncryptedPass)
+verifyPass' = verifyPass defaultParams
+
+------------------------------------------------------------------------------
+-- $low-level
+--
+-- Bindings to a fast C implementation of 'scrypt'. For password storage,
+-- consider using the more convenient higher-level API above.
+--
+
 -- |Calculates a 64-byte hash from the given password, salt and parameters.
+--
 scrypt :: ScryptParams -> Salt -> Pass -> PassHash
 scrypt Params{..} (Salt salt) (Pass pass) =
     PassHash <$> unsafePerformIO $
@@ -90,15 +227,7 @@
     -> Ptr Word8 -> CSize         -- result buffer
     -> IO CInt
 
--- |Note the prime symbol (\'). Calls 'scrypt' with default parameters as
---  recommended in the scrypt paper:
---
---  @   N = 2^14, r = 8, p = 1 @
+-- |Note the prime symbol (\'). Calls 'scrypt' with 'defaultParams'.
 --
---  Equivalent to @'scrypt' ('fromJust' ('params' 14 8 1))@.
 scrypt' :: Salt -> Pass -> PassHash
-scrypt' = scrypt $ fromJust (params 14 8 1)
-
--- |Reads a 32-byte random salt from @\/dev\/urandom@.
-getSalt :: IO Salt
-getSalt = Salt <$> withBinaryFile "/dev/urandom" ReadMode (flip hGet 32)
+scrypt' = scrypt $ fromJust (scryptParams 14 8 1)
diff --git a/scrypt.cabal b/scrypt.cabal
--- a/scrypt.cabal
+++ b/scrypt.cabal
@@ -1,5 +1,5 @@
 name:           scrypt
-version:        0.2.1
+version:        0.3.0
 license:        BSD3
 license-file:   LICENSE
 category:       Cryptography
@@ -35,6 +35,7 @@
 
     build-depends:
         base == 4.*,
+        base64-bytestring == 0.1.*,
         bytestring == 0.9.*
 
     ghc-options: -Wall
