{-# LANGUAGE DeriveDataTypeable, GeneralizedNewtypeDeriving, DeriveGeneric, ForeignFunctionInterface #-} -- | -- Module : Crypto.Saltine.Internal.Password -- Copyright : (c) Promethea Raschke 2018 -- Max Amanshauser 2021 -- License : MIT -- Maintainer : max@lambdalifting.org -- Stability : experimental -- Portability : non-portable module Crypto.Saltine.Internal.Password ( c_pwhash , c_pwhash_str , c_pwhash_str_verify , c_pwhash_str_needs_rehash , pwhash_alg_argon2i13 , pwhash_alg_argon2id13 , pwhash_alg_default , algorithm -- Default algorithm constants , pwhash_bytes_max , pwhash_bytes_min , pwhash_memlimit_interactive , pwhash_memlimit_moderate , pwhash_memlimit_sensitive , pwhash_memlimit_min , pwhash_memlimit_max , pwhash_opslimit_interactive , pwhash_opslimit_moderate , pwhash_opslimit_sensitive , pwhash_opslimit_min , pwhash_opslimit_max , pwhash_passwd_min , pwhash_passwd_max , pwhash_saltbytes , pwhash_strbytes , pwhash_strprefix -- Argon2i algorithm constants , pwhash_argon2i_bytes_max , pwhash_argon2i_bytes_min , pwhash_argon2i_memlimit_interactive , pwhash_argon2i_memlimit_moderate , pwhash_argon2i_memlimit_sensitive , pwhash_argon2i_memlimit_min , pwhash_argon2i_memlimit_max , pwhash_argon2i_opslimit_interactive , pwhash_argon2i_opslimit_moderate , pwhash_argon2i_opslimit_sensitive , pwhash_argon2i_opslimit_min , pwhash_argon2i_opslimit_max , pwhash_argon2i_passwd_min , pwhash_argon2i_passwd_max , pwhash_argon2i_saltbytes , pwhash_argon2i_strbytes , pwhash_argon2i_strprefix -- Argon2id algorithm constants , pwhash_argon2id_bytes_max , pwhash_argon2id_bytes_min , pwhash_argon2id_memlimit_interactive , pwhash_argon2id_memlimit_moderate , pwhash_argon2id_memlimit_sensitive , pwhash_argon2id_memlimit_min , pwhash_argon2id_memlimit_max , pwhash_argon2id_opslimit_interactive , pwhash_argon2id_opslimit_moderate , pwhash_argon2id_opslimit_sensitive , pwhash_argon2id_opslimit_min , pwhash_argon2id_opslimit_max , pwhash_argon2id_passwd_min , pwhash_argon2id_passwd_max , pwhash_argon2id_saltbytes , pwhash_argon2id_strbytes , pwhash_argon2id_strprefix , Salt(..) , PasswordHash(..) , Opslimit(..) , Memlimit(..) , Policy(..) , Algorithm(..) ) where import Control.DeepSeq import Crypto.Saltine.Class import Crypto.Saltine.Internal.Util as U import Data.ByteString (ByteString) import Data.Data (Data, Typeable) import Data.Hashable (Hashable) import Data.Monoid import Data.Text (Text) import GHC.Generics (Generic) import Foreign.C import Foreign.Ptr import qualified Data.ByteString as S import qualified Data.Text.Encoding as DTE -- | Salt for deriving keys from passwords newtype Salt = Salt { unSalt :: ByteString } deriving (Ord, Data, Hashable, Typeable, Generic, NFData) instance Eq Salt where Salt a == Salt b = U.compare a b instance Show Salt where show k = "Password.Salt " <> bin2hex (encode k) instance IsEncoding Salt where decode v = if S.length v == pwhash_saltbytes then Just (Salt v) else Nothing {-# INLINE decode #-} encode (Salt v) = v {-# INLINE encode #-} -- | Verification string for stored passwords -- This hash contains only printable characters, hence we can just derive Show. newtype PasswordHash = PasswordHash { unPasswordHash :: Text } deriving (Ord, Data, Hashable, Typeable, Generic, Show, NFData) -- Constant time Eq instance, just in case. instance Eq PasswordHash where PasswordHash a == PasswordHash b = U.compare (DTE.encodeUtf8 a) (DTE.encodeUtf8 b) -- | Wrapper type for the operations used by password hashing newtype Opslimit = Opslimit { getOpslimit :: Int } deriving (Eq, Ord, Data, Hashable, Typeable, Generic, Show, NFData) -- | Wrapper type for the memory used by password hashing newtype Memlimit = Memlimit { getMemlimit :: Int } deriving (Eq, Ord, Data, Hashable, Typeable, Generic, Show, NFData) -- | Wrapper for opslimit, memlimit and algorithm data Policy = Policy { opsPolicy :: Opslimit , memPolicy :: Memlimit , algPolicy :: Algorithm } deriving (Eq, Ord, Data, Typeable, Generic, Show) instance Hashable Policy -- | Algorithms known to Libsodium, as an enum datatype data Algorithm = DefaultAlgorithm | Argon2i13 | Argon2id13 deriving (Eq, Enum, Ord, Show, Generic, Data, Typeable, Bounded) instance Hashable Algorithm algorithm :: Algorithm -> CInt algorithm DefaultAlgorithm = fromIntegral pwhash_alg_default algorithm Argon2i13 = fromIntegral pwhash_alg_argon2i13 algorithm Argon2id13 = fromIntegral pwhash_alg_argon2id13 -- | Lets libsodium pick a hashing algorithm pwhash_alg_default :: Int pwhash_alg_default = fromIntegral c_crypto_pwhash_alg_default -- | version 1.3 of the Argon2i algorithm pwhash_alg_argon2i13 :: Int pwhash_alg_argon2i13 = fromIntegral c_crypto_pwhash_alg_argon2i13 -- | version 1.3 of the Argon2id algorithm pwhash_alg_argon2id13 :: Int pwhash_alg_argon2id13 = fromIntegral c_crypto_pwhash_alg_argon2id13 -- | Constants for the default algorithm -- | Minimum output length for key derivation (16 (128 bits)). pwhash_bytes_min :: Int pwhash_bytes_min = fromIntegral c_crypto_pwhash_bytes_min -- | Maximum output length for key derivation. pwhash_bytes_max :: Int pwhash_bytes_max = fromIntegral c_crypto_pwhash_bytes_max -- | Minimum allowed memory limit for password hashing pwhash_memlimit_min :: Int pwhash_memlimit_min = fromIntegral c_crypto_pwhash_memlimit_min -- | Maximum allowed memory limit for password hashing pwhash_memlimit_max :: Int pwhash_memlimit_max = fromIntegral c_crypto_pwhash_memlimit_max -- | Constant for currently 64MB memory pwhash_memlimit_interactive :: Int pwhash_memlimit_interactive = fromIntegral c_crypto_pwhash_memlimit_interactive -- | Constant for currently 256MB memory pwhash_memlimit_moderate :: Int pwhash_memlimit_moderate = fromIntegral c_crypto_pwhash_memlimit_moderate -- | Constant for currently 1024MB memory pwhash_memlimit_sensitive :: Int pwhash_memlimit_sensitive = fromIntegral c_crypto_pwhash_memlimit_sensitive -- | Minimum allowed number of computations for password hashing pwhash_opslimit_min :: Int pwhash_opslimit_min = fromIntegral c_crypto_pwhash_opslimit_min -- | Maximum allowed number of computations for password hashing pwhash_opslimit_max :: Int pwhash_opslimit_max = fromIntegral c_crypto_pwhash_opslimit_max -- | Constant for relatively fast hashing pwhash_opslimit_interactive :: Int pwhash_opslimit_interactive = fromIntegral c_crypto_pwhash_opslimit_interactive -- | Constant for moderately fast hashing pwhash_opslimit_moderate :: Int pwhash_opslimit_moderate = fromIntegral c_crypto_pwhash_opslimit_moderate -- | Constant for relatively slow hashing pwhash_opslimit_sensitive :: Int pwhash_opslimit_sensitive = fromIntegral c_crypto_pwhash_opslimit_sensitive -- | Minimum number of characters in password for key derivation pwhash_passwd_min :: Int pwhash_passwd_min = fromIntegral c_crypto_pwhash_passwd_min -- | Maximum number of characters in password for key derivation pwhash_passwd_max :: Int pwhash_passwd_max = fromIntegral c_crypto_pwhash_passwd_max -- | Size of salt pwhash_saltbytes :: Int pwhash_saltbytes = fromIntegral c_crypto_pwhash_saltbytes -- | (Maximum) size of password hashing output pwhash_strbytes :: Int pwhash_strbytes = fromIntegral c_crypto_pwhash_strbytes -- string that hashes with this algorithm are prefixed with pwhash_strprefix :: Int pwhash_strprefix = fromIntegral c_crypto_pwhash_strprefix -- | Constants for Argon2ID -- | Minimum output length for key derivation (= 16 (128 bits)). pwhash_argon2id_bytes_min :: Int pwhash_argon2id_bytes_min = fromIntegral c_crypto_pwhash_argon2id_bytes_min -- | Maximum output length for key derivation. pwhash_argon2id_bytes_max :: Int pwhash_argon2id_bytes_max = fromIntegral c_crypto_pwhash_argon2id_bytes_max -- | Minimum allowed memory limit for password hashing pwhash_argon2id_memlimit_min :: Int pwhash_argon2id_memlimit_min = fromIntegral c_crypto_pwhash_argon2id_memlimit_min -- | Maximum allowed memory limit for password hashing pwhash_argon2id_memlimit_max :: Int pwhash_argon2id_memlimit_max = fromIntegral c_crypto_pwhash_argon2id_memlimit_max -- | Constant for currently 64MB memory pwhash_argon2id_memlimit_interactive :: Int pwhash_argon2id_memlimit_interactive = fromIntegral c_crypto_pwhash_argon2id_memlimit_interactive -- | Constant for currently 256MB memory pwhash_argon2id_memlimit_moderate :: Int pwhash_argon2id_memlimit_moderate = fromIntegral c_crypto_pwhash_argon2id_memlimit_moderate -- | Constant for currently 1024MB memory pwhash_argon2id_memlimit_sensitive :: Int pwhash_argon2id_memlimit_sensitive = fromIntegral c_crypto_pwhash_argon2id_memlimit_sensitive -- | Minimum allowed number of computations for password hashing pwhash_argon2id_opslimit_min :: Int pwhash_argon2id_opslimit_min = fromIntegral c_crypto_pwhash_argon2id_opslimit_min -- | Maximum allowed number of computations for password hashing pwhash_argon2id_opslimit_max :: Int pwhash_argon2id_opslimit_max = fromIntegral c_crypto_pwhash_argon2id_opslimit_max -- | Constant for relatively fast hashing pwhash_argon2id_opslimit_interactive :: Int pwhash_argon2id_opslimit_interactive = fromIntegral c_crypto_pwhash_argon2id_opslimit_interactive -- | Constant for moderately fast hashing pwhash_argon2id_opslimit_moderate :: Int pwhash_argon2id_opslimit_moderate = fromIntegral c_crypto_pwhash_argon2id_opslimit_moderate -- | Constant for relatively slow hashing pwhash_argon2id_opslimit_sensitive :: Int pwhash_argon2id_opslimit_sensitive = fromIntegral c_crypto_pwhash_argon2id_opslimit_sensitive -- | Minimum number of characters in password for key derivation pwhash_argon2id_passwd_min :: Int pwhash_argon2id_passwd_min = fromIntegral c_crypto_pwhash_argon2id_passwd_min -- | Maximum number of characters in password for key derivation pwhash_argon2id_passwd_max :: Int pwhash_argon2id_passwd_max = fromIntegral c_crypto_pwhash_argon2id_passwd_max -- | Size of salt pwhash_argon2id_saltbytes :: Int pwhash_argon2id_saltbytes = fromIntegral c_crypto_pwhash_argon2id_saltbytes -- | (Maximum) size of password hashing output pwhash_argon2id_strbytes :: Int pwhash_argon2id_strbytes = fromIntegral c_crypto_pwhash_argon2id_strbytes -- string that hashes with this algorithm are prefixed with pwhash_argon2id_strprefix :: Int pwhash_argon2id_strprefix = fromIntegral c_crypto_pwhash_argon2id_strprefix -- | Constants for ARGON2I -- | Minimum output length for key derivation (= 16 (128 bits)). pwhash_argon2i_bytes_min :: Int pwhash_argon2i_bytes_min = fromIntegral c_crypto_pwhash_argon2i_bytes_min -- | Maximum output length for key derivation. pwhash_argon2i_bytes_max :: Int pwhash_argon2i_bytes_max = fromIntegral c_crypto_pwhash_argon2i_bytes_max -- | Minimum allowed memory limit for password hashing pwhash_argon2i_memlimit_min :: Int pwhash_argon2i_memlimit_min = fromIntegral c_crypto_pwhash_argon2i_memlimit_min -- | Maximum allowed memory limit for password hashing pwhash_argon2i_memlimit_max :: Int pwhash_argon2i_memlimit_max = fromIntegral c_crypto_pwhash_argon2i_memlimit_max -- | Constant for currently 64MB memory pwhash_argon2i_memlimit_interactive :: Int pwhash_argon2i_memlimit_interactive = fromIntegral c_crypto_pwhash_argon2i_memlimit_interactive -- | Constant for currently 256MB memory pwhash_argon2i_memlimit_moderate :: Int pwhash_argon2i_memlimit_moderate = fromIntegral c_crypto_pwhash_argon2i_memlimit_moderate -- | Constant for currently 1024MB memory pwhash_argon2i_memlimit_sensitive :: Int pwhash_argon2i_memlimit_sensitive = fromIntegral c_crypto_pwhash_argon2i_memlimit_sensitive -- | Minimum allowed number of computations for password hashing pwhash_argon2i_opslimit_min :: Int pwhash_argon2i_opslimit_min = fromIntegral c_crypto_pwhash_argon2i_opslimit_min -- | Maximum allowed number of computations for password hashing pwhash_argon2i_opslimit_max :: Int pwhash_argon2i_opslimit_max = fromIntegral c_crypto_pwhash_argon2i_opslimit_max -- | Constant for relatively fast hashing pwhash_argon2i_opslimit_interactive :: Int pwhash_argon2i_opslimit_interactive = fromIntegral c_crypto_pwhash_argon2i_opslimit_interactive -- | Constant for moderately fast hashing pwhash_argon2i_opslimit_moderate :: Int pwhash_argon2i_opslimit_moderate = fromIntegral c_crypto_pwhash_argon2i_opslimit_moderate -- | Constant for relatively slow hashing pwhash_argon2i_opslimit_sensitive :: Int pwhash_argon2i_opslimit_sensitive = fromIntegral c_crypto_pwhash_argon2i_opslimit_sensitive -- | Minimum number of characters in password for key derivation pwhash_argon2i_passwd_min :: Int pwhash_argon2i_passwd_min = fromIntegral c_crypto_pwhash_argon2i_passwd_min -- | Maximum number of characters in password for key derivation pwhash_argon2i_passwd_max :: Int pwhash_argon2i_passwd_max = fromIntegral c_crypto_pwhash_argon2i_passwd_max -- | Size of salt pwhash_argon2i_saltbytes :: Int pwhash_argon2i_saltbytes = fromIntegral c_crypto_pwhash_argon2i_saltbytes -- | (Maximum) size of password hashing output pwhash_argon2i_strbytes :: Int pwhash_argon2i_strbytes = fromIntegral c_crypto_pwhash_argon2i_strbytes -- string that hashes with this algorithm are prefixed with pwhash_argon2i_strprefix :: Int pwhash_argon2i_strprefix = fromIntegral c_crypto_pwhash_argon2i_strprefix foreign import ccall "crypto_pwhash" c_pwhash :: Ptr CChar -- ^ Derived key output buffer -> CULLong -- ^ Derived key length -> Ptr CChar -- ^ Password input buffer -> CULLong -- ^ Password length -> Ptr CChar -- ^ Salt input buffer -> CULLong -- ^ Operation limit -> CSize -- ^ Memory usage limit -> CInt -- ^ Algorithm -> IO CInt foreign import ccall "crypto_pwhash_str" c_pwhash_str :: Ptr CChar -- ^ Hashed password output buffer -> Ptr CChar -- ^ Password input buffer -> CULLong -- ^ Password length -> CULLong -- ^ Operation limit -> CSize -- ^ Memory usage limit -> IO CInt foreign import ccall "crypto_pwhash_str_verify" c_pwhash_str_verify :: Ptr CChar -- ^ Hashed password input buffer -> Ptr CChar -- ^ Password input buffer -> CULLong -- ^ Password length -> IO CInt foreign import ccall "crypto_pwhash_str_needs_rehash" c_pwhash_str_needs_rehash :: Ptr CChar -- ^ Hashed password input buffer -> CULLong -- ^ Operation limit -> CSize -- ^ Memory usage limit -> IO CInt foreign import ccall "crypto_pwhash_alg_argon2id13" c_crypto_pwhash_alg_argon2id13 :: CSize foreign import ccall "crypto_pwhash_alg_argon2i13" c_crypto_pwhash_alg_argon2i13 :: CSize foreign import ccall "crypto_pwhash_alg_default" c_crypto_pwhash_alg_default :: CSize -- Constants for the default algorithm foreign import ccall "crypto_pwhash_bytes_min" c_crypto_pwhash_bytes_min :: CSize foreign import ccall "crypto_pwhash_bytes_max" c_crypto_pwhash_bytes_max :: CSize foreign import ccall "crypto_pwhash_memlimit_min" c_crypto_pwhash_memlimit_min :: CSize foreign import ccall "crypto_pwhash_memlimit_max" c_crypto_pwhash_memlimit_max :: CSize foreign import ccall "crypto_pwhash_memlimit_interactive" c_crypto_pwhash_memlimit_interactive :: CSize foreign import ccall "crypto_pwhash_memlimit_moderate" c_crypto_pwhash_memlimit_moderate :: CSize foreign import ccall "crypto_pwhash_memlimit_sensitive" c_crypto_pwhash_memlimit_sensitive :: CSize foreign import ccall "crypto_pwhash_opslimit_min" c_crypto_pwhash_opslimit_min :: CSize foreign import ccall "crypto_pwhash_opslimit_max" c_crypto_pwhash_opslimit_max :: CSize foreign import ccall "crypto_pwhash_opslimit_interactive" c_crypto_pwhash_opslimit_interactive :: CSize foreign import ccall "crypto_pwhash_opslimit_moderate" c_crypto_pwhash_opslimit_moderate :: CSize foreign import ccall "crypto_pwhash_opslimit_sensitive" c_crypto_pwhash_opslimit_sensitive :: CSize foreign import ccall "crypto_pwhash_passwd_min" c_crypto_pwhash_passwd_min :: CSize foreign import ccall "crypto_pwhash_passwd_max" c_crypto_pwhash_passwd_max :: CSize foreign import ccall "crypto_pwhash_saltbytes" c_crypto_pwhash_saltbytes :: CSize foreign import ccall "crypto_pwhash_strbytes" c_crypto_pwhash_strbytes :: CSize foreign import ccall "crypto_pwhash_strprefix" c_crypto_pwhash_strprefix :: CSize -- Constants for ARGON2ID (currently default) foreign import ccall "crypto_pwhash_argon2id_bytes_min" c_crypto_pwhash_argon2id_bytes_min :: CSize foreign import ccall "crypto_pwhash_argon2id_bytes_max" c_crypto_pwhash_argon2id_bytes_max :: CSize foreign import ccall "crypto_pwhash_argon2id_memlimit_min" c_crypto_pwhash_argon2id_memlimit_min :: CSize foreign import ccall "crypto_pwhash_argon2id_memlimit_max" c_crypto_pwhash_argon2id_memlimit_max :: CSize foreign import ccall "crypto_pwhash_argon2id_memlimit_interactive" c_crypto_pwhash_argon2id_memlimit_interactive :: CSize foreign import ccall "crypto_pwhash_argon2id_memlimit_moderate" c_crypto_pwhash_argon2id_memlimit_moderate :: CSize foreign import ccall "crypto_pwhash_argon2id_memlimit_sensitive" c_crypto_pwhash_argon2id_memlimit_sensitive :: CSize foreign import ccall "crypto_pwhash_argon2id_opslimit_min" c_crypto_pwhash_argon2id_opslimit_min :: CSize foreign import ccall "crypto_pwhash_argon2id_opslimit_max" c_crypto_pwhash_argon2id_opslimit_max :: CSize foreign import ccall "crypto_pwhash_argon2id_opslimit_interactive" c_crypto_pwhash_argon2id_opslimit_interactive :: CSize foreign import ccall "crypto_pwhash_argon2id_opslimit_moderate" c_crypto_pwhash_argon2id_opslimit_moderate :: CSize foreign import ccall "crypto_pwhash_argon2id_opslimit_sensitive" c_crypto_pwhash_argon2id_opslimit_sensitive :: CSize foreign import ccall "crypto_pwhash_argon2id_passwd_min" c_crypto_pwhash_argon2id_passwd_min :: CSize foreign import ccall "crypto_pwhash_argon2id_passwd_max" c_crypto_pwhash_argon2id_passwd_max :: CSize foreign import ccall "crypto_pwhash_argon2id_saltbytes" c_crypto_pwhash_argon2id_saltbytes :: CSize foreign import ccall "crypto_pwhash_argon2id_strbytes" c_crypto_pwhash_argon2id_strbytes :: CSize foreign import ccall "crypto_pwhash_argon2id_strprefix" c_crypto_pwhash_argon2id_strprefix :: CSize -- Constants for ARGON2I foreign import ccall "crypto_pwhash_argon2i_bytes_min" c_crypto_pwhash_argon2i_bytes_min :: CSize foreign import ccall "crypto_pwhash_argon2i_bytes_max" c_crypto_pwhash_argon2i_bytes_max :: CSize foreign import ccall "crypto_pwhash_argon2i_memlimit_min" c_crypto_pwhash_argon2i_memlimit_min :: CSize foreign import ccall "crypto_pwhash_argon2i_memlimit_max" c_crypto_pwhash_argon2i_memlimit_max :: CSize foreign import ccall "crypto_pwhash_argon2i_memlimit_interactive" c_crypto_pwhash_argon2i_memlimit_interactive :: CSize foreign import ccall "crypto_pwhash_argon2i_memlimit_moderate" c_crypto_pwhash_argon2i_memlimit_moderate :: CSize foreign import ccall "crypto_pwhash_argon2i_memlimit_sensitive" c_crypto_pwhash_argon2i_memlimit_sensitive :: CSize foreign import ccall "crypto_pwhash_argon2i_opslimit_min" c_crypto_pwhash_argon2i_opslimit_min :: CSize foreign import ccall "crypto_pwhash_argon2i_opslimit_max" c_crypto_pwhash_argon2i_opslimit_max :: CSize foreign import ccall "crypto_pwhash_argon2i_opslimit_interactive" c_crypto_pwhash_argon2i_opslimit_interactive :: CSize foreign import ccall "crypto_pwhash_argon2i_opslimit_moderate" c_crypto_pwhash_argon2i_opslimit_moderate :: CSize foreign import ccall "crypto_pwhash_argon2i_opslimit_sensitive" c_crypto_pwhash_argon2i_opslimit_sensitive :: CSize foreign import ccall "crypto_pwhash_argon2i_passwd_min" c_crypto_pwhash_argon2i_passwd_min :: CSize foreign import ccall "crypto_pwhash_argon2i_passwd_max" c_crypto_pwhash_argon2i_passwd_max :: CSize foreign import ccall "crypto_pwhash_argon2i_saltbytes" c_crypto_pwhash_argon2i_saltbytes :: CSize foreign import ccall "crypto_pwhash_argon2i_strbytes" c_crypto_pwhash_argon2i_strbytes :: CSize foreign import ccall "crypto_pwhash_argon2i_strprefix" c_crypto_pwhash_argon2i_strprefix :: CSize