    -- |
    -- Module      : Crypto.KDF.Argon2
    -- License     : BSD-style
    -- Maintainer  : Vincent Hanquez <vincent@snarc.org>
    -- Stability   : experimental
    -- Portability : unknown
    --
    -- Argon2 hashing function (P-H-C winner)
    --
    -- Recommended to use this module qualified
    --
    -- File started from Argon2.hs, from Oliver Charles
    -- at https://github.com/ocharles/argon2
    --
    module Crypto.KDF.Argon2
        (
          Options(..)
        , TimeCost
        , MemoryCost
        , Parallelism
        , Variant(..)
        , Version(..)
        , defaultOptions
        -- * Hashing function
        , hash
        ) where

    import           Crypto.Internal.ByteArray (ByteArray, ByteArrayAccess)
    import qualified Crypto.Internal.ByteArray as B
    import           Crypto.Error
    import           Control.Monad (when)
    import           Data.Word
    import           Foreign.C
    import           Foreign.Ptr

    -- | Which variant of Argon2 to use. You should choose the variant that is most
    -- applicable to your intention to hash inputs.
    data Variant =
          Argon2d  -- ^ Argon2d is faster than Argon2i and uses data-depending memory access,
                   -- which makes it suitable for cryptocurrencies and applications with no
                   -- threats from side-channel timing attacks.
        | Argon2i  -- ^ Argon2i uses data-independent memory access, which is preferred
                   -- for password hashing and password-based key derivation. Argon2i
                   -- is slower as it makes more passes over the memory to protect from
                   -- tradeoff attacks.
        | Argon2id -- ^ Argon2id is a hybrid of Argon2i and Argon2d, using a combination
                   -- of data-depending and data-independent memory accesses, which gives
                   -- some of Argon2i's resistance to side-channel cache timing attacks
                   -- and much of Argon2d's resistance to GPU cracking attacks
        deriving (Variant -> Variant -> Bool
    (Variant -> Variant -> Bool)
    -> (Variant -> Variant -> Bool) -> Eq Variant
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Variant -> Variant -> Bool
    == :: Variant -> Variant -> Bool
    $c/= :: Variant -> Variant -> Bool
    /= :: Variant -> Variant -> Bool
    Eq,Eq Variant
    Eq Variant
    -> (Variant -> Variant -> Ordering)
    -> (Variant -> Variant -> Bool)
    -> (Variant -> Variant -> Bool)
    -> (Variant -> Variant -> Bool)
    -> (Variant -> Variant -> Bool)
    -> (Variant -> Variant -> Variant)
    -> (Variant -> Variant -> Variant)
    -> Ord Variant
    Variant -> Variant -> Bool
    Variant -> Variant -> Ordering
    Variant -> Variant -> Variant
    forall a.
    Eq a
    -> (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Variant -> Variant -> Ordering
    compare :: Variant -> Variant -> Ordering
    $c< :: Variant -> Variant -> Bool
    < :: Variant -> Variant -> Bool
    $c<= :: Variant -> Variant -> Bool
    <= :: Variant -> Variant -> Bool
    $c> :: Variant -> Variant -> Bool
    > :: Variant -> Variant -> Bool
    $c>= :: Variant -> Variant -> Bool
    >= :: Variant -> Variant -> Bool
    $cmax :: Variant -> Variant -> Variant
    max :: Variant -> Variant -> Variant
    $cmin :: Variant -> Variant -> Variant
    min :: Variant -> Variant -> Variant
    Ord,ReadPrec [Variant]
    ReadPrec Variant
    Int -> ReadS Variant
    ReadS [Variant]
    (Int -> ReadS Variant)
    -> ReadS [Variant]
    -> ReadPrec Variant
    -> ReadPrec [Variant]
    -> Read Variant
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS Variant
    readsPrec :: Int -> ReadS Variant
    $creadList :: ReadS [Variant]
    readList :: ReadS [Variant]
    $creadPrec :: ReadPrec Variant
    readPrec :: ReadPrec Variant
    $creadListPrec :: ReadPrec [Variant]
    readListPrec :: ReadPrec [Variant]
    Read,Int -> Variant -> ShowS
    [Variant] -> ShowS
    Variant -> String
    (Int -> Variant -> ShowS)
    -> (Variant -> String) -> ([Variant] -> ShowS) -> Show Variant
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Variant -> ShowS
    showsPrec :: Int -> Variant -> ShowS
    $cshow :: Variant -> String
    show :: Variant -> String
    $cshowList :: [Variant] -> ShowS
    showList :: [Variant] -> ShowS
    Show,Int -> Variant
    Variant -> Int
    Variant -> [Variant]
    Variant -> Variant
    Variant -> Variant -> [Variant]
    Variant -> Variant -> Variant -> [Variant]
    (Variant -> Variant)
    -> (Variant -> Variant)
    -> (Int -> Variant)
    -> (Variant -> Int)
    -> (Variant -> [Variant])
    -> (Variant -> Variant -> [Variant])
    -> (Variant -> Variant -> [Variant])
    -> (Variant -> Variant -> Variant -> [Variant])
    -> Enum Variant
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Variant -> Variant
    succ :: Variant -> Variant
    $cpred :: Variant -> Variant
    pred :: Variant -> Variant
    $ctoEnum :: Int -> Variant
    toEnum :: Int -> Variant
    $cfromEnum :: Variant -> Int
    fromEnum :: Variant -> Int
    $cenumFrom :: Variant -> [Variant]
    enumFrom :: Variant -> [Variant]
    $cenumFromThen :: Variant -> Variant -> [Variant]
    enumFromThen :: Variant -> Variant -> [Variant]
    $cenumFromTo :: Variant -> Variant -> [Variant]
    enumFromTo :: Variant -> Variant -> [Variant]
    $cenumFromThenTo :: Variant -> Variant -> Variant -> [Variant]
    enumFromThenTo :: Variant -> Variant -> Variant -> [Variant]
    Enum,Variant
    Variant -> Variant -> Bounded Variant
    forall a. a -> a -> Bounded a
    $cminBound :: Variant
    minBound :: Variant
    $cmaxBound :: Variant
    maxBound :: Variant
    Bounded)

    -- | Which version of Argon2 to use
    data Version = Version10 | Version13
        deriving (Version -> Version -> Bool
    (Version -> Version -> Bool)
    -> (Version -> Version -> Bool) -> Eq Version
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Version -> Version -> Bool
    == :: Version -> Version -> Bool
    $c/= :: Version -> Version -> Bool
    /= :: Version -> Version -> Bool
    Eq,Eq Version
    Eq Version
    -> (Version -> Version -> Ordering)
    -> (Version -> Version -> Bool)
    -> (Version -> Version -> Bool)
    -> (Version -> Version -> Bool)
    -> (Version -> Version -> Bool)
    -> (Version -> Version -> Version)
    -> (Version -> Version -> Version)
    -> Ord Version
    Version -> Version -> Bool
    Version -> Version -> Ordering
    Version -> Version -> Version
    forall a.
    Eq a
    -> (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Version -> Version -> Ordering
    compare :: Version -> Version -> Ordering
    $c< :: Version -> Version -> Bool
    < :: Version -> Version -> Bool
    $c<= :: Version -> Version -> Bool
    <= :: Version -> Version -> Bool
    $c> :: Version -> Version -> Bool
    > :: Version -> Version -> Bool
    $c>= :: Version -> Version -> Bool
    >= :: Version -> Version -> Bool
    $cmax :: Version -> Version -> Version
    max :: Version -> Version -> Version
    $cmin :: Version -> Version -> Version
    min :: Version -> Version -> Version
    Ord,ReadPrec [Version]
    ReadPrec Version
    Int -> ReadS Version
    ReadS [Version]
    (Int -> ReadS Version)
    -> ReadS [Version]
    -> ReadPrec Version
    -> ReadPrec [Version]
    -> Read Version
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS Version
    readsPrec :: Int -> ReadS Version
    $creadList :: ReadS [Version]
    readList :: ReadS [Version]
    $creadPrec :: ReadPrec Version
    readPrec :: ReadPrec Version
    $creadListPrec :: ReadPrec [Version]
    readListPrec :: ReadPrec [Version]
    Read,Int -> Version -> ShowS
    [Version] -> ShowS
    Version -> String
    (Int -> Version -> ShowS)
    -> (Version -> String) -> ([Version] -> ShowS) -> Show Version
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Version -> ShowS
    showsPrec :: Int -> Version -> ShowS
    $cshow :: Version -> String
    show :: Version -> String
    $cshowList :: [Version] -> ShowS
    showList :: [Version] -> ShowS
    Show,Int -> Version
    Version -> Int
    Version -> [Version]
    Version -> Version
    Version -> Version -> [Version]
    Version -> Version -> Version -> [Version]
    (Version -> Version)
    -> (Version -> Version)
    -> (Int -> Version)
    -> (Version -> Int)
    -> (Version -> [Version])
    -> (Version -> Version -> [Version])
    -> (Version -> Version -> [Version])
    -> (Version -> Version -> Version -> [Version])
    -> Enum Version
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    $csucc :: Version -> Version
    succ :: Version -> Version
    $cpred :: Version -> Version
    pred :: Version -> Version
    $ctoEnum :: Int -> Version
    toEnum :: Int -> Version
    $cfromEnum :: Version -> Int
    fromEnum :: Version -> Int
    $cenumFrom :: Version -> [Version]
    enumFrom :: Version -> [Version]
    $cenumFromThen :: Version -> Version -> [Version]
    enumFromThen :: Version -> Version -> [Version]
    $cenumFromTo :: Version -> Version -> [Version]
    enumFromTo :: Version -> Version -> [Version]
    $cenumFromThenTo :: Version -> Version -> Version -> [Version]
    enumFromThenTo :: Version -> Version -> Version -> [Version]
    Enum,Version
    Version -> Version -> Bounded Version
    forall a. a -> a -> Bounded a
    $cminBound :: Version
    minBound :: Version
    $cmaxBound :: Version
    maxBound :: Version
    Bounded)

    -- | The time cost, which defines the amount of computation realized and therefore the execution time, given in number of iterations.
    --
    -- 'FFI.ARGON2_MIN_TIME' <= 'hashIterations' <= 'FFI.ARGON2_MAX_TIME'
    type TimeCost = Word32

    -- | The memory cost, which defines the memory usage, given in kibibytes.
    --
    -- max 'FFI.ARGON2_MIN_MEMORY' (8 * 'hashParallelism') <= 'hashMemory' <= 'FFI.ARGON2_MAX_MEMORY'
    type MemoryCost = Word32

    -- | A parallelism degree, which defines the number of parallel threads.
    --
    -- 'FFI.ARGON2_MIN_LANES' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_LANES' && 'FFI.ARGON_MIN_THREADS' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_THREADS'
    type Parallelism = Word32

    -- | Parameters that can be adjusted to change the runtime performance of the
    -- hashing.
    data Options = Options
        { Options -> TimeCost
    iterations  :: !TimeCost
        , Options -> TimeCost
    memory      :: !MemoryCost
        , Options -> TimeCost
    parallelism :: !Parallelism
        , Options -> Variant
    variant     :: !Variant     -- ^ Which variant of Argon2 to use.
        , Options -> Version
    version     :: !Version     -- ^ Which version of Argon2 to use.
        }
        deriving (Options -> Options -> Bool
    (Options -> Options -> Bool)
    -> (Options -> Options -> Bool) -> Eq Options
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Options -> Options -> Bool
    == :: Options -> Options -> Bool
    $c/= :: Options -> Options -> Bool
    /= :: Options -> Options -> Bool
    Eq,Eq Options
    Eq Options
    -> (Options -> Options -> Ordering)
    -> (Options -> Options -> Bool)
    -> (Options -> Options -> Bool)
    -> (Options -> Options -> Bool)
    -> (Options -> Options -> Bool)
    -> (Options -> Options -> Options)
    -> (Options -> Options -> Options)
    -> Ord Options
    Options -> Options -> Bool
    Options -> Options -> Ordering
    Options -> Options -> Options
    forall a.
    Eq a
    -> (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Options -> Options -> Ordering
    compare :: Options -> Options -> Ordering
    $c< :: Options -> Options -> Bool
    < :: Options -> Options -> Bool
    $c<= :: Options -> Options -> Bool
    <= :: Options -> Options -> Bool
    $c> :: Options -> Options -> Bool
    > :: Options -> Options -> Bool
    $c>= :: Options -> Options -> Bool
    >= :: Options -> Options -> Bool
    $cmax :: Options -> Options -> Options
    max :: Options -> Options -> Options
    $cmin :: Options -> Options -> Options
    min :: Options -> Options -> Options
    Ord,ReadPrec [Options]
    ReadPrec Options
    Int -> ReadS Options
    ReadS [Options]
    (Int -> ReadS Options)
    -> ReadS [Options]
    -> ReadPrec Options
    -> ReadPrec [Options]
    -> Read Options
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    $creadsPrec :: Int -> ReadS Options
    readsPrec :: Int -> ReadS Options
    $creadList :: ReadS [Options]
    readList :: ReadS [Options]
    $creadPrec :: ReadPrec Options
    readPrec :: ReadPrec Options
    $creadListPrec :: ReadPrec [Options]
    readListPrec :: ReadPrec [Options]
    Read,Int -> Options -> ShowS
    [Options] -> ShowS
    Options -> String
    (Int -> Options -> ShowS)
    -> (Options -> String) -> ([Options] -> ShowS) -> Show Options
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Options -> ShowS
    showsPrec :: Int -> Options -> ShowS
    $cshow :: Options -> String
    show :: Options -> String
    $cshowList :: [Options] -> ShowS
    showList :: [Options] -> ShowS
    Show)

    saltMinLength :: Int
    saltMinLength :: Int
    saltMinLength = Int
    8

    outputMinLength :: Int
    outputMinLength :: Int
    outputMinLength = Int
    4

    -- specification allows up to 2^32-1 but this is too big for a signed Int
    -- on a 32-bit architecture, so we limit tag length to 2^31-1 bytes
    outputMaxLength :: Int
    outputMaxLength :: Int
    outputMaxLength = Int
    0x7fffffff

    defaultOptions :: Options
    defaultOptions :: Options
    defaultOptions =
        Options { iterations :: TimeCost
    iterations  = TimeCost
    1
                , memory :: TimeCost
    memory      = TimeCost
    2 TimeCost -> Int -> TimeCost
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (Int
    17 :: Int)
                , parallelism :: TimeCost
    parallelism = TimeCost
    4
                , variant :: Variant
    variant     = Variant
    Argon2i
                , version :: Version
    version     = Version
    Version13
                }

    hash :: (ByteArrayAccess password, ByteArrayAccess salt, ByteArray out)
         => Options
         -> password
         -> salt
         -> Int
         -> CryptoFailable out
    hash :: forall password salt out.
    (ByteArrayAccess password, ByteArrayAccess salt, ByteArray out) =>
    Options -> password -> salt -> Int -> CryptoFailable out
    hash Options
    options password
    password salt
    salt Int
    outLen
        | Int
    saltLen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    saltMinLength  = CryptoError -> CryptoFailable out
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_SaltTooSmall
        | Int
    outLen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    < Int
    outputMinLength = CryptoError -> CryptoFailable out
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_OutputLengthTooSmall
        | Int
    outLen Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    > Int
    outputMaxLength = CryptoError -> CryptoFailable out
    forall a. CryptoError -> CryptoFailable a
    CryptoFailed CryptoError
    CryptoError_OutputLengthTooBig
        | Bool
    otherwise                = out -> CryptoFailable out
    forall a. a -> CryptoFailable a
    CryptoPassed (out -> CryptoFailable out) -> out -> CryptoFailable out
    forall a b. (a -> b) -> a -> b
    $ Int -> (Ptr HashOut -> IO ()) -> out
    forall a p. ByteArray a => Int -> (Ptr p -> IO ()) -> a
    B.allocAndFreeze Int
    outLen ((Ptr HashOut -> IO ()) -> out) -> (Ptr HashOut -> IO ()) -> out
    forall a b. (a -> b) -> a -> b
    $ \Ptr HashOut
    out -> do
            CVariant
    res <- password -> (Ptr Pass -> IO CVariant) -> IO CVariant
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. password -> (Ptr p -> IO a) -> IO a
    B.withByteArray password
    password ((Ptr Pass -> IO CVariant) -> IO CVariant)
    -> (Ptr Pass -> IO CVariant) -> IO CVariant
    forall a b. (a -> b) -> a -> b
    $ \Ptr Pass
    pPass ->
                   salt -> (Ptr Salt -> IO CVariant) -> IO CVariant
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. salt -> (Ptr p -> IO a) -> IO a
    B.withByteArray salt
    salt     ((Ptr Salt -> IO CVariant) -> IO CVariant)
    -> (Ptr Salt -> IO CVariant) -> IO CVariant
    forall a b. (a -> b) -> a -> b
    $ \Ptr Salt
    pSalt ->
                        TimeCost
    -> TimeCost
    -> TimeCost
    -> Ptr Pass
    -> CSize
    -> Ptr Salt
    -> CSize
    -> Ptr HashOut
    -> CSize
    -> CVariant
    -> CVariant
    -> IO CVariant
    argon2_hash (Options -> TimeCost
    iterations Options
    options)
                                    (Options -> TimeCost
    memory Options
    options)
                                    (Options -> TimeCost
    parallelism Options
    options)
                                    Ptr Pass
    pPass
                                    (Int -> CSize
    csizeOfInt Int
    passwordLen)
                                    Ptr Salt
    pSalt
                                    (Int -> CSize
    csizeOfInt Int
    saltLen)
                                    Ptr HashOut
    out
                                    (Int -> CSize
    csizeOfInt Int
    outLen)
                                    (Variant -> CVariant
    cOfVariant (Variant -> CVariant) -> Variant -> CVariant
    forall a b. (a -> b) -> a -> b
    $ Options -> Variant
    variant Options
    options)
                                    (Version -> CVariant
    cOfVersion (Version -> CVariant) -> Version -> CVariant
    forall a b. (a -> b) -> a -> b
    $ Options -> Version
    version Options
    options)
            Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (CVariant
    res CVariant -> CVariant -> Bool
    forall a. Eq a => a -> a -> Bool
    /= CVariant
    0) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ String -> IO ()
    forall a. HasCallStack => String -> a
    error String
    "argon2: hash: internal error"
      where
        saltLen :: Int
    saltLen = salt -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length salt
    salt
        passwordLen :: Int
    passwordLen = password -> Int
    forall ba. ByteArrayAccess ba => ba -> Int
    B.length password
    password

    data Pass
    data Salt
    data HashOut

    type CVariant = CInt -- valid value is 0 (Argon2d), 1 (Argon2i) and 2 (Argon2id)
    type CVersion = CInt -- valid value is 0x10, 0x13

    cOfVersion :: Version -> CVersion
    cOfVersion :: Version -> CVariant
    cOfVersion Version
    Version10 = CVariant
    0x10
    cOfVersion Version
    Version13 = CVariant
    0x13

    cOfVariant :: Variant -> CVariant
    cOfVariant :: Variant -> CVariant
    cOfVariant Variant
    Argon2d  = CVariant
    0
    cOfVariant Variant
    Argon2i  = CVariant
    1
    cOfVariant Variant
    Argon2id = CVariant
    2

    csizeOfInt :: Int -> CSize
    csizeOfInt :: Int -> CSize
    csizeOfInt = Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral

    foreign import ccall unsafe "crypton_argon2_hash"
        argon2_hash :: Word32 -> Word32 -> Word32
                    -> Ptr Pass -> CSize
                    -> Ptr Salt -> CSize
                    -> Ptr HashOut -> CSize
                    -> CVariant
                    -> CVersion
                    -> IO CInt