Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions botan-bindings/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
experimental `x509` code is moved.
* PATCH: enable `-Wall` in addition to a number of other GHC warnings.
* PATCH: use `GHC2021` as the default language.
* PATCH: update documentation in the `Botan.Bindings.PwdHash` module.

## 0.1.0.0 -- 2025-09-17

Expand Down
102 changes: 87 additions & 15 deletions botan-bindings/src/Botan/Bindings/PwdHash.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,96 @@ Maintainer : joris@well-typed.com, leo@apotheca.io
Stability : experimental
Portability : POSIX

Derive a key from a passphrase
This module is based on the [Password Based Key
Deriviation](https://botan.randombit.net/handbook/api_ref/pbkdf.html) section of
the C++ Botan documentation.
-}

{-# LANGUAGE CApiFFI #-}

module Botan.Bindings.PwdHash (
-- * Available schemes
-- $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
-- * Password hashing
, botan_pwdhash
, botan_pwdhash_timed
) where

import Botan.Bindings.Prelude

{-------------------------------------------------------------------------------
Available schemes
-------------------------------------------------------------------------------}

-- $schemes
--
-- There are a number of schemes available to be used as the PBKDF algorithm for
-- 'botan_pwdhash' and 'botan_pwdhash_timed', which are listed in the [Available
-- Schemes](https://botan.randombit.net/handbook/api_ref/pbkdf.html#available-schemes)
-- section of the C++ Botan documentation. A pattern synonym for the name of
-- each of the available schemes is included in these Haskell bindings.

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_SCRYPT
, BOTAN_PBKDF_ARGON2D
, BOTAN_PBKDF_ARGON2I
, BOTAN_PBKDF_ARGON2ID
, BOTAN_PBKDF_BCRYPT_PBKDF
, BOTAN_PBKDF_OPENPGP_S2K
:: (Eq a, IsString a) => a

-- | Name of the @PBKDF2@ scheme
--
-- NOTE: @PBKDF2@ is not a valid scheme name to pass to 'botan_pwdhash' or
-- 'botan_pwdhash_timed' directly. Instead, the scheme name should be
-- parameterised by a hash function. For more information see the [Available
-- Schemes](https://botan.randombit.net/handbook/api_ref/pbkdf.html#available-schemes)
-- section of the C++ Botan documentation
pattern BOTAN_PBKDF_PBKDF2 = "PBKDF2"

-- | Name of the @Scrypt@ scheme
pattern BOTAN_PBKDF_SCRYPT = "Scrypt"

-- | Name of the @Argon2d@ scheme
pattern BOTAN_PBKDF_ARGON2D = "Argon2d"

-- | Name of the @Argon2i@ scheme
pattern BOTAN_PBKDF_ARGON2I = "Argon2i"

-- | Name of the @Argon2d@ scheme
pattern BOTAN_PBKDF_ARGON2ID = "Argon2id"

-- | Name of the @Bcrypt-PBKDF@ scheme
pattern BOTAN_PBKDF_BCRYPT_PBKDF = "Bcrypt-PBKDF"

-- | Name of the @OpenPGP-S2K@ scheme
--
-- NOTE: @OpenPGP-S2K@ is not a valid scheme name to pass to 'botan_pwdhash' or
-- 'botan_pwdhash_timed' directly. Instead, the scheme name should be
-- parameterised by a hash function. For more information see the [Available
-- Schemes](https://botan.randombit.net/handbook/api_ref/pbkdf.html#available-schemes)
-- section of the C++ Botan documentation
pattern BOTAN_PBKDF_OPENPGP_S2K = "OpenPGP-S2K"

-- | Derive a key from a passphrase using algorithm-specific parameters
{-------------------------------------------------------------------------------
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"
Expand All @@ -55,20 +108,39 @@ foreign import capi safe "botan/ffi.h botan_pwdhash"
-> 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.
-- 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 key from a passphrase using parameters generated over a specific duration
-- | 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 password hash parameter
-> Ptr CSize -- ^ __param2__: will be set to the second password hash parameter
-> Ptr CSize -- ^ __param3__: will be set to the third password hash parameter
-> 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
Expand Down
3 changes: 3 additions & 0 deletions botan-low/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
experimental `x509` code is moved.
* PATCH: enable `-Wall` in addition to a number of other GHC warnings.
* PATCH: use `GHC2021` as the default language.
* BREAKING: `Botan.Low.PwdHash.pbkdf2` now takes a `HashName` instead of a
`MacName`.
* PATCH: update documentation in the `Botan.Low.PwdHash` module.

## 0.0.2.0 -- 2025-09-17

Expand Down
46 changes: 21 additions & 25 deletions botan-low/botan-low.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ common language
default-language: GHC2021
default-extensions:
DerivingStrategies
LambdaCase
PatternSynonyms
RecordWildCards
RoleAnnotations
ViewPatterns

library
import: warnings, language
Expand Down Expand Up @@ -128,6 +130,25 @@ library
, deepseq >=1.1 && <2
, text >=1.2 && <1.3 || >=2.0 && <2.2

test-suite test
import: warnings, language
type: exitcode-stdio-1.0
main-is: Main.hs
hs-source-dirs: test/
build-depends:
, base
, botan-low
, bytestring
, hspec
, QuickCheck
, tasty
, tasty-hspec
, tasty-hunit

other-modules:
Test.Botan.Low.PwdHash
Test.Prelude

--
-- Unit tests
--
Expand Down Expand Up @@ -697,31 +718,6 @@ test-suite botan-low-pubkey-x25519-tests

-- TODO: Pubkey folder tests

test-suite botan-low-pwdhash-tests
import: warnings, language

-- TODO: temporarily disabled because the test suite fails. See issue #33.
buildable: False
type: exitcode-stdio-1.0
main-is: Botan/Low/PwdHashSpec.hs
hs-source-dirs: test/
build-depends:
, base
, botan-bindings
, botan-low
, bytestring
, hspec
, QuickCheck

other-modules:
Paths_botan_low
Test.Prelude

autogen-modules: Paths_botan_low
default-extensions:
NoImplicitPrelude
OverloadedStrings

test-suite botan-low-rng-tests
import: warnings, language

Expand Down
Loading