diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,17 @@
 # Changelog for `password`
 
+## 3.0.0.0
+
+-   Split the main datatypes module (`Data.Password`) into a separate package: `password-types`.
+    The new package just contains `Password`, `PasswordHash`, `Salt` and their helper functions/instances.
+-   Adjusted entire `password` package to use the `Data.Password.Types` from this new `password-types`.
+    Thanks to [@Vlix](https://github.com/Vlix)
+    [#40](https://github.com/cdepillabout/password/pull/40)
+-   Argon2: fixed the producing and checking of Argon2 hashes.
+    The base64 padding is removed when producing hashes and when
+    checking hashes it will accept hashes with or without padding.
+    [#45](https://github.com/cdepillabout/password/pull/45)
+
 ## 2.1.1.0
 
 -   Fixed `homepage` links in the `.cabal` files.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,13 +1,12 @@
 # password
 
-[![Build Status](https://secure.travis-ci.org/cdepillabout/password.svg)](http://travis-ci.org/cdepillabout/password)
+[![Build Status](https://github.com/cdepillabout/password/workflows/password/badge.svg)](http://github.com/cdepillabout/password)
 [![Hackage](https://img.shields.io/hackage/v/password.svg)](https://hackage.haskell.org/package/password)
 [![Stackage LTS](http://stackage.org/package/password/badge/lts)](http://stackage.org/lts/package/password)
 [![Stackage Nightly](http://stackage.org/package/password/badge/nightly)](http://stackage.org/nightly/package/password)
 [![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](./LICENSE)
 
-This library provides datatypes and functions for working with passwords and
-password hashes in Haskell.
+This library provides functions for working with passwords and password hashes in Haskell.
 
 Currently supports the following algorithms:
 
diff --git a/password.cabal b/password.cabal
--- a/password.cabal
+++ b/password.cabal
@@ -1,10 +1,39 @@
 cabal-version: 1.12
 
 name:           password
-version:        2.1.1.0
+version:        3.0.0.0
 category:       Data
 synopsis:       Hashing and checking of passwords
-description:    A library providing functionality for working with plain-text and hashed passwords with different types of algorithms.
+description:
+    A library providing functionality for working with plain-text and hashed passwords
+    with different types of algorithms.
+    .
+    == API
+    .
+    Every supported hashing algorithm has its own module (e.g. "Data.Password.Bcrypt")
+    which exports its own @hashPassword@ and @checkPassword@ functions, as well as all the
+    types and functions in this module. If you are not sure about the specifics of an
+    algorithm you want to use, you can rest assured that by using the @hashPassword@ function
+    of the respective algorithm you are not making any big mistakes, security-wise.
+    .
+    Of course, if you know what you're doing and you want more fine-grained control
+    over the hashing function, you can adjust it using the @hashPasswordWithParams@
+    function of the respective algorithm.
+    .
+    == Algorithms
+    .
+    Generally, the most "secure" algorithm is believed to be @Argon2@, then @scrypt@,
+    then @bcrypt@, and lastly @PBKDF2@.
+    @bcrypt@ and @PBKDF2@ are the most established algorithms, so they have been tried and
+    tested, though they both lack a memory cost, and therefore have a greater vulnerability
+    to specialized hardware attacks.
+    .
+    When choosing an algorithm, and you have no idea which to pick, just go for @bcrypt@ if
+    your password does not need the highest security possible.
+    It's still a fine way for hashing passwords, and the cost is easily adjustable if needed.
+    If your needs do require stronger protection, you should find someone who can advise you
+    on this topic. (And if you're already knowledgeable enough, you know what to do)
+
 homepage:       https://github.com/cdepillabout/password/tree/master/password#readme
 bug-reports:    https://github.com/cdepillabout/password/issues
 author:         Dennis Gosnell, Felix Paulusma
@@ -31,7 +60,6 @@
   hs-source-dirs:
       src
   exposed-modules:
-      Data.Password
       Data.Password.Argon2
       Data.Password.Bcrypt
       Data.Password.PBKDF2
@@ -44,8 +72,9 @@
       base        >= 4.9      && < 5
     , base64      >= 0.3      && < 0.5
     , bytestring  >= 0.10.8.1 && < 0.11
-    , cryptonite  >= 0.15.1   && < 0.28
+    , cryptonite  >= 0.15.1   && < 0.29
     , memory      >= 0.14     && < 0.16
+    , password-types             < 2
     , template-haskell
     , text        >= 1.2.2    && < 1.3
   ghc-options:
@@ -94,6 +123,7 @@
   build-depends:
       base >=4.9 && <5
     , password
+    , password-types
     , bytestring
     , cryptonite
     , memory
diff --git a/src/Data/Password.hs b/src/Data/Password.hs
deleted file mode 100644
--- a/src/Data/Password.hs
+++ /dev/null
@@ -1,88 +0,0 @@
-{-|
-Module      : Data.Password
-Copyright   : (c) Dennis Gosnell, 2019; Felix Paulusma, 2020
-License     : BSD-style (see LICENSE file)
-Maintainer  : cdep.illabout@gmail.com
-Stability   : experimental
-Portability : POSIX
-
-This library provides an easy way for interacting with passwords from Haskell.
-It provides the types 'Password' and 'PasswordHash', which correspond to plain-text and
-hashed passwords.
-
-== API
-
-Every supported hashing algorithm has its own module (e.g. "Data.Password.Bcrypt")
-which exports its own @hashPassword@ and @checkPassword@ functions, as well as all the
-types and functions in this module. If you are not sure about the specifics of an
-algorithm you want to use, you can rest assured that by using the @hashPassword@ function
-of the respective algorithm you are not making any big mistakes, security-wise.
-
-Of course, if you know what you're doing and you want more fine-grained control
-over the hashing function, you can adjust it using the @hashPasswordWithParams@
-function of the respective algorithm.
-
-== Algorithms
-
-Generally, the most "secure" algorithm is believed to be @'Data.Password.Argon2.Argon2'@,
-then @'Data.Password.Scrypt.Scrypt'@, then @'Data.Password.Bcrypt.Bcrypt'@, and lastly
-@'Data.Password.PBKDF2.PBKDF2'@. @'Data.Password.Bcrypt.Bcrypt'@
-and @'Data.Password.PBKDF2.PBKDF2'@ are the most established algorithms, so they have
-been tried and tested, though they both lack a memory cost, and therefore have a
-greater vulnerability to specialized hardware attacks.
-
-When choosing an algorithm, and you have no idea which to pick, just go for
-@'Data.Password.Bcrypt.Bcrypt'@ if your password does not need the highest security possible.
-It's still a fine way for hashing passwords, and the cost is easily adjustable if needed.
-If your needs do require stronger protection, you should find someone who can advise you
-on this topic. (And if you're already knowledgeable enough, you know what to do)
-
-== Special instances
-
-The real benefit of this module is that there is an accompanying
-<http://hackage.haskell.org/package/password-instances password-instances>
-package that provides canonical typeclass instances for
-'Password' and 'PasswordHash' for many common typeclasses, like
-<http://hackage.haskell.org/package/aeson/docs/Data-Aeson.html#t:FromJSON FromJSON> from
-<http://hackage.haskell.org/package/aeson aeson>,
-<http://hackage.haskell.org/package/persistent/docs/Database-Persist-Class.html#t:PersistField PersistField>
-from
-<http://hackage.haskell.org/package/persistent persistent>, etc.
-
-See the <http://hackage.haskell.org/package/password-instances password-instances> package for more information.
--}
-
-module Data.Password (
-    -- * Plain-text Password
-    Password
-  , mkPassword
-    -- * Password Hashing
-  , PasswordHash(..)
-  , PasswordCheck(..)
-  , Salt(..)
-  , newSalt
-    -- * Unsafe debugging function to show a Password
-  , unsafeShowPassword
-  ) where
-
-import Data.Password.Internal
-
--- TODO: Create code for checking that plain-text passwords conform to some sort of
--- password policy.
-
--- data PasswordPolicy = PasswordPolicy
---   { passPolicyLength :: Int
---   , passPolicyCharReqs :: [PolicyCharReq]
---   , passPolicyCharSet :: PolicyCharSet
---   }
-
--- -- | Character requirements for a password policy.
--- data PolicyCharReq
---   = PolicyCharReqUpper Int
---   -- ^ A password requires at least 'Int' upper-case characters.
---   | PolicyCharReqLower Int
---   -- ^ A password requires at least 'Int' lower-case characters.
---   | PolicyCharReqSpecial Int
---   -- ^ A password requires at least 'Int' special characters
-
--- data PolicyCharSet = PolicyCharSetAscii
diff --git a/src/Data/Password/Argon2.hs b/src/Data/Password/Argon2.hs
--- a/src/Data/Password/Argon2.hs
+++ b/src/Data/Password/Argon2.hs
@@ -70,29 +70,36 @@
   ) where
 
 import Control.Monad (guard)
-import Control.Monad.IO.Class (MonadIO(liftIO))
+import Control.Monad.IO.Class (MonadIO (liftIO))
 import Crypto.Error (throwCryptoError)
-import Crypto.KDF.Argon2 as Argon2
+import Crypto.KDF.Argon2 as Argon2 (Options (..), Variant (..), Version (..), hash)
 import Data.ByteArray (Bytes, constEq, convert)
-import Data.ByteString (ByteString)
+import Data.ByteString as B (ByteString, length)
 import Data.ByteString.Base64 (encodeBase64)
-import qualified Data.ByteString.Char8 as C8 (length)
 import Data.Maybe (fromMaybe)
-#if! MIN_VERSION_base(4,13,0)
+#if !MIN_VERSION_base(4,13,0)
 import Data.Semigroup ((<>))
 #endif
 import Data.Text (Text)
 import qualified Data.Text as T (intercalate, length, split, splitAt)
 import Data.Word (Word32)
 
-import Data.Password (
-         PasswordCheck(..)
-       , PasswordHash(..)
-       , Salt(..)
-       , mkPassword
-       , unsafeShowPassword
-       )
-import Data.Password.Internal (Password(..), from64, readT, showT, toBytes)
+import Data.Password.Internal (
+    PasswordCheck (..),
+    from64,
+    readT,
+    showT,
+    toBytes,
+    unsafePad64,
+    unsafeRemovePad64,
+ )
+import Data.Password.Types (
+    Password,
+    PasswordHash (..),
+    Salt (..),
+    mkPassword,
+    unsafeShowPassword,
+ )
 import qualified Data.Password.Internal (newSalt)
 
 
@@ -107,13 +114,13 @@
 --
 -- Import needed libraries.
 --
--- >>> import Data.Password
+-- >>> import Data.Password.Types
 -- >>> import Data.ByteString (pack)
 -- >>> import Test.QuickCheck (Arbitrary(arbitrary), Blind(Blind), vector)
 -- >>> import Test.QuickCheck.Instances.Text ()
 --
 -- >>> instance Arbitrary (Salt a) where arbitrary = Salt . pack <$> vector 16
--- >>> instance Arbitrary Password where arbitrary = fmap Password arbitrary
+-- >>> instance Arbitrary Password where arbitrary = fmap mkPassword arbitrary
 -- >>> let testParams = defaultParams {argon2TimeCost = 1}
 -- >>> let salt = Salt "abcdefghijklmnop"
 
@@ -183,7 +190,7 @@
 --
 -- >>> let salt = Salt "abcdefghijklmnop"
 -- >>> hashPasswordWithSalt defaultParams salt (mkPassword "foobar")
--- PasswordHash {unPasswordHash = "$argon2id$v=19$m=65536,t=2,p=1$YWJjZGVmZ2hpamtsbW5vcA==$BztdyfEefG5V18ZNlztPrfZaU5duVFKZiI6dJeWht0o="}
+-- PasswordHash {unPasswordHash = "$argon2id$v=19$m=65536,t=2,p=1$YWJjZGVmZ2hpamtsbW5vcA$BztdyfEefG5V18ZNlztPrfZaU5duVFKZiI6dJeWht0o"}
 --
 -- (Note that we use an explicit 'Salt' in the example above.  This is so that the
 -- example is reproducible, but in general you should use 'hashPassword'. 'hashPassword'
@@ -194,10 +201,12 @@
     [ variantToLetter argon2Variant
     , "v=" <> versionToNum argon2Version
     , parameters
-    , encodeBase64 salt
-    , encodeBase64 key
+    , encodeWithoutPadding salt
+    , encodeWithoutPadding key
     ]
   where
+    encodeWithoutPadding bs =
+        unsafeRemovePad64 (B.length bs) $ encodeBase64 bs
     parameters = T.intercalate ","
         [ "m=" <> showT argon2MemoryCost
         , "t=" <> showT argon2TimeCost
@@ -207,11 +216,15 @@
 
 -- | Only for internal use
 hashPasswordWithSalt' :: Argon2Params -> Salt Argon2 -> Password -> ByteString
-hashPasswordWithSalt' Argon2Params{..} (Salt salt) (Password pass) =
+hashPasswordWithSalt' Argon2Params{..} (Salt salt) pass =
     convert (argon2Hash :: Bytes)
   where
     argon2Hash = throwCryptoError $
-        Argon2.hash options (toBytes pass) (convert salt :: Bytes) $ fromIntegral argon2OutputLength
+        Argon2.hash
+            options
+            (toBytes $ unsafeShowPassword pass)
+            (convert salt :: Bytes)
+            $ fromIntegral argon2OutputLength
     options = Argon2.Options {
         iterations = argon2TimeCost,
         memory = argon2MemoryCost,
@@ -264,7 +277,7 @@
 checkPassword pass (PasswordHash passHash) =
   fromMaybe PasswordCheckFail $ do
     let paramList = T.split (== '$') passHash
-    guard $ length paramList == 6
+    guard $ Prelude.length paramList == 6
     let [ _,
           variantT,
           versionT,
@@ -274,9 +287,9 @@
     argon2Variant <- parseVariant variantT
     argon2Version <- parseVersion versionT
     (argon2MemoryCost, argon2TimeCost, argon2Parallelism) <- parseParameters parametersT
-    salt <- from64 salt64
-    hashedKey <- from64 hashedKey64
-    let argon2OutputLength = fromIntegral $ C8.length hashedKey -- only here because of warnings
+    salt <- from64 $ unsafePad64 salt64
+    hashedKey <- from64 $ unsafePad64 hashedKey64
+    let argon2OutputLength = fromIntegral $ B.length hashedKey -- only here because of warnings
         producedKey = hashPasswordWithSalt' Argon2Params{..} (Salt salt) pass
     guard $ hashedKey `constEq` producedKey
     return PasswordCheckSuccess
@@ -286,7 +299,7 @@
     parseVersion = splitMaybe "v=" numToVersion
     parseParameters params = do
         let ps = T.split (== ',') params
-        guard $ length ps == 3
+        guard $ Prelude.length ps == 3
         go ps (Nothing, Nothing, Nothing)
       where
         go [] (Just m, Just t, Just p) = Just (m, t, p)
diff --git a/src/Data/Password/Bcrypt.hs b/src/Data/Password/Bcrypt.hs
--- a/src/Data/Password/Bcrypt.hs
+++ b/src/Data/Password/Bcrypt.hs
@@ -60,17 +60,21 @@
   ) where
 
 import Control.Monad.IO.Class (MonadIO(liftIO))
-import Crypto.KDF.BCrypt as Bcrypt hiding (hashPassword)
+import Crypto.KDF.BCrypt as Bcrypt (bcrypt, validatePassword)
 import Data.ByteArray (Bytes, convert)
 
-import Data.Password (
-         PasswordCheck(..)
-       , PasswordHash(..)
-       , Salt(..)
-       , mkPassword
-       , unsafeShowPassword
-       )
-import Data.Password.Internal (Password(..), fromBytes, toBytes)
+import Data.Password.Types (
+    Password
+  , PasswordHash(..)
+  , mkPassword
+  , unsafeShowPassword
+  , Salt(..)
+  )
+import Data.Password.Internal (
+    PasswordCheck(..)
+  , fromBytes
+  , toBytes
+  )
 import qualified Data.Password.Internal (newSalt)
 
 
@@ -85,13 +89,13 @@
 --
 -- Import needed libraries.
 --
--- >>> import Data.Password
+-- >>> import Data.Password.Types
 -- >>> import Data.ByteString (pack)
 -- >>> import Test.QuickCheck (Arbitrary(arbitrary), Blind(Blind), vector)
 -- >>> import Test.QuickCheck.Instances.Text ()
 --
 -- >>> instance Arbitrary (Salt a) where arbitrary = Salt . pack <$> vector 16
--- >>> instance Arbitrary Password where arbitrary = fmap Password arbitrary
+-- >>> instance Arbitrary Password where arbitrary = fmap mkPassword arbitrary
 -- >>> let salt = Salt "abcdefghijklmnop"
 
 -- -- >>> instance Arbitrary (PasswordHash Bcrypt) where arbitrary = hashPasswordWithSalt 8 <$> arbitrary <*> arbitrary
@@ -126,8 +130,11 @@
   -> Salt Bcrypt -- ^ The salt. MUST be 16 bytes in length or an error will be raised.
   -> Password -- ^ The password to be hashed.
   -> PasswordHash Bcrypt -- ^ The bcrypt hash in standard format.
-hashPasswordWithSalt cost (Salt salt) (Password pass) =
-    let hash = Bcrypt.bcrypt cost (convert salt :: Bytes) (toBytes pass)
+hashPasswordWithSalt cost (Salt salt) pass =
+    let hash = Bcrypt.bcrypt
+            cost
+            (convert salt :: Bytes)
+            (toBytes $ unsafeShowPassword pass)
     in PasswordHash $ fromBytes hash
 
 -- | Hash a password using the /bcrypt/ algorithm with the given cost.
@@ -169,8 +176,10 @@
 --
 -- prop> \(Blind badpass) -> let correctPasswordHash = hashPasswordWithSalt 8 salt "foobar" in checkPassword badpass correctPasswordHash == PasswordCheckFail
 checkPassword :: Password -> PasswordHash Bcrypt -> PasswordCheck
-checkPassword (Password pass) (PasswordHash passHash) =
-    if Bcrypt.validatePassword (toBytes pass) (toBytes passHash)
+checkPassword pass (PasswordHash passHash) =
+    if Bcrypt.validatePassword
+        (toBytes $ unsafeShowPassword pass)
+        (toBytes passHash)
       then PasswordCheckSuccess
       else PasswordCheckFail
 
diff --git a/src/Data/Password/Internal.hs b/src/Data/Password/Internal.hs
--- a/src/Data/Password/Internal.hs
+++ b/src/Data/Password/Internal.hs
@@ -1,5 +1,5 @@
-{-# LANGUAGE ExplicitForAll #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-|
 Module      : Data.Password.Internal
 Copyright   : (c) Dennis Gosnell, 2019; Felix Paulusma, 2020
@@ -10,72 +10,40 @@
 -}
 
 module Data.Password.Internal (
-    -- * Global types
-    Password(..)
-  , mkPassword
-  , PasswordHash(..)
-  , PasswordCheck(..)
-  , Salt(..)
+  -- * Global types
+    PasswordCheck(..)
   , newSalt
-  -- * Unsafe function
-  , unsafeShowPassword
   -- * Utility
   , toBytes
   , fromBytes
   , from64
+  , unsafePad64
+  , unsafeRemovePad64
   , readT
   , showT
   ) where
 
 import Control.Monad.IO.Class (MonadIO(liftIO))
 import Crypto.Random (getRandomBytes)
-import Data.ByteArray (Bytes, constEq, convert)
+import Data.ByteArray (Bytes, convert)
 import Data.ByteString (ByteString)
-import Data.Function (on)
 import Data.ByteString.Base64 (decodeBase64)
-import Data.String (IsString(..))
-import Data.Text as T (Text, pack, unpack)
+#if !MIN_VERSION_base(4,13,0)
+import Data.Semigroup ((<>))
+#endif
+import Data.Text as T (
+    Text,
+    dropEnd,
+    length,
+    pack,
+    replicate,
+    unpack,
+ )
+import Data.Password.Types (Salt(..))
 import Data.Text.Encoding (decodeUtf8, encodeUtf8)
 import Text.Read (readMaybe)
 
 
--- | A plain-text password.
---
--- This represents a plain-text password that has /NOT/ been hashed.
---
--- You should be careful with 'Password'. Make sure not to write it to logs or
--- store it in a database.
---
--- You can construct a 'Password' by using the 'mkPassword' function or as literal
--- strings together with the OverloadedStrings pragma (or manually, by using
--- 'fromString' on a 'String'). Alternatively, you could also use some of the
--- instances in the <http://hackage.haskell.org/package/password-instances password-instances>
--- library.
-newtype Password = Password Text
-  deriving (IsString)
-
--- | CAREFUL: 'Show'-ing a 'Password' will always print @"**PASSWORD**"@
---
--- >>> show ("hello" :: Password)
--- "**PASSWORD**"
---
--- @since 1.0.0.0
-instance Show Password where
- show _ = "**PASSWORD**"
-
--- | Construct a 'Password'
---
--- @since 1.0.0.0
-mkPassword :: Text -> Password
-mkPassword = Password
-{-# INLINE mkPassword #-}
-
--- | A salt used by a hashing algorithm.
---
--- @since 2.0.0.0
-newtype Salt a = Salt ByteString
-  deriving (Eq, Show)
-
 -- | Generate a random x-byte-long salt.
 --
 -- @since 2.0.0.0
@@ -83,27 +51,6 @@
 newSalt i = liftIO $ Salt <$> getRandomBytes i
 {-# INLINE newSalt #-}
 
--- | This is an unsafe function that shows a password in plain-text.
---
--- >>> unsafeShowPassword ("foobar" :: Password)
--- "foobar"
---
--- You should generally not use this function.
-unsafeShowPassword :: Password -> Text
-unsafeShowPassword (Password pass) = pass
-{-# INLINE unsafeShowPassword #-}
-
--- | A hashed password.
---
--- This represents a password that has been put through a hashing function.
--- The hashed password can be stored in a database.
-newtype PasswordHash a = PasswordHash
-  { unPasswordHash :: Text
-  } deriving (Ord, Read, Show)
-
-instance Eq (PasswordHash a)  where
-  (==) = constEq `on` encodeUtf8 . unPasswordHash
-
 -- | The result of checking a password against a hashed version. This is
 -- returned by the @checkPassword@ functions.
 data PasswordCheck
@@ -133,11 +80,33 @@
 {-# INLINE from64 #-}
 
 -- | Same as 'read' but works on 'Text'
-readT :: forall a. Read a => Text -> Maybe a
+readT :: Read a => Text -> Maybe a
 readT = readMaybe . T.unpack
 {-# INLINE readT #-}
 
 -- | Same as 'show' but works on 'Text'
-showT :: forall a. Show a => a -> Text
+showT :: Show a => a -> Text
 showT = T.pack . show
 {-# INLINE showT #-}
+
+-- | (UNSAFE) Pad a base64 text to "length `rem` 4 == 0" with "="
+unsafePad64 :: Text -> Text
+unsafePad64 t
+    | remains == 0 = t
+    | otherwise = t <> pad
+  where
+    remains = T.length t `rem` 4
+    pad = T.replicate (4 - remains) "="
+
+-- | (UNSAFE) Removes the "=" padding from a base64 text
+-- given the length of the original bytestring.
+unsafeRemovePad64 :: Int -> Text -> Text
+unsafeRemovePad64 bsLen = T.dropEnd drops
+  where
+    drops = case bsLen `rem` 3 of
+        -- 1 extra byte results in 2 characters (4 - 2 = 2)
+        1 -> 2
+        -- 2 extra bytes results in 3 characters (4 - 3 = 1)
+        2 -> 1
+        -- This will just be 0
+        other -> other
diff --git a/src/Data/Password/PBKDF2.hs b/src/Data/Password/PBKDF2.hs
--- a/src/Data/Password/PBKDF2.hs
+++ b/src/Data/Password/PBKDF2.hs
@@ -80,14 +80,19 @@
 import qualified Data.Text as T (intercalate, pack, split, stripPrefix)
 import Data.Word (Word32)
 
-import Data.Password (
-         PasswordCheck(..)
-       , PasswordHash(..)
-       , Salt(..)
-       , mkPassword
-       , unsafeShowPassword
-       )
-import Data.Password.Internal (Password(..), from64, readT, toBytes)
+import Data.Password.Types (
+    Password
+  , PasswordHash(..)
+  , mkPassword
+  , unsafeShowPassword
+  , Salt(..)
+  )
+import Data.Password.Internal (
+    PasswordCheck(..)
+  , from64
+  , readT
+  , toBytes
+  )
 import qualified Data.Password.Internal (newSalt)
 
 
@@ -102,13 +107,13 @@
 --
 -- Import needed libraries.
 --
--- >>> import Data.Password
+-- >>> import Data.Password.Types
 -- >>> import Data.ByteString (pack)
 -- >>> import Test.QuickCheck (Arbitrary(arbitrary), Blind(Blind), vector)
 -- >>> import Test.QuickCheck.Instances.Text ()
 --
 -- >>> instance Arbitrary (Salt a) where arbitrary = Salt . pack <$> vector 16
--- >>> instance Arbitrary Password where arbitrary = fmap Password arbitrary
+-- >>> instance Arbitrary Password where arbitrary = fmap mkPassword arbitrary
 -- >>> let testParams = defaultParams{ pbkdf2Iterations = 5000 }
 -- >>> let salt = Salt "abcdefghijklmnop"
 
@@ -185,10 +190,14 @@
 
 -- | Only for internal use
 hashPasswordWithSalt' :: PBKDF2Params -> Salt PBKDF2 -> Password -> ByteString
-hashPasswordWithSalt' PBKDF2Params{..} (Salt salt) (Password pass) =
+hashPasswordWithSalt' PBKDF2Params{..} (Salt salt) pass =
     convert (pbkdf2Hash :: Bytes)
   where
-    pbkdf2Hash = algToFunc pbkdf2Algorithm params (toBytes pass) (convert salt :: Bytes)
+    pbkdf2Hash = algToFunc
+        pbkdf2Algorithm
+        params
+        (toBytes $ unsafeShowPassword pass)
+        (convert salt :: Bytes)
     params = PBKDF2.Parameters {
         PBKDF2.iterCounts = fromIntegral pbkdf2Iterations,
         PBKDF2.outputLength = fromIntegral $ maxOutputLength pbkdf2Algorithm pbkdf2OutputLength
diff --git a/src/Data/Password/Scrypt.hs b/src/Data/Password/Scrypt.hs
--- a/src/Data/Password/Scrypt.hs
+++ b/src/Data/Password/Scrypt.hs
@@ -63,7 +63,7 @@
 
 import Control.Monad (guard)
 import Control.Monad.IO.Class (MonadIO(liftIO))
-import Crypto.KDF.Scrypt as Scrypt
+import Crypto.KDF.Scrypt as Scrypt (Parameters(..), generate)
 import Data.ByteArray (Bytes, constEq, convert)
 import Data.ByteString (ByteString)
 import Data.ByteString.Base64 (encodeBase64)
@@ -72,14 +72,20 @@
 import qualified Data.Text as T (intercalate, split)
 import Data.Word (Word32)
 
-import Data.Password (
-         PasswordCheck(..)
-       , PasswordHash(..)
-       , Salt(..)
-       , mkPassword
-       , unsafeShowPassword
-       )
-import Data.Password.Internal (Password(..), from64, readT, showT, toBytes)
+import Data.Password.Types (
+    Password
+  , PasswordHash(..)
+  , mkPassword
+  , unsafeShowPassword
+  , Salt(..)
+  )
+import Data.Password.Internal (
+    PasswordCheck(..)
+  , from64
+  , readT
+  , showT
+  , toBytes
+  )
 import qualified Data.Password.Internal (newSalt)
 
 -- | Phantom type for __scrypt__
@@ -93,13 +99,13 @@
 --
 -- Import needed libraries.
 --
--- >>> import Data.Password
+-- >>> import Data.Password.Types
 -- >>> import Data.ByteString (pack)
 -- >>> import Test.QuickCheck (Arbitrary(arbitrary), Blind(Blind), vector)
 -- >>> import Test.QuickCheck.Instances.Text ()
 --
 -- >>> instance Arbitrary (Salt a) where arbitrary = Salt . pack <$> vector 32
--- >>> instance Arbitrary Password where arbitrary = fmap Password arbitrary
+-- >>> instance Arbitrary Password where arbitrary = fmap mkPassword arbitrary
 -- >>> let salt = Salt "abcdefghijklmnopqrstuvwxyz012345"
 -- >>> let testParams = defaultParams {scryptRounds = 10}
 
@@ -181,10 +187,13 @@
 
 -- | Only for internal use
 hashPasswordWithSalt' :: ScryptParams -> Salt Scrypt -> Password -> ByteString
-hashPasswordWithSalt' ScryptParams{..} (Salt salt) (Password pass) =
+hashPasswordWithSalt' ScryptParams{..} (Salt salt) pass =
     convert (scryptHash :: Bytes)
   where
-    scryptHash = Scrypt.generate params (toBytes pass) (convert salt :: Bytes)
+    scryptHash = Scrypt.generate
+        params
+        (toBytes $ unsafeShowPassword pass)
+        (convert salt :: Bytes)
     params = Scrypt.Parameters {
         n = 2 ^ scryptRounds,
         r = fromIntegral scryptBlockSize,
diff --git a/src/Data/Password/Validate.hs b/src/Data/Password/Validate.hs
--- a/src/Data/Password/Validate.hs
+++ b/src/Data/Password/Validate.hs
@@ -204,22 +204,19 @@
 import Data.Function (on)
 import Data.List (foldl')
 
-#if !MIN_VERSION_base(4,13,0)
-import Data.Semigroup ((<>))
-#endif
 import Data.Text (Text)
 import qualified Data.Text as T
 import Language.Haskell.TH (Exp, Q, appE)
 import Language.Haskell.TH.Syntax (Lift (..))
 
-import Data.Password.Internal (Password (..))
+import Data.Password.Types (Password, unsafeShowPassword)
 
 -- $setup
 -- >>> :set -XOverloadedStrings
 --
 -- Import needed libraries.
 --
--- >>> import Data.Password
+-- >>> import Data.Password.Types
 
 -- | Set of policies used to validate a 'Password'.
 --
@@ -471,12 +468,13 @@
 --
 -- @since 2.1.0.0
 validatePassword :: ValidPasswordPolicy -> Password -> ValidationResult
-validatePassword (VPP PasswordPolicy{..}) (Password password) =
+validatePassword (VPP PasswordPolicy{..}) pass =
   case validationFailures of
     [] -> ValidPassword
     _:_ -> InvalidPassword validationFailures
 
   where
+    password = unsafeShowPassword pass
     validationFailures = mconcat
         [ isTooShort
         , isTooLong
diff --git a/test/tasty/Argon2.hs b/test/tasty/Argon2.hs
--- a/test/tasty/Argon2.hs
+++ b/test/tasty/Argon2.hs
@@ -1,7 +1,8 @@
+{-# LANGUAGE OverloadedStrings #-}
 module Argon2 where
 
 import Test.Tasty
-import Test.QuickCheck.Instances.Text ()
+import Test.Tasty.HUnit (assertBool, assertEqual, testCase)
 
 import Data.Password.Argon2
 
@@ -10,13 +11,15 @@
 
 testArgon2 :: TestTree
 testArgon2 = testGroup "Argon2"
-  [ testCorrectPassword "Argon2 (hashPassword)" hashFast checkPassword
+  [ referenceTest
+  , testCorrectPassword "Argon2 (hashPassword)" hashFast checkPassword
   , testIncorrectPassword "Argon2 (hashPassword) fail" hashFast checkPassword
   , testWithSalt "Argon2 (hashPasswordWithSalt)"
                  (hashPasswordWithSalt fastParams)
                  checkPassword
   , testWithParams "Argon2 (Argon2i)" $ fastParams{ argon2Variant = Argon2i }
   , testWithParams "Argon2 (Argon2d)" $ fastParams{ argon2Variant = Argon2d }
+  , paddingTests
   ]
   where
     testWithParams s params =
@@ -27,3 +30,35 @@
         argon2MemoryCost = 2 ^ (8 :: Int),
         argon2TimeCost = 1
       }
+
+paddingTests :: TestTree
+paddingTests = testGroup "Padding"
+    [ testCase "with padding" $
+        assertBool "Bad hash" $ checkPassword pass hashWithPadding == PasswordCheckSuccess
+    , testCase "without padding" $
+        assertBool "Bad hash" $ checkPassword pass hashWithoutPadding == PasswordCheckSuccess
+    ]
+
+pass :: Password
+pass = "foobar"
+
+-- Hashed password ("foobar") with salt ("abcdefghijklmnop")
+hashWithPadding, hashWithoutPadding :: PasswordHash Argon2
+hashWithPadding    = PasswordHash "$argon2id$v=19$m=65536,t=2,p=1$YWJjZGVmZ2hpamtsbW5vcA==$BztdyfEefG5V18ZNlztPrfZaU5duVFKZiI6dJeWht0o="
+hashWithoutPadding = PasswordHash "$argon2id$v=19$m=65536,t=2,p=1$YWJjZGVmZ2hpamtsbW5vcA$BztdyfEefG5V18ZNlztPrfZaU5duVFKZiI6dJeWht0o"
+
+-- Reference check using the Command-line Utility output example
+-- from: https://github.com/P-H-C/phc-winner-argon2
+referenceTest :: TestTree
+referenceTest = testCase "PHC Argon2 reference" $
+    assertEqual "output hash is wrong" expected $
+        hashPasswordWithSalt params salt pwd
+  where
+    expected = PasswordHash "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG"
+    salt = Salt "somesalt"
+    pwd = mkPassword "password"
+    params = defaultParams {
+        argon2Variant = Argon2i,
+        argon2Parallelism = 4,
+        argon2OutputLength = 24
+    }
diff --git a/test/tasty/Internal.hs b/test/tasty/Internal.hs
--- a/test/tasty/Internal.hs
+++ b/test/tasty/Internal.hs
@@ -3,11 +3,12 @@
 module Internal where
 
 import Data.ByteArray (pack)
-import Test.Tasty
+import Test.Tasty (TestTree)
 import Test.Tasty.QuickCheck
 import Test.QuickCheck.Instances.Text ()
 
-import Data.Password
+import Data.Password.Types (mkPassword, Password, PasswordHash)
+import Data.Password.Bcrypt (PasswordCheck(..), Salt(..))
 
 
 testCorrectPassword :: String
diff --git a/test/tasty/Scrypt.hs b/test/tasty/Scrypt.hs
--- a/test/tasty/Scrypt.hs
+++ b/test/tasty/Scrypt.hs
@@ -8,7 +8,7 @@
 import Test.QuickCheck.Instances.Text ()
 
 import qualified Crypto.Scrypt as Scrypt
-import Data.Password
+import Data.Password.Types
 import Data.Password.Scrypt
 
 import Internal
diff --git a/test/tasty/Spec.hs b/test/tasty/Spec.hs
--- a/test/tasty/Spec.hs
+++ b/test/tasty/Spec.hs
@@ -2,13 +2,13 @@
 import Test.Tasty.QuickCheck
 import Test.Tasty.Runners (NumThreads(..))
 
-import Data.Password
+import Data.Password.Types
 
-import Argon2
-import Bcrypt
-import PBKDF2
-import Scrypt
-import Validate
+import Argon2 (testArgon2)
+import Bcrypt (testBcrypt)
+import PBKDF2 (testPBKDF2)
+import Scrypt (testScrypt)
+import Validate (testValidate)
 
 main :: IO ()
 main = defaultMain $ localOption (NumThreads 1) $
diff --git a/test/tasty/Validate.hs b/test/tasty/Validate.hs
--- a/test/tasty/Validate.hs
+++ b/test/tasty/Validate.hs
@@ -22,7 +22,7 @@
 import Data.Semigroup ((<>))
 #endif
 
-import Data.Password (Password, mkPassword)
+import Data.Password.Types (Password, mkPassword)
 import Data.Password.Validate hiding (ValidationResult(..))
 import qualified Data.Password.Validate as V
 
