diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,7 @@
+# Changelog for `password-types`
+
+## 1.0.0.0
+
+-   Split out this package from the `password` package to not saddle up
+    users with a `cryptonite` dependency, when they might only want to
+    use password data types.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) Dennis Gosnell, 2019; Felix Paulusma, 2020
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Dennis Gosnell, Felix Paulusma nor the names
+      of other contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,12 @@
+# password-types
+
+[![Build Status](https://github.com/cdepillabout/password/workflows/password/badge.svg)](http://github.com/cdepillabout/password)
+[![Hackage](https://img.shields.io/hackage/v/password-types.svg)](https://hackage.haskell.org/package/password-types)
+[![Stackage LTS](http://stackage.org/package/password-types/badge/lts)](http://stackage.org/lts/package/password-types)
+[![Stackage Nightly](http://stackage.org/package/password-types/badge/nightly)](http://stackage.org/nightly/package/password-types)
+[![BSD3 license](https://img.shields.io/badge/license-BSD3-blue.svg)](./LICENSE)
+
+This library provides datatypes for working with passwords and password hashes in Haskell.
+
+Also, see the [password](https://hackage.haskell.org/package/password) package for
+functions to hash and check passwords.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE CPP #-}
+{-# OPTIONS_GHC -Wall #-}
+module Main (main) where
+
+#ifndef MIN_VERSION_cabal_doctest
+#define MIN_VERSION_cabal_doctest(x,y,z) 0
+#endif
+
+#if MIN_VERSION_cabal_doctest(1,0,0)
+
+import Distribution.Extra.Doctest ( defaultMainWithDoctests )
+main :: IO ()
+main = defaultMainWithDoctests "doctests"
+
+#else
+
+#ifdef MIN_VERSION_Cabal
+-- If the macro is defined, we have new cabal-install,
+-- but for some reason we don't have cabal-doctest in package-db
+--
+-- Probably we are running cabal sdist, when otherwise using new-build
+-- workflow
+#warning You are configuring this package without cabal-doctest installed. \
+         The doctests test-suite will not work as a result. \
+         To fix this, install cabal-doctest before configuring.
+#endif
+
+import Distribution.Simple
+
+main :: IO ()
+main = defaultMain
+
+#endif
diff --git a/password-types.cabal b/password-types.cabal
new file mode 100644
--- /dev/null
+++ b/password-types.cabal
@@ -0,0 +1,86 @@
+cabal-version: 1.12
+
+name:           password-types
+version:        1.0.0.0
+category:       Data
+synopsis:       Types for handling passwords
+description:    A library providing types for working with plain-text and hashed passwords.
+homepage:       https://github.com/cdepillabout/password/tree/master/password-types#readme
+bug-reports:    https://github.com/cdepillabout/password/issues
+author:         Dennis Gosnell, Felix Paulusma
+maintainer:     cdep.illabout@gmail.com, felix.paulusma@gmail.com
+copyright:      Copyright (c) Dennis Gosnell & Felix Paulusma, 2020
+license:        BSD3
+license-file:   LICENSE
+build-type:     Custom
+extra-source-files:
+    README.md
+    ChangeLog.md
+
+custom-setup
+  setup-depends:
+      base
+    , Cabal
+    , cabal-doctest  >=1.0.6 && <1.1
+
+source-repository head
+  type: git
+  location: https://github.com/cdepillabout/password
+
+library
+  hs-source-dirs:
+      src
+  exposed-modules:
+      Data.Password.Types
+  other-modules:
+      Paths_password_types
+  build-depends:
+      base        >= 4.9 && < 5
+    , bytestring            < 1
+    , memory                < 0.16
+    , text                  < 1.3
+  ghc-options:
+      -Wall
+  default-language:
+      Haskell2010
+
+test-suite doctests
+  type:
+      exitcode-stdio-1.0
+  hs-source-dirs:
+      test/doctest
+  main-is:
+      doctest.hs
+  ghc-options:
+      -threaded -O2 -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.9 && <5
+    , base-compat
+    , doctest
+    , password-types
+    , QuickCheck
+    , quickcheck-instances
+    , template-haskell
+  default-language:
+      Haskell2010
+
+test-suite password-types-tasty
+  type:
+      exitcode-stdio-1.0
+  hs-source-dirs:
+      test/tasty
+  main-is:
+      Spec.hs
+  other-modules:
+      Paths_password_types
+  ghc-options:
+      -threaded -O2 -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.9 && <5
+    , password-types
+    , quickcheck-instances
+    , tasty
+    , tasty-quickcheck
+    , text
+  default-language:
+      Haskell2010
diff --git a/src/Data/Password/Types.hs b/src/Data/Password/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Password/Types.hs
@@ -0,0 +1,120 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-|
+Module      : Data.Password.Types
+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 datatypes for interacting with passwords.
+It provides the types 'Password' and 'PasswordHash', which correspond
+to plain-text and hashed passwords.
+
+== Special instances
+
+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.
+
+== Phantom types
+
+The 'PasswordHash' and 'Salt' data types have a phantom type parameter
+to be able to make sure salts and hashes can carry information about the
+algorithm they should be used with.
+
+For example, the @bcrypt@ algorithm requires its salt to be exactly
+16 bytes (128 bits) long, so this way you won't accidentally use a
+@'Salt' PBKDF2@ when the hashing function requires a @'Salt' Bcrypt@.
+And checking a password using @bcrypt@ would obviously fail if checked
+against a @'PasswordHash' PBKDF2@.
+
+-}
+
+module Data.Password.Types (
+    -- * Plain-text Password
+    Password
+  , mkPassword
+    -- * Password Hashing
+  , PasswordHash (..)
+    -- ** Unsafe debugging function to show a Password
+  , unsafeShowPassword
+    -- * Hashing salts
+  , Salt (..)
+  ) where
+
+import Data.ByteArray (constEq)
+import Data.ByteString (ByteString)
+import Data.Function (on)
+import Data.String (IsString(..))
+import Data.Text (Text)
+import Data.Text.Encoding (encodeUtf8)
+
+-- $setup
+-- >>> :set -XOverloadedStrings
+
+-- | 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**"
+instance Show Password where
+ show _ = "**PASSWORD**"
+
+-- | Construct a 'Password'
+mkPassword :: Text -> Password
+mkPassword = Password
+{-# INLINE mkPassword #-}
+
+-- | This is an unsafe function that shows a password in plain-text.
+--
+-- >>> unsafeShowPassword ("foobar" :: Password)
+-- "foobar"
+--
+-- You should generally __not use this function__ in production settings,
+-- as you don't want to accidentally print a password anywhere, like
+-- logs, network responses, database entries, etc.
+--
+-- This will mostly be used by other libraries to handle the actual
+-- password internally, though it is conceivable that, even in a production
+-- setting, a password might have to be handled in an unsafe manner at some point.
+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
+
+-- | A salt used by a hashing algorithm.
+newtype Salt a = Salt
+  { getSalt :: ByteString
+  } deriving (Eq, Show)
diff --git a/test/doctest/doctest.hs b/test/doctest/doctest.hs
new file mode 100644
--- /dev/null
+++ b/test/doctest/doctest.hs
@@ -0,0 +1,12 @@
+module Main where
+
+import Build_doctests (flags, pkgs, module_sources)
+import System.Environment.Compat (unsetEnv)
+import Test.DocTest (doctest)
+
+main :: IO ()
+main = do
+  unsetEnv "GHC_ENVIRONMENT"
+  doctest args
+  where
+    args = flags ++ pkgs ++ module_sources
diff --git a/test/tasty/Spec.hs b/test/tasty/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/tasty/Spec.hs
@@ -0,0 +1,20 @@
+module Main where
+
+import Data.String (fromString)
+import Data.Text (pack)
+import Test.QuickCheck.Instances()
+import Test.Tasty ( defaultMain, testGroup )
+import Test.Tasty.QuickCheck ( (===), testProperty )
+
+import Data.Password.Types ( mkPassword, unsafeShowPassword )
+
+main :: IO ()
+main = defaultMain $
+  testGroup "Password"
+    [ testProperty "mkPassword <-> unsafeShowPassword" $ \pass ->
+        unsafeShowPassword (mkPassword pass) === pass
+    , testProperty "Password always prints **PASSWORD**" $ \pass ->
+        show (mkPassword pass) === "**PASSWORD**"
+    , testProperty "fromString works" $ \pass ->
+        unsafeShowPassword (fromString pass) === pack pass
+    ]
