diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.7
+
+* Add PKCS5 / PKCS7 padding and unpadding methods
+* Fix ChaChaPoly1305 Decryption
+* Add support for BCrypt (Luke Taylor)
+
 ## 0.6
 
 * Add ChaChaPoly1305 AE cipher
diff --git a/Crypto/Cipher/Blowfish/Primitive.hs b/Crypto/Cipher/Blowfish/Primitive.hs
--- a/Crypto/Cipher/Blowfish/Primitive.hs
+++ b/Crypto/Cipher/Blowfish/Primitive.hs
@@ -16,16 +16,18 @@
     , initBlowfish
     , encrypt
     , decrypt
+    , eksBlowfish
     ) where
 
 import           Control.Monad (when)
 import           Data.Bits
+import           Data.Memory.Endian
 import           Data.Word
 
 import           Crypto.Error
 import           Crypto.Internal.Compat
 import           Crypto.Internal.Imports
-import           Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray)
+import           Crypto.Internal.ByteArray (ByteArrayAccess, ByteArray, Bytes)
 import qualified Crypto.Internal.ByteArray as B
 import           Crypto.Internal.Words
 import           Crypto.Internal.WordArray
@@ -64,17 +66,25 @@
 
 -- | Initialize a new Blowfish context from a key.
 --
--- key need to be between 0 to 448 bits.
+-- key needs to be between 0 and 448 bits.
 initBlowfish :: ByteArrayAccess key => key -> CryptoFailable Context
 initBlowfish key
-    | len > (448 `div` 8) = CryptoFailed $ CryptoError_KeySizeInvalid
-    | otherwise           = CryptoPassed $ makeKeySchedule key
+    | len > (448 `div` 8) = CryptoFailed CryptoError_KeySizeInvalid
+    | otherwise           = CryptoPassed $ makeKeySchedule key (Nothing :: Maybe (Bytes, Int))
   where len = B.length key
 
+-- | The BCrypt "expensive key schedule" version of blowfish.
+--
+-- Salt must be 128 bits
+-- Cost must be between 4 and 31 inclusive
+-- See <https://www.usenix.org/conference/1999-usenix-annual-technical-conference/future-adaptable-password-scheme>
+eksBlowfish :: (ByteArrayAccess salt, ByteArrayAccess password) => Int -> salt -> password -> Context
+eksBlowfish cost salt key = makeKeySchedule key (Just (salt, cost))
+
 coreCrypto :: Context -> Word64 -> Word64
 coreCrypto (BF p s0 s1 s2 s3) input = doRound input 0
   where
-    -- transform the input @i over 16 rounds
+    -- transform the input over 16 rounds
     doRound :: Word64 -> Int -> Word64
     doRound i roundIndex
         | roundIndex == 16 =
@@ -84,7 +94,6 @@
             let newr = fromIntegral (i `shiftR` 32) `xor` (p roundIndex)
                 newi = ((i `shiftL` 32) `xor` (f newr)) .|. (fromIntegral newr)
              in doRound newi (roundIndex+1)
-
     f   :: Word32 -> Word64
     f t = let a = s0 (fromIntegral $ (t `shiftR` 24) .&. 0xff)
               b = s1 (fromIntegral $ (t `shiftR` 16) .&. 0xff)
@@ -92,22 +101,26 @@
               d = s3 (fromIntegral $ t .&. 0xff)
            in fromIntegral (((a + b) `xor` c) + d) `shiftL` 32
 
-makeKeySchedule :: ByteArrayAccess key => key -> Context
-makeKeySchedule key =
+
+-- | Create a key schedule for either plain Blowfish or the BCrypt "EKS" version
+-- For the expensive version, the salt and cost factor are supplied. Salt must be
+-- a 128-bit byte array.
+--
+-- The standard case is just a single key expansion with the salt set to zero.
+makeKeySchedule :: (ByteArrayAccess key, ByteArrayAccess salt) => key-> Maybe (salt, Int) -> Context
+makeKeySchedule keyBytes saltCost =
     let v = unsafeDoIO $ do
-              let len = B.length key
               mv <- createKeySchedule
-              when (len > 0) $ forM_ [0..17] $ \i -> do
-                    let a = B.index key ((i * 4 + 0) `mod` len)
-                        b = B.index key ((i * 4 + 1) `mod` len)
-                        c = B.index key ((i * 4 + 2) `mod` len)
-                        d = B.index key ((i * 4 + 3) `mod` len)
-                        k = (fromIntegral a `shiftL` 24) .|.
-                            (fromIntegral b `shiftL` 16) .|.
-                            (fromIntegral c `shiftL`  8) .|.
-                            (fromIntegral d)
-                    mutableArrayWriteXor32 mv i k
-              prepare mv
+              case saltCost of
+                  -- Standard blowfish
+                  Nothing -> expandKey mv 0 0 keyBytes
+                  -- The expensive case
+                  Just (s, cost)  -> do
+                      let (salt1, salt2) = splitSalt s
+                      expandKey mv salt1 salt2 keyBytes
+                      forM_ [1..2^cost :: Int] $ \_ -> do
+                          expandKey mv 0 0 keyBytes
+                          expandKey mv 0 0 s
               mutableArray32Freeze mv
      in BF (\i -> arrayRead32 v i)
            (\i -> arrayRead32 v (s0+i))
