{-| Module : Botan.Bindings.PwdHash Description : Password hashing Copyright : (c) 2023-2024, Apotheca Labs (c) 2024-2025, Haskell Foundation License : BSD-3-Clause Maintainer : joris@well-typed.com, leo@apotheca.io Stability : experimental Portability : POSIX This module is based on the [Password Based Key Deriviation](https://botan.randombit.net/handbook/api_ref/pbkdf.html) section of the C++ API reference. -} {-# LANGUAGE CApiFFI #-} {-# LANGUAGE OverloadedStrings #-} module Botan.Bindings.PwdHash ( botan_pwdhash , botan_pwdhash_timed -- * Available schemes -- $available-schemes , pattern BOTAN_PBKDF_PBKDF2 , pattern BOTAN_PBKDF_SCRYPT , pattern BOTAN_PBKDF_ARGON2D , pattern BOTAN_PBKDF_ARGON2I , pattern BOTAN_PBKDF_ARGON2ID , pattern BOTAN_PBKDF_BCRYPT_PBKDF , pattern BOTAN_PBKDF_OPENPGP_S2K ) where import Botan.Bindings.ConstPtr import Data.String import Data.Word import Foreign.C.Types import Foreign.Ptr {------------------------------------------------------------------------------- Password hashing -------------------------------------------------------------------------------} -- | Derive a cryptographic key from a passphrase using algorithm-specific parameters -- -- NOTE: the interpretation of parameters @param1@, @param2@, and @param3@ are -- different depending on the PBKDF algorithm that is picked. See the -- documentation of the -- [@from_params@](https://botan.randombit.net/handbook/api_ref/pbkdf.html#passwordhash) -- C++ function for more information about the meaning of the parameters. -- foreign import capi safe "botan/ffi.h botan_pwdhash" botan_pwdhash :: ConstPtr CChar -- ^ __algo__: PBKDF algorithm, e.g., "PBKDF2(SHA-256)" or "Scrypt" -> CSize -- ^ __param1__: the first PBKDF algorithm parameter -> CSize -- ^ __param2__: the second PBKDF algorithm parameter (may be zero if unneeded) -> CSize -- ^ __param3__: the third PBKDF algorithm parameter (may be zero if unneeded) -> Ptr Word8 -- ^ __out[]__: buffer to store the derived key, must be of out_len bytes -> CSize -- ^ __out_len__: the desired length of the key to produce -> ConstPtr CChar -- ^ __passphrase__: the password to derive the key from -> CSize -- ^ __passphrase_len__: if > 0, specifies length of password. If len == 0, then -- strlen will be called on passphrase to compute the length. -> ConstPtr Word8 -- ^ __salt[]__: a randomly chosen salt -> CSize -- ^ __salt_len__: length of salt in bytes -> IO CInt -- ^ 0 on success, a negative value on failure -- | Derive a cryptographic key from a passphrase using algorithm-specific -- parameters that are tuned automatically for a desired running time of the -- algorithm. -- -- NOTE: for the @Argon2@ and @Scrypt@ PBKDF algorithms, 'botan_pwdhash_timed' -- returns parameters in a different order than the order in which they should -- be passed to 'botan_pwdhash'. This is a known issue with the Botan C++ -- library. See <https://github.com/randombit/botan/issues/2144> for more -- information. -- -- 'botan_pwdhash_timed' always returns parameters in this order: -- -- > (iterations, parallelism, memoryParam) -- -- 'botan_pwdhash' shoulds be given parameters in this order for the -- @Argon2@ and @Scrypt@ algorithms: -- -- > param1 = memoryParam -- > param2 = iterations -- > param3 = parallelism -- foreign import capi safe "botan/ffi.h botan_pwdhash_timed" botan_pwdhash_timed :: ConstPtr CChar -- ^ __algo__: PBKDF algorithm, e.g., "Scrypt" or "PBKDF2(SHA-256)" -> Word32 -- ^ __msec__: the desired runtime in milliseconds -> Ptr CSize -- ^ __param1__: will be set to the first PBKDF algorithm parameter -> Ptr CSize -- ^ __param2__: will be set to the second PBKDF algorithm parameter (may be zero if unneeded) -> Ptr CSize -- ^ __param3__: will be set to the third PBKDF algorithm parameter (may be zero if unneeded) -> Ptr Word8 -- ^ __out[]__: buffer to store the derived key, must be of out_len bytes -> CSize -- ^ __out_len__: the desired length of the key to produce -> ConstPtr CChar -- ^ __passphrase__: the password to derive the key from -> CSize -- ^ __passphrase_len__: if > 0, specifies length of password. If len == 0, then -- strlen will be called on passphrase to compute the length. -> ConstPtr Word8 -- ^ __salt[]__: a randomly chosen salt -> CSize -- ^ __salt_len__: length of salt in bytes -> IO CInt -- ^ 0 on success, a negative value on failure {------------------------------------------------------------------------------- Available schemes -------------------------------------------------------------------------------} {- $available-schemes A number of algorithms are available to be used as password derivation schemes. An algorithm is selected by passing the /algorithm specification name/ of the algorithm as a string to the password hashing functions. In some cases an algorithm specification name is just the /algorithm name/, like @"Scrypt"@. In other cases an algorithm specification name is a combination of an algorithm name paired with some parameters, such as @"PKBDF2(SHA-256)"@ where @"PBKDF2"@ is the algorithm name followed by a single parameter. Pattern synonyms are included for each available /algorithm name/. Where necessary, such as in the @"PBKDF2"@ case, these algorithm names should be manually extended to full algorithm specification names. See the [Available Schemes](https://botan.randombit.net/handbook/api_ref/pbkdf.html#available-schemes) section of the C++ API reference for more information about available schemes. -} pattern BOTAN_PBKDF_PBKDF2 , BOTAN_PBKDF_SCRYPT , BOTAN_PBKDF_ARGON2D , BOTAN_PBKDF_ARGON2I , BOTAN_PBKDF_ARGON2ID , BOTAN_PBKDF_BCRYPT_PBKDF , BOTAN_PBKDF_OPENPGP_S2K :: (Eq a, IsString a) => a -- | -- >>> BOTAN_PBKDF_PBKDF2 @String -- "PBKDF2" pattern $bBOTAN_PBKDF_PBKDF2 :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_PBKDF2 :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_PBKDF2 = "PBKDF2" -- | -- >>> BOTAN_PBKDF_SCRYPT @String -- "Scrypt" pattern $bBOTAN_PBKDF_SCRYPT :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_SCRYPT :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_SCRYPT = "Scrypt" -- | -- >>> BOTAN_PBKDF_ARGON2D @String -- "Argon2d" pattern $bBOTAN_PBKDF_ARGON2D :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_ARGON2D :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_ARGON2D = "Argon2d" -- | -- >>> BOTAN_PBKDF_ARGON2I @String -- "Argon2i" pattern $bBOTAN_PBKDF_ARGON2I :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_ARGON2I :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_ARGON2I = "Argon2i" -- | -- >>> BOTAN_PBKDF_ARGON2ID @String -- "Argon2id" pattern $bBOTAN_PBKDF_ARGON2ID :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_ARGON2ID :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_ARGON2ID = "Argon2id" -- | -- >>> BOTAN_PBKDF_BCRYPT_PBKDF @String -- "Bcrypt-PBKDF" pattern $bBOTAN_PBKDF_BCRYPT_PBKDF :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_BCRYPT_PBKDF :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_BCRYPT_PBKDF = "Bcrypt-PBKDF" -- | -- >>> BOTAN_PBKDF_OPENPGP_S2K @String -- "OpenPGP-S2K" pattern $bBOTAN_PBKDF_OPENPGP_S2K :: forall a. (Eq a, IsString a) => a $mBOTAN_PBKDF_OPENPGP_S2K :: forall {r} {a}. (Eq a, IsString a) => a -> ((# #) -> r) -> ((# #) -> r) -> r BOTAN_PBKDF_OPENPGP_S2K = "OpenPGP-S2K"