{-# LANGUAGE CApiFFI #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE Trustworthy #-} {-# OPTIONS_GHC -Wno-unused-imports #-} -- | -- -- Module: LibSodium.Bindings.Scrypt -- Description: Direct bindings to the scrypt password hashing function. -- Copyright: (C) Hécate Moonlight 2022 -- License: BSD-3-Clause -- Maintainer: The Haskell Cryptography Group -- Stability: Stable -- Portability: GHC only module LibSodium.Bindings.Scrypt ( -- * Introduction -- $introduction -- * Key Derivation cryptoPWHashScryptSalsa208SHA256 -- * Password storage , cryptoPWHashScryptSalsa208SHA256Str , cryptoPWHashScryptSalsa208SHA256StrVerify -- * Constants , cryptoPWHashScryptSalsa208SHA256BytesMin , cryptoPWHashScryptSalsa208SHA256BytesMax , cryptoPWHashScryptSalsa208SHA256PasswdMin , cryptoPWHashScryptSalsa208SHA256PasswdMax , cryptoPWHashScryptSalsa208SHA256SaltBytes , cryptoPWHashScryptSalsa208SHA256StrBytes , cryptoPWHashScryptSalsa208SHA256StrPrefix , cryptoPWHashScryptSalsa208SHA256OpsLimitMin , cryptoPWHashScryptSalsa208SHA256OpsLimitMax , cryptoPWHashScryptSalsa208SHA256MemLimitMin , cryptoPWHashScryptSalsa208SHA256MemLimitMax , cryptoPWHashScryptSalsa208SHA256OpsLimitInteractive , cryptoPWHashScryptSalsa208SHA256MemLimitInteractive , cryptoPWHashScryptSalsa208SHA256OpsLimitSensitive , cryptoPWHashScryptSalsa208SHA256MemLimitSensitive ) where import Foreign (Ptr) import Foreign.C (CChar (CChar), CInt (CInt), CSize (CSize), CUChar, CULLong (CULLong)) -- $introduction -- This is an implementation of the scrypt password hashing function. -- However, unless you have specific reasons to use scrypt, you __should__ instead consider the default function Argon2. -- -- == Glossary -- -- * /opslimit/: The maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key. -- * /memlimit/: The maximum amount of RAM in bytes that the function will use. -- -- == Guidelines for choosing scrypt parameters -- -- Start by determining how much memory the scrypt 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? -- The /memlimit/ parameter should be a power of 2. -- -- Do not use anything less than 16 MiB, even for interactive use. -- A reasonable starting point for /opslimit/ is @memlimit / 32@. -- Measure how long the scrypt function needs to hash a password. -- If this is way too long for your application, reduce /memlimit/ and adjust /opslimit/ using the above formula. -- If the function is so fast that you can afford it to be more computationally intensive without any usability issues, 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](https://www.openwall.com/passwdqc/) can help enforce this. -- -- == Notes -- -- Do not use constants to verify a password or produce a deterministic output. -- Save the parameters alongside the hash instead. -- By doing so, passwords can be rehashed using different parameters if required later on. -- -- By design, a password whose length is 65 bytes or more is reduced to SHA-256(password). -- This can have security implications if the password is present in another password database -- using raw, unsalted SHA-256 or when upgrading passwords previously hashed with unsalted SHA-256 to scrypt. -- -- It is highly recommended to use 'LibSodium.Bindings.SecureMemory.lock' -- to lock memory regions storing plaintext passwords and to call -- 'LibSodium.Bindings.SecureMemory.unlock' right after -- 'cryptoPWHashScryptSalsa208SHA256Str' and 'cryptoPWHashScryptSalsa208SHA256StrVerify' -- return. -- | Derive a key from a password. -- -- For interactive, online operations, 'cryptoPWHashScryptSalsa208SHA256OpsLimitInteractive' -- and 'cryptoPWHashScryptSalsa208SHA256MemLimitInteractive' provide a safe baseline to be used. -- However, using higher values may improve security. -- -- For highly sensitive data, 'cryptoPWHashScryptSalsa208SHA256OpsLimitSensitive' and -- 'cryptoPWHashScryptSalsa208SHA256MemLimitSensitive' can be used as an alternative. -- However, with these parameters, deriving a key takes about -- 2 seconds on a 2.8 GHz Core i7 CPU and requires up to 1 GiB of dedicated RAM. -- -- The salt should be unpredictable. 'LibSodium.Bindings.Random.randombytesBuf' -- is the easiest way to fill the 'cryptoPWHashScryptSalsa208SHA256SaltBytes' bytes -- of the salt. -- -- Keep in mind that to produce the same key from the same password, the same salt, -- opslimit, and memlimit values must be used. Therefore, these parameters must be stored for each user. -- -- /See:/ [crypto_pwhash_scryptsalsa208sha256()](https://doc.libsodium.org/advanced/scrypt#key-derivation) -- -- @since 0.0.1.0 foreign import capi "sodium.h crypto_pwhash_scryptsalsa208sha256" cryptoPWHashScryptSalsa208SHA256 :: Ptr CUChar -- ^ A pointer to the computed key. -> CULLong -- ^ The length of the computed key. -- Should be between 'cryptoPWHashScryptSalsa208SHA256BytesMin' -- and 'cryptoPWHashScryptSalsa208SHA256BytesMax' (~127 GB). -> Ptr CChar -- ^ A pointer to the password from which the key is derived -> CULLong -- ^ The length of the password. -- Should be between 'cryptoPWHashScryptSalsa208SHA256PasswdMin' -- and 'cryptoPWHashScryptSalsa208SHA256PasswdMax'. -> Ptr CUChar -- ^ The salt, of length 'cryptoPWHashScryptSalsa208SHA256SaltBytes'. -> CULLong -- ^ /opslimit:/ The maximum amount of computations to perform. -- Must be between 'cryptoPWHashScryptSalsa208SHA256OpsLimitMin' -- and 'cryptoPWHashScryptSalsa208SHA256OpsLimitMax'. -> CSize -- ^ /memlimit:/ The maximum amount of RAM in bytes that the function will use. -- It is highly recommended to allow the function to use at least 16 MiB. -- This number must be between 'cryptoPWHashScryptSalsa208SHA256MemLimitMin' -- and 'cryptoPWHashScryptSalsa208SHA256MemLimitMax'. -> IO CInt -- ^ Returns 0 on success, -1 if the computation didn't complete, -- usually because the operating system refused to allocate the amount of -- requested memory. ---------------------- -- Password Storage -- ---------------------- -- | Generate an ASCII C-String string which includes: -- -- * The result of a memory-hard, CPU-intensive hash function applied to the password; -- * The automatically generated salt used for the previous computation; -- * The other parameters required to verify the password: opslimit and memlimit. -- -- /See:/ [crypto_pwhash_scryptsalsa208sha256_str()](https://doc.libsodium.org/advanced/scrypt#password-storage) -- -- @since 0.0.1.0 foreign import capi "sodium.h crypto_pwhash_scryptsalsa208sha256_str" cryptoPWHashScryptSalsa208SHA256Str :: Ptr CChar -- ^ A pointer to the buffer receiving the string. -> Ptr CChar -- ^ The password -> CULLong -- ^ Password length -> CULLong -- ^ /opslimit:/ The maximum amount of computations to perform. -- The 'cryptoPWHashScryptSalsa208SHA256OpsLimitInteractive' constant -- is a safe baseline value to use. -> CSize -- ^ /memlimit:/ The maximum amount of RAM in bytes that the function will use. -- The 'cryptoPWHashScryptSalsa208SHA256MemLimitInteractive' constant -- is a safe baseline value to use. -> IO CInt -- ^ Returns 0 on success, -1 on error. -- | Verify that the password verification string is valid for the associated password. -- -- /See:/ [crypto_pwhash_scryptsalsa208sha256_str_verify()](https://doc.libsodium.org/advanced/scrypt#password-storage) -- -- @since 0.0.1.0 foreign import capi "sodium.h crypto_pwhash_scryptsalsa208sha256_str_verify" cryptoPWHashScryptSalsa208SHA256StrVerify :: Ptr CChar -- ^ The password verification C-string, of size 'cryptoPWHashScryptSalsa208SHA256StrBytes' bytes. -> Ptr CChar -- ^ The password. -> CULLong -- ^ The password length. -> IO CInt -- ^ Returns 0 on success, -1 on password verification failure. --------------- -- Constants -- --------------- -- | Minimum size of the computed key. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_BYTES_MIN" cryptoPWHashScryptSalsa208SHA256BytesMin :: CSize -- | Maximum size of the computed key (~127GB). -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_BYTES_MAX" cryptoPWHashScryptSalsa208SHA256BytesMax :: CSize -- | Minimum size of the password. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN" cryptoPWHashScryptSalsa208SHA256PasswdMin :: CSize -- | Maximum size of the password. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX" cryptoPWHashScryptSalsa208SHA256PasswdMax :: CSize -- | Length of the salt used by 'cryptoPWHashScryptSalsa208SHA256'. -- The easiest way to get a salt is to use 'LibSodium.Bindings.Random.randombytesBuf'. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_SALTBYTES" cryptoPWHashScryptSalsa208SHA256SaltBytes :: CSize -- | Length of the buffer receiving the string when using -- 'cryptoPWHashScryptSalsa208SHA256Str'. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_STRBYTES" cryptoPWHashScryptSalsa208SHA256StrBytes :: CSize -- | The string prefix that is prepended to the computed keys. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_STRPREFIX" cryptoPWHashScryptSalsa208SHA256StrPrefix :: Ptr CChar -- | The minimum amount of operations during the computation process -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN" cryptoPWHashScryptSalsa208SHA256OpsLimitMin :: CSize -- | The maximum amount of operations during the computation process -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX" cryptoPWHashScryptSalsa208SHA256OpsLimitMax :: CSize -- | The minimum amount of memory during the computation process -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN" cryptoPWHashScryptSalsa208SHA256MemLimitMin :: CSize -- | The maximum amount of memory during the computation process -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX" cryptoPWHashScryptSalsa208SHA256MemLimitMax :: CSize -- | The amount of operations most suitable for an interactive usage. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE" cryptoPWHashScryptSalsa208SHA256OpsLimitInteractive :: CSize -- | The amount of memory most suitable for an interactive usage. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE" cryptoPWHashScryptSalsa208SHA256MemLimitInteractive :: CSize -- | The amount of operations most suitable for for highly sensitive data. -- -- ⚠️ using the sensitive parameters can take up to 2 seconds on a 2.8GHz Core i7 CPU -- and require up to 1GiB of dedicated RAM. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE" cryptoPWHashScryptSalsa208SHA256OpsLimitSensitive :: CSize -- | The amount of memory most suitable for for highly sensitive data. -- -- ⚠️ using the sensitive parameters can take up to 2 seconds on a 2.8GHz Core i7 CPU -- and require up to 1GiB of dedicated RAM. -- -- @since 0.0.1.0 foreign import capi "sodium.h value crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE" cryptoPWHashScryptSalsa208SHA256MemLimitSensitive :: CSize