@@ -115,21 +128,49 @@
            (\i -> arrayRead32 v (s2+i))
            (\i -> arrayRead32 v (s3+i))
   where
+        splitSalt s = (fromBE (B.toW64BE s 0), fromBE (B.toW64BE s 8))
+
+        -- Indices of the S-Box arrays, each containing 256 32-bit words
+        -- The first 18 words contain the P-Array of subkeys
         s0 = 18
         s1 = 274
         s2 = 530
         s3 = 786
 
-        prepare mctx = loop 0 0
-          where loop i input
+expandKey :: ByteArrayAccess ba
+          => MutableArray32      -- ^ The key schedule
+          -> Word64              -- ^ First word of the salt
+          -> Word64              -- ^ Second word of the salt
+          -> ba                  -- ^ The key
+          -> IO ()
+expandKey mv salt1 salt2 key = do
+    when (len > 0) $ forM_ [0..17] $ \i -> do
+        let a = B.index key ((i * 4 + 0) `mod` len)
+            b = B.index key ((i * 4 + 1) `mod` len)
+            c = B.index key ((i * 4 + 2) `mod` len)
+            d = B.index key ((i * 4 + 3) `mod` len)
+            k = (fromIntegral a `shiftL` 24) .|.
+                (fromIntegral b `shiftL` 16) .|.
+                (fromIntegral c `shiftL`  8) .|.
+                (fromIntegral d)
+        mutableArrayWriteXor32 mv i k
+    prepare mv
+    return ()
+  where
+        len = B.length key
+
+        -- | Go through the entire key schedule overwriting the P-Array and S-Boxes
+        prepare mctx = loop 0 salt1 salt1 salt2
+          where loop i input slt1 slt2
                   | i == 1042   = return ()
                   | otherwise = do
                       ninput <- coreCryptoMutable input
                       let (nl, nr) = w64to32 ninput
                       mutableArrayWrite32 mctx i     nl
                       mutableArrayWrite32 mctx (i+1) nr
-                      loop (i+2) ninput
+                      loop (i+2) (ninput `xor` slt2) slt2 slt1
 
+                -- | Blowfish encrypt a Word using the current state of the key schedule
                 coreCryptoMutable :: Word64 -> IO Word64
                 coreCryptoMutable input = doRound input 0
                   where doRound i roundIndex
@@ -145,10 +186,14 @@
                               let newi = ((i `shiftL` 32) `xor` newr') .|. (fromIntegral newr)
                               doRound newi (roundIndex+1)
 
-
+                -- The Blowfish Feistel function F
                 f   :: Word32 -> IO Word64
                 f t = do a <- mutableArrayRead32 mctx (s0 + fromIntegral ((t `shiftR` 24) .&. 0xff))
                          b <- mutableArrayRead32 mctx (s1 + fromIntegral ((t `shiftR` 16) .&. 0xff))
                          c <- mutableArrayRead32 mctx (s2 + fromIntegral ((t `shiftR` 8) .&. 0xff))
                          d <- mutableArrayRead32 mctx (s3 + fromIntegral (t .&. 0xff))
                          return (fromIntegral (((a + b) `xor` c) + d) `shiftL` 32)
+                  where s0 = 18
+                        s1 = 274
+                        s2 = 530
+                        s3 = 786
diff --git a/Crypto/Cipher/ChaChaPoly1305.hs b/Crypto/Cipher/ChaChaPoly1305.hs
--- a/Crypto/Cipher/ChaChaPoly1305.hs
+++ b/Crypto/Cipher/ChaChaPoly1305.hs
@@ -17,7 +17,8 @@
     , initialize
     , appendAAD
     , finalizeAAD
-    , combine
+    , encrypt
+    , decrypt
     , finalize
     ) where
 
@@ -81,7 +82,7 @@
   where
     rootState           = ChaCha.initialize 20 key nonce
     (polyKey, encState) = ChaCha.generate rootState 64
-    polyState           = Poly1305.initialize (B.take 32 polyKey :: ScrubbedBytes)
+    polyState           = throwCryptoError $ Poly1305.initialize (B.take 32 polyKey :: ScrubbedBytes)
 
 appendAAD :: ByteArrayAccess ba => ba -> State -> State
 appendAAD ba (State encState macState aadLength plainLength) =
