{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE Trustworthy #-}

-- |
--
-- Module: LibSodium.Bindings.PasswordHashing
-- Description: Direct bindings to the password hashing primitives of Libsodium.
-- Copyright: (C) Hécate Moonlight 2022
-- License: BSD-3-Clause
-- Maintainer: The Haskell Cryptography Group
-- Stability: Stable
-- Portability: GHC only
module LibSodium.Bindings.PasswordHashing
  ( -- * Introduction
    -- $introduction

    -- * Operations
    cryptoPWHash
  , cryptoPWHashStr
  , cryptoPWHashStrVerify
  , cryptoPWHashStrNeedsRehash

    -- * Constants
  , cryptoPWHashAlgDefault
  , cryptoPWHashAlgArgon2I13
  , cryptoPWHashAlgArgon2ID13
  , cryptoPWHashSaltBytes
  , cryptoPWHashPasswdMin
  , cryptoPWHashPasswdMax
  , cryptoPWHashOpsLimitInteractive
  , cryptoPWHashOpsLimitSensitive
  , cryptoPWHashOpsLimitModerate
  , cryptoPWHashOpsLimitMin
  , cryptoPWHashOpsLimitMax
  , cryptoPWHashMemLimitModerate
  , cryptoPWHashMemLimitInteractive
  , cryptoPWHashMemLimitSensitive
  , cryptoPWHashMemLimitMin
  , cryptoPWHashMemLimitMax
  , cryptoPWHashBytesMax
  , cryptoPWHashBytesMin
  , cryptoPWHashStrBytes
  , cryptoPWHashStrPrefix
  )
where

import Foreign (Ptr)
import Foreign.C (CChar, CInt (CInt), CLLong (CLLong), CSize (CSize), CUChar, CULLong (CULLong))

-- $introduction
-- This modules provides an API that can be used both for key derivation using a low-entropy input and password storage.
--
-- === Guidelines for choosing the parameters
-- Start by determining how much memory the function can use.
-- What will be the highest number of threads/processes evaluating the function simultaneously
-- (ideally, no more than 1 per CPU core)? How much physical memory is guaranteed to be available?
--
-- Set @memlimit@ to the amount of memory you want to reserve for password hashing.
--
-- Then set @opslimit@ to 3 and measure the time it takes to hash a password.
--
-- If this is way too long for your application, reduce @memlimit@, but keep @opslimit@ set to 3.
--
-- If the function is so fast that you can afford it to be more computationally intensive without
-- any usability issues, then increase @opslimit@.
--
-- For online use (e.g. logging in on a website), a 1 second computation is likely to be the
-- acceptable maximum.
--
-- For interactive use (e.g. a desktop application), a 5 second pause after having entered a
-- password is acceptable if the password doesn't need to be entered more than once per session.
--
-- For non-interactive and infrequent use (e.g. restoring an encrypted backup),
-- an even slower computation can be an option.
--
-- However, the best defense against brute-force password cracking is to use strong passwords.
-- Libraries such as [passwdqc](http://www.openwall.com/passwdqc/) can help enforce this.

-- | This functions derives a key from a password. The computed key is then stored in the @out@ parameter.
--
-- /See:/ [crypto_pwhash()](https://doc.libsodium.org/password_hashing/default_phf)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_pwhash"
  cryptoPWHash
    :: Ptr CUChar
    -- ^ @out@ parameter. It represents the address of a dedicated storage area of @outlen@ bytes.
    -> CLLong
    -- ^ @outlen@ parameter. It is the length of the key derived from the @passwd@ parameter.
    -- This should be a least 'cryptoPWHashBytesMin' and at most 'cryptoPWHashBytesMax'.
    -> Ptr CChar
    -- ^ @passwd@ parameter. It is a pointer to the password that is to be derived.
    -> CULLong
    -- ^ @passwdlen@ parameter. It is the size of the password.
    -> Ptr CUChar
    -- ^ @salt@ parameter. It is of a fixed length established by 'cryptoPWHashSaltBytes'. It should be unpredictable.
    -- 'LibSodium.Bindings.Random.randombytesBuf' is the best way to fill the 'cryptoPWHashSaltBytes' of the
    -- salt.
    -> CULLong
    -- ^ @opslimit@ parameter. It represents the maximum amount of computations to perform. Raising this number will make the function require more CPU cycles
    -- to compute a key. This number must be between 'cryptoPWHashOpsLimitMin' and 'cryptoPWHashOpsLimitMax'.
    -> CSize
    -- ^ @memlimit@ parameter. It is the maximum amount of RAM in bytes that the function will use.
    -- This number must be between 'cryptoPWHashMemLimitMin' 'cryptoPWHashMemLimitMax'
    -> CInt
    -- ^ @alg@ parameter. It is an identifier for the algorithm to use and should be set to one of the following values:
    --     'cryptoPWHashAlgDefault', 'cryptoPWHashAlgArgon2I13' or 'cryptoPWHashAlgArgon2ID13'.
    -> IO CInt
    -- ^ The return code is 0 on success and -1 if the computation didn't complete,
    -- usually because the operating system refused to allocate the amount of requested memory.

-- | This function is used for password storage, like an SQL database.
-- It stores an ASCII-encoded string into its @out@ parameter,
-- which includes:
--
--   * The result of a memory-hard, CPU-intensive hash function applied to the password passwd of length passwdlen;
--   * The automatically generated salt used for the previous computation;
--   * The other parameters required to verify the password, including the algorithm identifier, its version, opslimit, and memlimit.
--
-- The @out@ parameter must be a dedicated storage area that's large enough to hold 'cryptoPWHashStrBytes' bytes,
-- but the actual output string may be shorter.
--
-- /See:/ [crypto_pwhash_str()](https://doc.libsodium.org/password_hashing/default_phf)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_pwhash_str"
  cryptoPWHashStr
    :: Ptr CChar
    -- ^ @out@ parameter. It must be of size 'cryptoPWHashStrBytes'.
    -> Ptr CChar
    -- ^ @passwd@ parameter. Points to a password to be stored.
    -> CULLong
    -- ^ @passwdlen@ parameter. Length of the password.
    -> CULLong
    -- ^ @opslimit@ parameter. It represents the maximum amount of computations to perform.
    -> CSize
    -- ^ @memlimit@ parameter. It is the maximum amount of RAM in bytes that the function will use.
    -> IO CInt
    -- ^ The function returns 0 on success and -1 if it didn't complete successfully.

-- | This function verifies that the @str@ parameter is a valid password verification string
-- (as generated by 'cryptoPWHashStr'), for a @passwd@ whose length is @passwdlen@.
--
-- /See:/ [crypto_pwhash_str_verify()](https://doc.libsodium.org/password_hashing/default_phf)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_pwhash_str_verify"
  cryptoPWHashStrVerify
    :: Ptr CChar
    -- ^ @str@ parameter. It must be zero-terminated.
    -> Ptr CChar
    -- ^ @passwd@ parameter.
    -> CULLong
    -- ^ @passwdlen@ parameter.
    -> IO CInt
    -- ^ It returns 0 if the verification succeeds and -1 on error.

-- | This functions checks if a password verification string @str@ matches the parameters @opslimit@, @memlimit@, and the current default algorithm.
--
-- /See:/ [crypto_pwhash_str_needs_rehash()](https://doc.libsodium.org/password_hashing/default_phf)
--
-- @since 0.0.1.0
foreign import capi "sodium.h crypto_pwhash_str_needs_rehash"
  cryptoPWHashStrNeedsRehash
    :: Ptr CChar
    -- ^ @str@ parameter.
    -> CULLong
    -- ^ @opslimit@ parameter.
    -> CSize
    -- ^ @memlimit@ parameter.
    -> IO CInt
    -- ^ The function returns 0 if the parameters already match the given ones, and returns 1 on error. In particular, It will return 1 if the string appears to be correct but doesn't match the given parameters. In that situation, applications may want to compute a new hash using the current parameters the next time the user logs in.

-- | Numeric indicator for the default algorithm, Argon2id v1.3.
--
-- /See:/ [crypto_pwhash_ALG_DEFAULT](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_ALG_DEFAULT"
  cryptoPWHashAlgDefault :: CInt

-- | Numeric indicator for the Argon2i v1.3 algorithm.
--
-- /See:/ [crypto_pwhash_ALG_ARGON2I13](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_ALG_ARGON2I13"
  cryptoPWHashAlgArgon2I13 :: CInt

-- | Numeric indicator for the Argon2id v1.3 algorithm.
--
-- /See:/ [crypto_pwhash_ALG_ARGON2ID13](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_ALG_ARGON2ID13"
  cryptoPWHashAlgArgon2ID13 :: CInt

-- | Size of the salt parameter, in bytes.
--
-- /See:/ [crypto_pwhash_SALTBYTES](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
--  @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_SALTBYTES"
  cryptoPWHashSaltBytes :: CSize

-- | Minimum size of a password, in bytes.
--
-- /See:/ [crypto_pwhash_PASSWD_MIN](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_PASSWD_MIN"
  cryptoPWHashPasswdMin :: CSize

-- | Maximum size of a password, in bytes.
--
-- /See:/ [crypto_pwhash_PASSWD_MAX](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
--  @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_PASSWD_MAX"
  cryptoPWHashPasswdMax :: CSize

-- | Upper limit of operations in an interactive setting.
--
-- /See:/ [crypto_pwhash_OPSLIMIT_INTERACTIVE](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
--  @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_OPSLIMIT_INTERACTIVE"
  cryptoPWHashOpsLimitInteractive :: CULLong

-- | Cryptographic perations done in a sensitive setting.
--
-- /See:/ [crypto_pwhash_OPSLIMIT_SENSITIVE](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
--  @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_OPSLIMIT_SENSITIVE"
  cryptoPWHashOpsLimitSensitive :: CULLong

-- | Cryptographic operations in a moderately sensitive setting.
--
-- /See:/ [crypto_pwhash_OPSLIMIT_MODERATE](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
--  @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_OPSLIMIT_MODERATE"
  cryptoPWHashOpsLimitModerate :: CULLong

-- | Lower limit of cryptographic operations.
--
-- /See:/ [crypto_pwhash_OPSLIMIT_MIN](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_OPSLIMIT_MIN"
  cryptoPWHashOpsLimitMin :: CULLong

-- | Upper limit of cryptographic operations.
--
-- /See:/ [crypto_pwhash_OPSLIMIT_MAX](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_OPSLIMIT_MAX"
  cryptoPWHashOpsLimitMax :: CULLong

-- | Memory used in a moderately sensitive setting, in bytes.
--
-- /See:/ [crypto_pwhash_MEMLIMIT_MODERATE](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_MEMLIMIT_MODERATE"
  cryptoPWHashMemLimitModerate :: CSize

-- | Memory used in an interactive setting, in bytes.
--
-- /See:/ [crypto_pwhash_MEMLIMIT_INTERACTIVE](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_MEMLIMIT_INTERACTIVE"
  cryptoPWHashMemLimitInteractive :: CSize

-- | Memory used in a sensitive setting, in bytes.
--
-- /See:/ [crypto_pwhash_MEMLIMIT_INTERACTIVE](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_MEMLIMIT_SENSITIVE"
  cryptoPWHashMemLimitSensitive :: CSize

-- | Minimum amount of memory that the caller can use, in bytes.
--
-- /See:/ [crypto_pwhash_MEMLIMIT_MIN](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_MEMLIMIT_MIN"
  cryptoPWHashMemLimitMin :: CSize

-- | Maximum amount of memory that the caller can use, in bytes.
--
-- /See:/ [crypto_pwhash_MEMLIMIT_MAX](https://doc.libsodium.org/password_hashing/default_phf#constants)
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_MEMLIMIT_MAX"
  cryptoPWHashMemLimitMax :: CSize

-- | Maximum size of the hash, in bytes.
--
-- /See:/ [crypto_pwhash_BYTES_MAX](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_BYTES_MAX"
  cryptoPWHashBytesMax :: CULLong

-- | Minimum size of the hash, in bytes.
--
-- /See:/ [crypto_pwhash_BYTES_MIN](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_BYTES_MIN"
  cryptoPWHashBytesMin :: CULLong

-- | Expected size of a hash's textual representation, as generated by 'cryptoPWHashStr'.
--
-- /See:/ [crypto_pwhash_BYTES_MIN](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_STRBYTES"
  cryptoPWHashStrBytes :: CSize

-- | Prefix used in the hash's textual representation, as generated by 'cryptoPWHashStr': @"$argon2id$"@
--
-- /See:/ [crypto_pwhash_STRPREFIX](https://doc.libsodium.org/password_hashing/default_phf#constants)
--
-- @since 0.0.1.0
foreign import capi "sodium.h value crypto_pwhash_STRPREFIX"
  cryptoPWHashStrPrefix :: Ptr CChar