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 @@ -19,6 +19,7 @@
* 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.
* PATCH: update documentation in the `Botan.Bindings.SRP6` module.

## 0.1.0.0 -- 2025-09-17

Expand Down
64 changes: 32 additions & 32 deletions botan-bindings/src/Botan/Bindings/PwdHash.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ 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++ Botan documentation.
the C++ API reference.
-}

{-# LANGUAGE CApiFFI #-}
Expand Down Expand Up @@ -41,8 +41,8 @@ import Botan.Bindings.Prelude
-- 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.
-- section of the C++ API reference. 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
Expand All @@ -59,7 +59,7 @@ pattern BOTAN_PBKDF_PBKDF2
-- '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
-- section of the C++ API reference.
pattern BOTAN_PBKDF_PBKDF2 = "PBKDF2"

-- | Name of the @Scrypt@ scheme
Expand All @@ -83,7 +83,7 @@ pattern BOTAN_PBKDF_BCRYPT_PBKDF = "Bcrypt-PBKDF"
-- '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
-- section of the C++ API reference.
pattern BOTAN_PBKDF_OPENPGP_S2K = "OpenPGP-S2K"

{-------------------------------------------------------------------------------
Expand All @@ -99,19 +99,19 @@ pattern BOTAN_PBKDF_OPENPGP_S2K = "OpenPGP-S2K"
-- 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
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
Expand All @@ -135,17 +135,17 @@ foreign import capi safe "botan/ffi.h botan_pwdhash"
-- > 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
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
162 changes: 80 additions & 82 deletions botan-bindings/src/Botan/Bindings/SRP6.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,9 @@ Maintainer : [email protected], [email protected]
Stability : experimental
Portability : POSIX

The library contains an implementation of the SRP6-a password
authenticated key exchange protocol.

A SRP client provides what is called a SRP verifier to the server.
This verifier is based on a password, but the password cannot be
easily derived from the verifier (however brute force attacks are
possible). Later, the client and server can perform an SRP exchange,
which results in a shared secret key. This key can be used for
mutual authentication and/or encryption.

SRP works in a discrete logarithm group. Special parameter sets for
SRP6 are defined, denoted in the library as “modp/srp/<size>”, for
example “modp/srp/2048”.

Warning

While knowledge of the verifier does not easily allow an attacker to
get the raw password, they could still use the verifier to impersonate
the server to the client, so verifiers should be protected as carefully
as a plaintext password would be.
This module is based on the [Secure Remote
Password](https://botan.randombit.net/handbook/api_ref/srp.html) section of the
C++ API reference.
-}

{-# LANGUAGE CApiFFI #-}
Expand All @@ -50,79 +33,94 @@ import Botan.Bindings.RNG
-- | Opaque SRP-6 server session struct
data {-# CTYPE "botan/ffi.h" "struct botan_srp6_server_session_struct" #-} BotanSRP6ServerSessionStruct

-- | Botan SRP-6 server session object
-- | SRP-6 server session object
newtype {-# CTYPE "botan/ffi.h" "botan_srp6_server_session_t" #-} BotanSRP6ServerSession
= MkBotanSRP6ServerSession { runBotanSRP6ServerSession :: Ptr BotanSRP6ServerSessionStruct }
deriving newtype (Eq, Ord, Storable)
= MkBotanSRP6ServerSession { runBotanSRP6ServerSession :: Ptr BotanSRP6ServerSessionStruct }
deriving newtype (Eq, Ord, Storable)

-- | Frees all resources of the SRP-6 server session object
--
-- NOTE: this a binding to the /address/ of the
-- @botan_srp6_server_session_destroy@ C function.
foreign import capi safe "botan/ffi.h &botan_srp6_server_session_destroy"
botan_srp6_server_session_destroy
:: FinalizerPtr BotanSRP6ServerSessionStruct
botan_srp6_server_session_destroy
:: FinalizerPtr BotanSRP6ServerSessionStruct

-- | Initialize an SRP-6 server session object
foreign import capi safe "botan/ffi.h botan_srp6_server_session_init"
botan_srp6_server_session_init
:: Ptr BotanSRP6ServerSession -- ^ __srp6__: SRP-6 server session object
-> IO CInt

-- | SRP-6 Server side step 1: Generate a server B-value
botan_srp6_server_session_init
:: Ptr BotanSRP6ServerSession -- ^ __srp6__: SRP-6 server session object
-> IO CInt

-- | SRP-6 Server side step 1
--
-- NOTE: this function should be not be invoked twice on the same server
-- session. Regardless of the result of the first invocation, the second
-- invocation will result in an error. See
-- https://github.com/randombit/botan/issues/5112 for more information. If a
-- second invocation can not be prevented, try it on a newly initialised server
-- session instead.
foreign import capi safe "botan/ffi.h botan_srp6_server_session_step1"
botan_srp6_server_session_step1
:: BotanSRP6ServerSession -- ^ __srp6__: SRP-6 server session object
-> ConstPtr Word8 -- ^ __verifier[]__: the verification value saved from client registration
-> CSize -- ^ __verifier_len__: SRP-6 verifier value length
-> ConstPtr CChar -- ^ __group_id__: the SRP group id
-> ConstPtr CChar -- ^ __hash_id__: the SRP hash in use
-> BotanRNG -- ^ __rng_obj__: a random number generator object
-> Ptr Word8 -- ^ __B_pub[]__: out buffer to store the SRP-6 B value
-> Ptr CSize -- ^ __B_pub_len__: SRP-6 B value length
-> IO CInt -- ^ 0 on success, negative on failure

-- | SRP-6 Server side step 2: Generate the server shared key
botan_srp6_server_session_step1
:: BotanSRP6ServerSession -- ^ __srp6__: SRP-6 server session object
-> ConstPtr Word8 -- ^ __verifier[]__: the verification value saved from client registration
-> CSize -- ^ __verifier_len__: SRP-6 verifier value length
-> ConstPtr CChar -- ^ __group_id__: the SRP group id
-> ConstPtr CChar -- ^ __hash_id__: the SRP hash in use
-> BotanRNG -- ^ __rng_obj__: a random number generator object
-> Ptr Word8 -- ^ __B_pub[]__: out buffer to store the SRP-6 B value
-> Ptr CSize -- ^ __B_pub_len__: SRP-6 B value length
-> IO CInt -- ^ 0 on success, negative on failure

-- | SRP-6 Server side step 2
foreign import capi safe "botan/ffi.h botan_srp6_server_session_step2"
botan_srp6_server_session_step2
:: BotanSRP6ServerSession -- ^ __srp6__: SRP-6 server session object
-> ConstPtr Word8 -- ^ __A[]__: the client's value
-> CSize -- ^ __A_len__: the client's value length
-> Ptr Word8 -- ^ __key[]__: out buffer to store the symmetric key value
-> Ptr CSize -- ^ __key_len__: symmetric key length
-> IO CInt -- ^ 0 on success, negative on failure

-- | SRP-6 Client side step 1: Generate a new SRP-6 verifier
botan_srp6_server_session_step2
:: BotanSRP6ServerSession -- ^ __srp6__: SRP-6 server session object
-> ConstPtr Word8 -- ^ __A[]__: the client's value
-> CSize -- ^ __A_len__: the client's value length
-> Ptr Word8 -- ^ __key[]__: out buffer to store the symmetric key value
-> Ptr CSize -- ^ __key_len__: symmetric key length
-> IO CInt -- ^ 0 on success, negative on failure

-- | Generate a new SRP-6 verifier
foreign import capi safe "botan/ffi.h botan_srp6_generate_verifier"
botan_srp6_generate_verifier
:: ConstPtr CChar -- ^ __identifier__: a username or other client identifier
-> ConstPtr CChar -- ^ __password__: the secret used to authenticate user
-> ConstPtr Word8 -- ^ __salt[]__: a randomly chosen value, at least 128 bits long
-> CSize -- ^ __salt_len__: the length of salt
-> ConstPtr CChar -- ^ __group_id__: specifies the shared SRP group
-> ConstPtr CChar -- ^ __hash_id__: specifies a secure hash function
-> Ptr Word8 -- ^ __verifier[]__: out buffer to store the SRP-6 verifier value
-> Ptr CSize -- ^ __verifier_len__: SRP-6 verifier value length
-> IO CInt -- ^ 0 on success, negative on failure

-- | SRP6a Client side step 2: Generate a client A-value and the client shared key
botan_srp6_generate_verifier
:: ConstPtr CChar -- ^ __identifier__: a username or other client identifier
-> ConstPtr CChar -- ^ __password__: the secret used to authenticate user
-> ConstPtr Word8 -- ^ __salt[]__: a randomly chosen value, at least 128 bits long
-> CSize -- ^ __salt_len__: the length of salt
-> ConstPtr CChar -- ^ __group_id__: specifies the shared SRP group
-> ConstPtr CChar -- ^ __hash_id__: specifies a secure hash function
-> Ptr Word8 -- ^ __verifier[]__: out buffer to store the SRP-6 verifier value
-> Ptr CSize -- ^ __verifier_len__: SRP-6 verifier value length
-> IO CInt -- ^ 0 on success, negative on failure

-- | SRP6a Client side
foreign import capi safe "botan/ffi.h botan_srp6_client_agree"
botan_srp6_client_agree
:: ConstPtr CChar -- ^ __username__: the username we are attempting login for
-> ConstPtr CChar -- ^ __password__: the password we are attempting to use
-> ConstPtr CChar -- ^ __group_id__: specifies the shared SRP group
-> ConstPtr CChar -- ^ __hash_id__: specifies a secure hash function
-> ConstPtr Word8 -- ^ __salt[]__: is the salt value sent by the server
-> CSize -- ^ __salt_len__: the length of salt
-> ConstPtr Word8 -- ^ __uint8_t__: B[] is the server's public value
-> CSize -- ^ __B_len__: is the server's public value length
-> BotanRNG -- ^ __rng_obj__: is a random number generator object
-> Ptr Word8 -- ^ __A[]__: out buffer to store the SRP-6 A value
-> Ptr CSize -- ^ __A_len__: SRP-6 A verifier value length
-> Ptr Word8 -- ^ __K[]__: out buffer to store the symmetric value
-> Ptr CSize -- ^ __K_len__: symmetric key length
-> IO CInt -- ^ 0 on success, negative on failure
botan_srp6_client_agree
:: ConstPtr CChar -- ^ __username__: the username we are attempting login for
-> ConstPtr CChar -- ^ __password__: the password we are attempting to use
-> ConstPtr CChar -- ^ __group_id__: specifies the shared SRP group
-> ConstPtr CChar -- ^ __hash_id__: specifies a secure hash function
-> ConstPtr Word8 -- ^ __salt[]__: is the salt value sent by the server
-> CSize -- ^ __salt_len__: the length of salt
-> ConstPtr Word8 -- ^ __B[]__: is the server's public value
-> CSize -- ^ __B_len__: is the server's public value length
-> BotanRNG -- ^ __rng_obj__: is a random number generator object
-> Ptr Word8 -- ^ __A[]__: out buffer to store the SRP-6 A value
-> Ptr CSize -- ^ __A_len__: SRP-6 A verifier value length
-> Ptr Word8 -- ^ __K[]__: out buffer to store the symmetric value
-> Ptr CSize -- ^ __K_len__: symmetric key length
-> IO CInt -- ^ 0 on success, negative on failure

-- | Return the size, in bytes, of the prime associated with group_id
--
-- This function can be used to determine the size of output buffers for
-- generated keys in the SRP6 algorithm. Such buffers need to be allocated
-- before calling SRP6 functions. An example of such a buffer is the
-- @verifier[]@ buffer in the 'botan_srp6_generate_verifier' function.
foreign import capi safe "botan/ffi.h botan_srp6_group_size"
botan_srp6_group_size
:: ConstPtr CChar -- ^ __group_id__
-> Ptr CSize -- ^ __group_p_bytes__
-> IO CInt
botan_srp6_group_size
:: ConstPtr CChar -- ^ __group_id__
-> Ptr CSize -- ^ __group_p_bytes__
-> IO CInt
7 changes: 7 additions & 0 deletions botan-low/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
* BREAKING: `Botan.Low.PwdHash.pbkdf2` now takes a `HashName` instead of a
`MacName`.
* PATCH: update documentation in the `Botan.Low.PwdHash` module.
* PATCH: introduce a work-around for a bug found in
`Botan.Low.SRP6.srp6ServerSessionStep1`, which would always throw an
exception. See issue
[#28](https://github.com/haskell-cryptography/botan/issues/28).
* BREAKING: add a `DLGroupName` function argument to
`Botan.Low.SRP6.srp6ServerSessionStep2`.
* PATCH: update documentation in the `Botan.Low.SRP6` module.

## 0.0.2.0 -- 2025-09-17

Expand Down
26 changes: 1 addition & 25 deletions botan-low/botan-low.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ test-suite test

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

--
Expand Down Expand Up @@ -744,31 +745,6 @@ test-suite botan-low-rng-tests
NoImplicitPrelude
OverloadedStrings

test-suite botan-low-srp6-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/SRP6Spec.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-totp-tests
import: warnings, language
type: exitcode-stdio-1.0
Expand Down
Loading