@@ -96,17 +97,25 @@
   where
     newMacState = Poly1305.update macState $ pad16 aadLength
 
-combine :: ByteArray ba => ba -> State -> (ba, State)
-combine input (State encState macState aadLength plainLength) =
+encrypt :: ByteArray ba => ba -> State -> (ba, State)
+encrypt input (State encState macState aadLength plainLength) =
     (output, State newEncState newMacState aadLength newPlainLength)
   where
     (output, newEncState) = ChaCha.combine encState input
     newMacState           = Poly1305.update macState output
     newPlainLength        = plainLength + fromIntegral (B.length input)
 
+decrypt :: ByteArray ba => ba -> State -> (ba, State)
+decrypt input (State encState macState aadLength plainLength) =
+    (output, State newEncState newMacState aadLength newPlainLength)
+  where
+    (output, newEncState) = ChaCha.combine encState input
+    newMacState           = Poly1305.update macState input
+    newPlainLength        = plainLength + fromIntegral (B.length input)
+
 finalize :: State -> Poly1305.Auth
 finalize (State _ macState aadLength plainLength) =
     Poly1305.finalize $ Poly1305.updates macState
         [ pad16 plainLength
-        , either (error "finalize: internal error") id $ P.fill 16 (P.putStorable (LE aadLength) >> P.putStorable (LE plainLength))
+        , either (error "finalize: internal error") id $ P.fill 16 (P.putStorable (toLE aadLength) >> P.putStorable (toLE plainLength))
         ]
diff --git a/Crypto/Data/Padding.hs b/Crypto/Data/Padding.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/Data/Padding.hs
@@ -0,0 +1,47 @@
+-- |
+-- Module      : Crypto.Data.Padding
+-- License     : BSD-style
+-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
+-- Stability   : experimental
+-- Portability : unknown
+--
+-- Various cryptographic padding commonly used for block ciphers
+-- or assymetric systems.
+--
+module Crypto.Data.Padding
+    ( Format(..)
+    , pad
+    , unpad
+    ) where
+
+import           Data.ByteArray (ByteArray, Bytes)
+import qualified Data.ByteArray as B
+
+data Format =
+      PKCS5     -- ^ PKCS5: PKCS7 with hardcoded size of 8
+    | PKCS7 Int -- ^ PKCS7 with padding size between 1 and 255
+    deriving (Show, Eq)
+
+-- | Apply some pad to a bytearray
+pad :: ByteArray byteArray => Format -> byteArray -> byteArray
+pad  PKCS5     bin = pad (PKCS7 8) bin
+pad (PKCS7 sz) bin = bin `B.append` paddingString
+  where
+    paddingString = B.replicate paddingByte (fromIntegral paddingByte)
+    paddingByte   = sz - (B.length bin `mod` sz)
+
+-- | Try to remove some padding from a bytearray.
+unpad :: ByteArray byteArray => Format -> byteArray -> Maybe byteArray
+unpad  PKCS5     bin = unpad (PKCS7 8) bin
+unpad (PKCS7 sz) bin
+    | len == 0                           = Nothing
+    | (len `mod` sz) /= 0                = Nothing
+    | paddingSz < 1 || paddingSz > len   = Nothing
+    | paddingWitness `B.constEq` padding = Just content
+    | otherwise                          = Nothing
+  where
+    len         = B.length bin
+    paddingByte = B.index bin (len - 1)
+    paddingSz   = fromIntegral paddingByte
+    (content, padding) = B.splitAt (len - paddingSz) bin
+    paddingWitness     = B.replicate paddingSz paddingByte :: Bytes
diff --git a/Crypto/Error/Types.hs b/Crypto/Error/Types.hs
--- a/Crypto/Error/Types.hs
+++ b/Crypto/Error/Types.hs
@@ -33,6 +33,8 @@
     | CryptoError_SecretKeySizeInvalid
     | CryptoError_SecretKeyStructureInvalid
     | CryptoError_PublicKeySizeInvalid
+    -- Message authentification error
+    | CryptoError_MacKeyInvalid
     deriving (Show,Eq,Enum,Data,Typeable)
 
 instance E.Exception CryptoError
diff --git a/Crypto/Internal/CompatPrim.hs b/Crypto/Internal/CompatPrim.hs
--- a/Crypto/Internal/CompatPrim.hs
+++ b/Crypto/Internal/CompatPrim.hs
@@ -24,6 +24,9 @@
     ) where
 
 import GHC.Prim
+#if !defined(ARCH_IS_LITTLE_ENDIAN) && !defined(ARCH_IS_BIG_ENDIAN)
+import Data.Memory.Endian (getSystemEndianness, Endianness(..))
+#endif
 
 -- | byteswap Word# to or from Big Endian
 --
@@ -31,8 +34,10 @@
 be32Prim :: Word# -> Word#
 #ifdef ARCH_IS_LITTLE_ENDIAN
 be32Prim = byteswap32Prim
+#elif defined(ARCH_IS_BIG_ENDIAN)
+be32Prim = id
 #else
-be32Prim w = w
+be32Prim w = if getSystemEndianness == LittleEndian then byteswap32Prim w else w
 #endif
 
 -- | byteswap Word# to or from Little Endian
@@ -41,8 +46,10 @@
 le32Prim :: Word# -> Word#
 #ifdef ARCH_IS_LITTLE_ENDIAN
 le32Prim w = w
-#else
+#elif defined(ARCH_IS_BIG_ENDIAN)
 le32Prim = byteswap32Prim
+#else
+le32Prim w = if getSystemEndianness == LittleEndian then w else byteswap32Prim w
 #endif
 
 -- | Simple compatibility for byteswap the lower 32 bits of a Word#
@@ -69,11 +76,24 @@
         !c2 = uncheckedShiftL# b 16#
         !c3 = uncheckedShiftL# c 8#
         !c4 = d
-#else
+#elif defined(ARCH_IS_BIG_ENDIAN)
         !c1 = uncheckedShiftL# d 24#
         !c2 = uncheckedShiftL# c 16#
         !c3 = uncheckedShiftL# b 8#
         !c4 = a
+#else
+        !c1
+            | getSystemEndianness == LittleEndian = uncheckedShiftL# a 24#
+            | otherwise                           = uncheckedShiftL# d 24#
+        !c2
+            | getSystemEndianness == LittleEndian = uncheckedShiftL# b 16#
+            | otherwise                           = uncheckedShiftL# c 16#
+        !c3
+            | getSystemEndianness == LittleEndian = uncheckedShiftL# c 8#
+            | otherwise                           = uncheckedShiftL# b 8#
+        !c4
+            | getSystemEndianness == LittleEndian = d
+            | otherwise                           = a
 #endif
 
 -- | Simple wrapper to handle pre 7.8 and future, where
diff --git a/Crypto/KDF/BCrypt.hs b/Crypto/KDF/BCrypt.hs
new file mode 100644
--- /dev/null
+++ b/Crypto/KDF/BCrypt.hs
@@ -0,0 +1,140 @@
+
+-- | Password encoding and validation using bcrypt.
+--
+-- See <https://www.usenix.org/conference/1999-usenix-annual-technical-conference/future-adaptable-password-scheme>
+-- for details of the original algorithm.
+--
+-- Hashes are strings of the form @$2a$10$MJJifxfaqQmbx1Mhsq3oq.YmMmfNhkyW4s/MS3K5rIMVfB7w0Q/OW@ which
+-- encode a version number, an integer cost parameter and the concatenated salt and hash bytes (each
+-- separately Base64 encoded. Incrementing the cost parameter approximately doubles the time taken
+-- to calculate the hash.
+--
+-- The different version numbers have evolved because of bugs in the standard C implementations.
+-- The most up to date version is @2b@ and this implementation the @2b@ version prefix, but will also
+-- attempt to validate against hashes with versions @2a@ and @2y@. Version @2@ or @2x@ will be rejected.
+-- No attempt is made to differentiate between the different versions when validating a password, but
+-- in practice this shouldn't cause any problems if passwords are UTF-8 encoded (which they should be).
+--
+-- The cost parameter can be between 4 and 31 inclusive, but anything less than 10 is probably not strong
+-- enough. High values may be prohibitively slow depending on your hardware. Choose the highest value you
+-- can without having an unacceptable impact on your users. The cost parameter can also varied depending on
+-- the account, since it is unique to an individual hash.
+
+module Crypto.KDF.BCrypt
+    ( hashPassword
+    , validatePassword
+    , validatePasswordEither
+    , bcrypt
+    )
+where
+
+import           Control.Monad (unless, when)
+import           Crypto.Cipher.Blowfish.Primitive (eksBlowfish, encrypt)
+import           Crypto.Random (MonadRandom, getRandomBytes)
+import           Data.ByteArray (ByteArrayAccess, ByteArray, Bytes)
+import qualified Data.ByteArray as B
+import           Data.ByteArray.Encoding
+import           Data.Char
+
+data BCryptHash = BCH Char Int Bytes Bytes
+
+-- | Create a bcrypt hash for a password with a provided cost value.
+--
+-- Each increment of the cost approximately doubles the time taken.
+-- The 16 bytes of random salt will be generated internally.
+hashPassword :: (MonadRandom m, ByteArray password, ByteArray hash)
+             => Int
+             -- ^ The cost parameter. Should be between 4 and 31 (inclusive).
+             -- Values which lie outside this range will be adjusted accordingly.
+             -> password
+             -- ^ The password. Should be the UTF-8 encoded bytes of the password text.
+             -> m hash
+             -- ^ The bcrypt hash in standard format.
+hashPassword cost password = do
+    salt <- getRandomBytes 16
+    return $ bcrypt cost (salt :: Bytes) password
+
+-- | Create a bcrypt hash for a password with a provided cost value and salt.
+bcrypt :: (ByteArray salt, ByteArray password, ByteArray output)
+       => Int
+       -- ^ The cost parameter. Should be between 4 and 31 (inclusive).
+       -- Values which lie outside this range will be adjusted accordingly.
+       -> salt
+       -- ^ The salt. Must be 16 bytes in length or an error will be raised.
+       -> password
+       -- ^ The password. Should be the UTF-8 encoded bytes of the password text.
+       -> output
+       -- ^ The bcrypt hash in standard format.
+bcrypt cost salt password = B.concat [header, B.snoc costBytes dollar, b64 salt, b64 hash]
+  where
+    hash   = rawHash 'b' realCost salt password
+    header = B.pack [dollar, fromIntegral (ord '2'), fromIntegral (ord 'a'), dollar]
+    dollar = fromIntegral (ord '$')
+    zero   = fromIntegral (ord '0')
+    costBytes  = B.pack [zero + fromIntegral (realCost `div` 10), zero + fromIntegral (realCost `mod` 10)]
+    realCost
+        | cost < 4  = 10 -- 4 is virtually pointless so go for 10
+        | cost > 31 = 31
+        | otherwise = cost
+
+    b64 :: (ByteArray ba) => ba -> ba
+    b64 = convertToBase Base64OpenBSD
+
+-- | Check a password against a bcrypt hash
+--
+-- Returns @False@ if the password doesn't match the hash, or if the hash is
+-- invalid or an unsupported version.
+validatePassword :: (ByteArray password, ByteArray hash) => password -> hash -> Bool
+validatePassword password bcHash = either (const False) id (validatePasswordEither password bcHash)
+
+-- | Check a password against a bcrypt hash
+--
+-- As for @validatePassword@ but will provide error information if the hash is invalid or
+-- an unsupported version.
+validatePasswordEither :: (ByteArray password, ByteArray hash) => password -> hash -> Either String Bool
+validatePasswordEither password bcHash = do
+    BCH version cost salt hash <- parseBCryptHash bcHash
+    return $ (rawHash version cost salt password :: Bytes) `B.constEq` hash
+
+rawHash :: (ByteArrayAccess salt, ByteArray password, ByteArray output) => Char -> Int -> salt -> password -> output
+rawHash _ cost salt password = B.take 23 hash -- Another compatibility bug. Ignore last byte of hash
+  where
+    hash = loop (0 :: Int) orpheanBeholder
+
+    loop i input
+        | i < 64    = loop (i+1) (encrypt ctx input)
+        | otherwise = input
+
+    -- Truncate the password if necessary and append a null byte for C compatibility
+    key = B.snoc (B.take 72 password) 0
+
+    ctx = eksBlowfish cost salt key
+
+    -- The BCrypt plaintext: "OrpheanBeholderScryDoubt"
+    orpheanBeholder = B.pack [79,114,112,104,101,97,110,66,101,104,111,108,100,101,114,83,99,114,121,68,111,117,98,116]
+
+-- "$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga"
+parseBCryptHash :: (ByteArray ba) => ba -> Either String BCryptHash
+parseBCryptHash bc = do
+    unless (B.length bc == 60      &&
+            B.index bc 0 == dollar &&
+            B.index bc 1 == fromIntegral (ord '2') &&
+            B.index bc 3 == dollar &&
+            B.index bc 6 == dollar) (Left "Invalid hash format")
+    unless (version == 'b' || version == 'a' || version == 'y') (Left ("Unsupported minor version: " ++ [version]))
+    when (costTens > 3 || cost > 31 || cost < 4)  (Left "Invalid bcrypt cost")
+    (salt, hash) <- decodeSaltHash (B.drop 7 bc)
+    return (BCH version cost salt hash)
+  where
+    dollar    = fromIntegral (ord '$')
+    zero      = ord '0'
+    costTens  = fromIntegral (B.index bc 4) - zero
+    costUnits = fromIntegral (B.index bc 5) - zero
+    version   = chr (fromIntegral (B.index bc 2))
+    cost      = costUnits + (if costTens == 0 then 0 else 10^costTens) :: Int
+
+    decodeSaltHash saltHash = do
+        let (s, h) = B.splitAt 22 saltHash
+        salt <- convertFromBase Base64OpenBSD s
+        hash <- convertFromBase Base64OpenBSD h
+        return (salt, hash)
diff --git a/Crypto/KDF/Scrypt.hs b/Crypto/KDF/Scrypt.hs
--- a/Crypto/KDF/Scrypt.hs
+++ b/Crypto/KDF/Scrypt.hs
@@ -5,7 +5,9 @@
 -- Stability   : experimental
 -- Portability : unknown
 --
--- Scrypt key derivation function as defined in Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard Functions" <http://www.tarsnap.com/scrypt/scrypt.pdf>.
+-- Scrypt key derivation function as defined in Colin Percival's paper
+-- "Stronger Key Derivation via Sequential Memory-Hard Functions"
+-- <http://www.tarsnap.com/scrypt/scrypt.pdf>.
 --
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
diff --git a/Crypto/MAC/Poly1305.hs b/Crypto/MAC/Poly1305.hs
--- a/Crypto/MAC/Poly1305.hs
+++ b/Crypto/MAC/Poly1305.hs
@@ -29,6 +29,8 @@
 import           Data.Word
 import           Crypto.Internal.ByteArray (ByteArrayAccess, ScrubbedBytes, Bytes)
 import qualified Crypto.Internal.ByteArray as B
+import           Crypto.Internal.DeepSeq
+import           Crypto.Error
 
 -- | Poly1305 State
 newtype State = State ScrubbedBytes
@@ -39,7 +41,7 @@
 
 -- | Poly1305 Auth
 newtype Auth = Auth Bytes
-    deriving (ByteArrayAccess)
+    deriving (ByteArrayAccess,NFData)
 
 instance Eq Auth where
     (Auth a1) == (Auth a2) = B.constEq a1 a2
@@ -56,10 +58,10 @@
 -- | initialize a Poly1305 context
 initialize :: ByteArrayAccess key
            => key
-           -> State
+           -> CryptoFailable State
 initialize key
-    | B.length key /= 32 = error "Poly1305: key length expected 32 bytes"
-    | otherwise          = State $ B.allocAndFreeze 84 $ \ctxPtr ->
+    | B.length key /= 32 = CryptoFailed $ CryptoError_MacKeyInvalid
+    | otherwise          = CryptoPassed $ State $ B.allocAndFreeze 84 $ \ctxPtr ->
         B.withByteArray key $ \keyPtr ->
             c_poly1305_init (castPtr ctxPtr) keyPtr
 {-# NOINLINE initialize #-}
diff --git a/cbits/cryptonite_scrypt.c b/cbits/cryptonite_scrypt.c
--- a/cbits/cryptonite_scrypt.c
+++ b/cbits/cryptonite_scrypt.c
@@ -46,7 +46,7 @@
 
 static inline uint64_t integerify(uint32_t *B, const uint32_t r)
 {
-	return le64_to_cpu(*((uint64_t *) (B + (2*r-1) * 16)));
+	return B[(2*r-1) * 16] | (uint64_t)B[(2*r-1) * 16 + 1] << 32;
 }
 
 static inline uint32_t load32(const uint8_t *p)
diff --git a/cryptonite.cabal b/cryptonite.cabal
--- a/cryptonite.cabal
+++ b/cryptonite.cabal
@@ -1,5 +1,5 @@
 Name:                cryptonite
-Version:             0.6
+Version:             0.7
 Synopsis:            Cryptography Primitives sink
 Description:
     A repository of cryptographic primitives.
@@ -83,6 +83,7 @@
                      Crypto.Cipher.TripleDES
                      Crypto.Cipher.Types
                      Crypto.Data.AFIS
+                     Crypto.Data.Padding
                      Crypto.Error
                      Crypto.MAC.Poly1305
                      Crypto.MAC.HMAC
@@ -95,6 +96,7 @@
                      Crypto.Number.Serialize.Internal
                      Crypto.KDF.PBKDF2
                      Crypto.KDF.Scrypt
+                     Crypto.KDF.BCrypt
                      Crypto.Hash
                      Crypto.Hash.IO
                      Crypto.Hash.Algorithms
@@ -166,7 +168,7 @@
                      Crypto.Internal.WordArray
   Build-depends:     base >= 4.3 && < 5
                    , bytestring
-                   , memory >= 0.2
+                   , memory >= 0.8
                    , ghc-prim
   ghc-options:       -Wall -fwarn-tabs -optc-O3
   default-language:  Haskell2010
@@ -241,6 +243,7 @@
   Main-is:           Tests.hs
   Other-modules:     BlockCipher
                      ChaCha
+                     BCrypt
                      Hash
                      Imports
                      KAT_AES.KATCBC
diff --git a/tests/BCrypt.hs b/tests/BCrypt.hs
new file mode 100644
--- /dev/null
+++ b/tests/BCrypt.hs
@@ -0,0 +1,77 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module BCrypt
+    ( tests
+    )
+where
+
+import Crypto.KDF.BCrypt
+import qualified Data.ByteString as B
+import Imports
+
+-- Openwall bcrypt tests, with 2x versions and 0xFF special cases removed.
+expected :: [(ByteString, ByteString)]
+expected =
+    [ ("$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", "U*U")
+    , ("$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", "U*U*")
+    , ("$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", "U*U*U")
+    , ("$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui",
+            "0123456789abcdefghijklmnopqrstuvwxyz\
+            \ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\
+            \chars after 72 are ignored")
+    , ("$2y$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", "\xff\xff\xa3")
+    , ("$2b$05$/OK.fbVrR/bpIqNJ5ianF.CE5elHaaO4EbggVDjb8P19RukzXSM3e", "\xff\xff\xa3")
+    , ("$2y$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", "\xa3")
+    , ("$2a$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", "\xa3")
+    , ("$2b$05$/OK.fbVrR/bpIqNJ5ianF.Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq", "\xa3")
+    , ("$2a$05$/OK.fbVrR/bpIqNJ5ianF.swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6",
+            "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
+            \\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
+            \\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
+            \\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
+            \\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
+            \\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\
+            \chars after 72 are ignored as usual")
+    , ("$2a$05$/OK.fbVrR/bpIqNJ5ianF.R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy",
+            "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
+            \\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
+            \\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
+            \\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
+            \\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\
+            \\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55")
+    , ("$2a$05$/OK.fbVrR/bpIqNJ5ianF.9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe",
+            "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
+            \\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
+            \\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
+            \\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
+            \\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\
+            \\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff")
+    , ("$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", "")
+    , ("$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s.", "")
+    , ("$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye", "")
+    , ("$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW", "")
+    , ("$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO", "")
+    , ("$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe", "a")
+    , ("$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V.", "a")
+    , ("$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS", "a")
+    , ("$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i", "abc")
+    , ("$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm", "abc")
+    , ("$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi", "abc")
+    , ("$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC", "abcdefghijklmnopqrstuvwxyz")
+    ]
+
+makeKATs expected = concatMap maketest (zip3 is passwords hashes)
+  where
+    is :: [Int]
+    is = [1..]
+
+    passwords = map snd expected
+    hashes    = map fst expected
+
+    maketest (i, password, hash) =
+        [ testCase (show i) (assertBool "" (validatePassword password hash))
+        ]
+
+tests = testGroup "bcrypt"
+    [ testGroup "KATs" (makeKATs expected)
+    ]
diff --git a/tests/ChaChaPoly1305.hs b/tests/ChaChaPoly1305.hs
--- a/tests/ChaChaPoly1305.hs
+++ b/tests/ChaChaPoly1305.hs
@@ -20,12 +20,22 @@
 
 tests = testGroup "ChaChaPoly1305"
     [ testCase "V1" runEncrypt
+    , testCase "V1-decrypt" runDecrypt
     ]
   where runEncrypt =
             let ini                 = throwCryptoError $ AEAD.initialize key (throwCryptoError $ AEAD.nonce8 constant iv)
                 afterAAD            = AEAD.finalizeAAD (AEAD.appendAAD aad ini)
-                (out, afterEncrypt) = AEAD.combine plaintext afterAAD
+                (out, afterEncrypt) = AEAD.encrypt plaintext afterAAD
                 outtag              = AEAD.finalize afterEncrypt
              in propertyHoldCase [ eqTest "ciphertext" ciphertext out
+                                 , eqTest "tag" tag (B.convert outtag)
+                                 ]
+
+        runDecrypt =
+            let ini                 = throwCryptoError $ AEAD.initialize key (throwCryptoError $ AEAD.nonce8 constant iv)
+                afterAAD            = AEAD.finalizeAAD (AEAD.appendAAD aad ini)
+                (out, afterDecrypt) = AEAD.decrypt ciphertext afterAAD
+                outtag              = AEAD.finalize afterDecrypt
+             in propertyHoldCase [ eqTest "plaintext" plaintext out
                                  , eqTest "tag" tag (B.convert outtag)
                                  ]
diff --git a/tests/Number.hs b/tests/Number.hs
--- a/tests/Number.hs
+++ b/tests/Number.hs
@@ -20,21 +20,21 @@
     ]
 
 tests = testGroup "number"
-    [ testProperty "num-bits" $ \(Int0_2901 i) ->
+    [ testProperty "num-bits" $ \(Int1_2901 i) ->
         and [ (numBits (2^i-1) == i)
             , (numBits (2^i) == i+1)
             , (numBits (2^i + (2^i-1)) == i+1)
             ]
     , testProperty "num-bits2" $ \(Positive i) ->
         not (i `testBit` numBits i) && (i `testBit` (numBits i - 1))
-    , testProperty "generate-param" $ \testDRG (Int0_2901 bits)  ->
+    , testProperty "generate-param" $ \testDRG (Int1_2901 bits)  ->
         let r = withTestDRG testDRG $ generateParams bits (Just SetHighest) False
          in r >= 0 && numBits r == bits && testBit r (bits-1)
-    , testProperty "generate-param2" $ \testDRG (Int0_2901 m1bits) ->
+    , testProperty "generate-param2" $ \testDRG (Int1_2901 m1bits) ->
         let bits = m1bits + 1 -- make sure minimum is 2
             r = withTestDRG testDRG $ generateParams bits (Just SetTwoHighest) False
          in r >= 0 && numBits r == bits && testBit r (bits-1) && testBit r (bits-2)
-    , testProperty "generate-param-odd" $ \testDRG (Int0_2901 bits) ->
+    , testProperty "generate-param-odd" $ \testDRG (Int1_2901 bits) ->
         let r = withTestDRG testDRG $ generateParams bits Nothing True
          in r >= 0 && odd r
     , testProperty "generate-range" $ \testDRG (Positive range) ->
diff --git a/tests/Padding.hs b/tests/Padding.hs
new file mode 100644
--- /dev/null
+++ b/tests/Padding.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Padding (tests) where
+
+import qualified Data.ByteString as B
+import Imports
+import Crypto.Error
+
+import Crypto.Data.Padding
+
+cases =
+    [ ("abcdef", 8, "abcdef\x02\x02")
+    , ("abcd", 4, "abcd\x04\x04\x04\x04")
+    , ("xyze", 5, "xyze\x01")
+    ]
+
+--instance Arbitrary where
+
+testPad :: Int -> (B.ByteString, Int, B.ByteString) -> TestTree
+testPad n (inp, sz, padded) =
+    testCase (show n) $ propertyHoldCase [ eqTest "padded" padded (pad (PKCS7 sz) inp)
+                                         , eqTest "unpadded" (Just inp) (unpad (PKCS7 sz) padded)
+                                         ]
+
+tests = testGroup "Padding"
+    [ testGroup "Cases" $ map (uncurry testPad) (zip [1..] cases)
+    ]
diff --git a/tests/Poly1305.hs b/tests/Poly1305.hs
--- a/tests/Poly1305.hs
+++ b/tests/Poly1305.hs
@@ -5,6 +5,7 @@
 import qualified Data.ByteString.Char8 as B ()
 
 import Imports
+import Crypto.Error
 
 import qualified Crypto.MAC.Poly1305 as Poly1305
 import qualified Data.ByteArray as B (convert)
@@ -27,7 +28,7 @@
     , testProperty "Chunking" $ \(Chunking chunkLen totalLen) ->
         let key = B.replicate 32 0
             msg = B.pack $ take totalLen $ concat (replicate 10 [1..255])
-         in Poly1305.auth key msg == Poly1305.finalize (foldr (flip Poly1305.update) (Poly1305.initialize key) (chunks chunkLen msg))
+         in Poly1305.auth key msg == Poly1305.finalize (foldr (flip Poly1305.update) (throwCryptoError $ Poly1305.initialize key) (chunks chunkLen msg))
     ]
   where
         chunks i bs
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -4,6 +4,7 @@
 import Imports
 
 import qualified Number
+import qualified BCrypt
 import qualified Hash
 import qualified Poly1305
 import qualified Salsa
@@ -24,10 +25,12 @@
 import qualified KAT_TripleDES
 -- misc --------------------------------
 import qualified KAT_AFIS
+import qualified Padding
 
 tests = testGroup "cryptonite"
     [ Number.tests
     , Hash.tests
+    , Padding.tests
     , testGroup "MAC"
         [ Poly1305.tests
         , KAT_HMAC.tests
@@ -38,6 +41,7 @@
     , testGroup "KDF"
         [ KAT_PBKDF2.tests
         , KAT_Scrypt.tests
+        , BCrypt.tests
         ]
     , testGroup "block-cipher"
         [ KAT_AES.tests
diff --git a/tests/Utils.hs b/tests/Utils.hs
--- a/tests/Utils.hs
+++ b/tests/Utils.hs
@@ -46,8 +46,14 @@
 newtype Int0_2901 = Int0_2901 Int
     deriving (Show,Eq,Ord)
 
+newtype Int1_2901 = Int1_2901 Int
+    deriving (Show,Eq,Ord)
+
 instance Arbitrary Int0_2901 where
     arbitrary = Int0_2901 `fmap` choose (0,2901)
+
+instance Arbitrary Int1_2901 where
+    arbitrary = Int1_2901 `fmap` choose (1,2901)
 
 -- | a integer wrapper with a better range property
 newtype QAInteger = QAInteger { getQAInteger :: Integer }
