{-|
Module      : Botan.Low.SRP6
Description : Secure remote password
Copyright   : (c) Leo D, 2023
License     : BSD-3-Clause
Maintainer  : leo@apotheca.io
Stability   : experimental
Portability : POSIX

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

-}

module Botan.Low.SRP6
(

-- * Secure Random Password 6a
-- $introduction

-- * Usage
-- $usage

  SRP6ServerSession(..)
, withSRP6ServerSession
, srp6ServerSessionInit
, srp6ServerSessionDestroy
, srp6ServerSessionStep1
, srp6ServerSessionStep2
, srp6GenerateVerifier
, srp6ClientAgree
, srp6GroupSize

-- * SRP6 Types

, SRP6Verifier(..)
, SRP6BValue(..)
, SRP6AValue(..)
, SRP6SharedSecret(..)

-- * SRP discrete logarithm groups

, pattern MODP_SRP_1024
, pattern MODP_SRP_1536
, pattern MODP_SRP_2048
, pattern MODP_SRP_3072
, pattern MODP_SRP_4096
, pattern MODP_SRP_6144
, pattern MODP_SRP_8192

) where

import qualified Data.ByteString as ByteString

import Botan.Bindings.SRP6

import Botan.Low.Error
import Botan.Low.Hash
import Botan.Low.Make
import Botan.Low.Prelude
import Botan.Low.Remake
import Botan.Low.RNG
import Botan.Low.PubKey

{- $introduction

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.

SRP6 may be used as part of SSL/TLS: https://www.rfc-editor.org/rfc/rfc5054

-}

{- $usage

On signup, the client generates a salt and verifier, and securely sends them to a server:

> import Botan.Low.SRP6
> import Botan.Low.Hash
> import Botan.Low.RNG
> import Botan.Low.MAC
> rng <- rngInit UserRNG
> group = MODP_SRP_4096
> hash = SHA512
> identifier = "alice"
> password = "Fee fi fo fum!"
> salt <- rngGet rng 12
> verifier <- srp6GenerateVerifier identifier password salt group hash
> -- signUpUserWithServer identifier verifier salt group hash

Later, on the server when the client request authentication, the server
looks up the verfier, generates a server key (a SRP6 'B' value), and sends
it back to the client:

> -- rng <- rngInit UserRNG
> session <- srp6ServerSessionInit 
> -- (verifier, salt, group, hash) <- lookupUser identifier
> serverKey <- srp6ServerSessionStep1 session verifier group hash rng

Once the client receives the server key, it generates a client key (SRP6 'A' value)
and the session key, and sends the client key to the server:

> -- serverKey <- didReceiveServerKey
> (clientKey, clientSessionKey) <- srp6ClientAgree identifier password group hash salt serverKey rng
> -- sendClientKey clientKey

The server then receives client key, and generates a matching session key:

> -- clientKey <- didReceiveClientKey
> serverSessionKey <- srp6ServerSessionStep2 session clientKey

At this point, clientSessionKey and serverSessionKey should be equal,
but this should be confirmed by exchanging a hash digest to check for integrity,
using the exchange's session key, identifier, salt, and client and server keys.

There are many ways to do this, but preferrably, an (h)mac digest should be used
to also include authentication and avoid impersonation.

> NOTE: Both sides could calculate 'identifier <> salt <> serverKey <> clientKey'
> individually but then we need to prove that each side has calculated it without
relying on the copy received for validation, so we do this song and dance:

The client should first calculate and send the HMAC auth, using identifier + salt + clientKey:

> mac <- macInit (hmac SHA3)
> macSetKey mac clientSessionKey
> macUpdate mac $ identifier <> salt <> clientKey
> clientAuth <- macFinal mac
> -- sendClientAuth clientAuth

The server should then verify the client auth, and send its own HMAC
auth back to the client using serverKey + clientAuth:

> -- clientAuth <- didReceiveClientAuth
> mac <- macInit (hmac SHA3)
> macSetKey mac serverSessionKey
> macUpdate mac $ identifier <> salt <> clientKey
> verifiedClientAuth <- macFinal mac
> -- clientAuth == verifiedClientAuth
> macClear mac
> macSetKey mac serverSessionKey
> macUpdate mac $ serverKey <> clientAuth
> serverAuth <- macFinal mac
> -- sendServerAuth serverAuth

The client then receives the server HMAC auth, and validates it

> -- serverAuth <- didReceiveServerAuth
> macClear mac
> macSetKey mac clientSessionKey
> macUpdate mac $ serverKey <> clientAuth
> verifiedServerAuth <- macFinal mac
> -- serverAuth == verifiedServerAuth

After this, the shared session key may be safely used.

-}


-- TODO: Unify with other / move to botan
type Identifier = ByteString
type Password = ByteString
type Salt = ByteString

type SRP6Verifier = ByteString
type SRP6BValue = ByteString
type SRP6AValue = ByteString
type SRP6SharedSecret = ByteString

newtype SRP6ServerSession = MkSRP6ServerSession { SRP6ServerSession -> ForeignPtr BotanSRP6ServerSessionStruct
getSRP6ServerSessionForeignPtr :: ForeignPtr BotanSRP6ServerSessionStruct }

newSRP6ServerSession      :: BotanSRP6ServerSession -> IO SRP6ServerSession
withSRP6ServerSession     :: SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a
-- | Destroy a SRP6 server session object immediately
srp6ServerSessionDestroy  :: SRP6ServerSession -> IO ()
createSRP6ServerSession   :: (Ptr BotanSRP6ServerSession -> IO CInt) -> IO SRP6ServerSession
(BotanSRP6ServerSession -> IO SRP6ServerSession
newSRP6ServerSession, SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a
withSRP6ServerSession, SRP6ServerSession -> IO ()
srp6ServerSessionDestroy, (Ptr BotanSRP6ServerSession -> IO CInt) -> IO SRP6ServerSession
createSRP6ServerSession, (Ptr BotanSRP6ServerSession -> Ptr CSize -> IO CInt)
-> IO [SRP6ServerSession]
_)
    = (Ptr BotanSRP6ServerSessionStruct -> BotanSRP6ServerSession)
-> (BotanSRP6ServerSession -> Ptr BotanSRP6ServerSessionStruct)
-> (ForeignPtr BotanSRP6ServerSessionStruct -> SRP6ServerSession)
-> (SRP6ServerSession -> ForeignPtr BotanSRP6ServerSessionStruct)
-> FinalizerPtr BotanSRP6ServerSessionStruct
-> (BotanSRP6ServerSession -> IO SRP6ServerSession,
    SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a,
    SRP6ServerSession -> IO (),
    (Ptr BotanSRP6ServerSession -> IO CInt) -> IO SRP6ServerSession,
    (Ptr BotanSRP6ServerSession -> Ptr CSize -> IO CInt)
    -> IO [SRP6ServerSession])
forall botan struct object a.
Storable botan =>
(Ptr struct -> botan)
-> (botan -> Ptr struct)
-> (ForeignPtr struct -> object)
-> (object -> ForeignPtr struct)
-> FinalizerPtr struct
-> (botan -> IO object, object -> (botan -> IO a) -> IO a,
    object -> IO (), (Ptr botan -> IO CInt) -> IO object,
    (Ptr botan -> Ptr CSize -> IO CInt) -> IO [object])
mkBindings
        Ptr BotanSRP6ServerSessionStruct -> BotanSRP6ServerSession
MkBotanSRP6ServerSession BotanSRP6ServerSession -> Ptr BotanSRP6ServerSessionStruct
runBotanSRP6ServerSession
        ForeignPtr BotanSRP6ServerSessionStruct -> SRP6ServerSession
MkSRP6ServerSession SRP6ServerSession -> ForeignPtr BotanSRP6ServerSessionStruct
getSRP6ServerSessionForeignPtr
        FinalizerPtr BotanSRP6ServerSessionStruct
botan_srp6_server_session_destroy

-- | Initialize an SRP-6 server session object
srp6ServerSessionInit
    :: IO SRP6ServerSession -- ^ __srp6__: SRP-6 server session object
srp6ServerSessionInit :: IO SRP6ServerSession
srp6ServerSessionInit = (Ptr BotanSRP6ServerSession -> IO CInt) -> IO SRP6ServerSession
createSRP6ServerSession Ptr BotanSRP6ServerSession -> IO CInt
botan_srp6_server_session_init

-- WARNING: withFooInit-style limited lifetime functions moved to high-level botan
withSRP6ServerSessionInit :: (SRP6ServerSession -> IO a) -> IO a
withSRP6ServerSessionInit :: forall a. (SRP6ServerSession -> IO a) -> IO a
withSRP6ServerSessionInit = IO SRP6ServerSession
-> (SRP6ServerSession -> IO ())
-> (SRP6ServerSession -> IO a)
-> IO a
forall t a. IO t -> (t -> IO ()) -> (t -> IO a) -> IO a
mkWithTemp IO SRP6ServerSession
srp6ServerSessionInit SRP6ServerSession -> IO ()
srp6ServerSessionDestroy

-- | SRP-6 Server side step 1: Generate a server B-value
srp6ServerSessionStep1
    :: SRP6ServerSession    -- ^ __srp6__: SRP-6 server session object
    -> SRP6Verifier         -- ^ __verifier[]__: the verification value saved from client registration
    -> DLGroupName          -- ^ __group_id__: the SRP group id
    -> HashName             -- ^ __hash_id__: the SRP hash in use
    -> RNG                  -- ^ __rng_obj__: a random number generator object
    -> IO SRP6BValue        -- ^ __B_pub[]__: out buffer to store the SRP-6 B value
srp6ServerSessionStep1 :: SRP6ServerSession
-> SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> RNG
-> IO SRP6Verifier
srp6ServerSessionStep1 SRP6ServerSession
srp6 SRP6Verifier
verifier SRP6Verifier
groupId SRP6Verifier
hashId RNG
rng = SRP6ServerSession
-> (BotanSRP6ServerSession -> IO SRP6Verifier) -> IO SRP6Verifier
forall a.
SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a
withSRP6ServerSession SRP6ServerSession
srp6 ((BotanSRP6ServerSession -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (BotanSRP6ServerSession -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ BotanSRP6ServerSession
srp6Ptr -> do
    SRP6Verifier
-> (Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier
forall byte a. SRP6Verifier -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen SRP6Verifier
verifier ((Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
verifierPtr CSize
verifierLen -> do
        SRP6Verifier -> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
groupId ((Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
groupIdPtr -> do
            SRP6Verifier -> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
hashId ((Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
hashIdPtr -> do
                RNG -> (BotanRNG -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. RNG -> (BotanRNG -> IO a) -> IO a
withRNG RNG
rng ((BotanRNG -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (BotanRNG -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ BotanRNG
botanRNG -> do
                    (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
forall byte. (Ptr byte -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
allocBytesQuerying ((Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier)
-> (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
outPtr Ptr CSize
outLen -> BotanSRP6ServerSession
-> ConstPtr Word8
-> CSize
-> ConstPtr CChar
-> ConstPtr CChar
-> BotanRNG
-> Ptr Word8
-> Ptr CSize
-> IO CInt
botan_srp6_server_session_step1
                        BotanSRP6ServerSession
srp6Ptr
                        (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
verifierPtr)
                        CSize
verifierLen
                        (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
groupIdPtr)
                        (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
hashIdPtr)
                        BotanRNG
botanRNG
                        Ptr Word8
outPtr
                        Ptr CSize
outLen

-- | SRP-6 Server side step 2:  Generate the server shared key
srp6ServerSessionStep2
    :: SRP6ServerSession    -- ^ __srp6__: SRP-6 server session object
    -> SRP6AValue           -- ^ __A[]__: the client's value
    -> IO SRP6SharedSecret  -- ^ __key[]__: out buffer to store the symmetric key value
srp6ServerSessionStep2 :: SRP6ServerSession -> SRP6Verifier -> IO SRP6Verifier
srp6ServerSessionStep2 SRP6ServerSession
srp6 SRP6Verifier
a = SRP6ServerSession
-> (BotanSRP6ServerSession -> IO SRP6Verifier) -> IO SRP6Verifier
forall a.
SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a
withSRP6ServerSession SRP6ServerSession
srp6 ((BotanSRP6ServerSession -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (BotanSRP6ServerSession -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ BotanSRP6ServerSession
srp6Ptr -> do
    SRP6Verifier
-> (Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier
forall byte a. SRP6Verifier -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen SRP6Verifier
a ((Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
aPtr CSize
aLen -> do
        (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
forall byte. (Ptr byte -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
allocBytesQuerying ((Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier)
-> (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
outPtr Ptr CSize
outLen -> BotanSRP6ServerSession
-> ConstPtr Word8 -> CSize -> Ptr Word8 -> Ptr CSize -> IO CInt
botan_srp6_server_session_step2
            BotanSRP6ServerSession
srp6Ptr
            (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
aPtr)
            CSize
aLen
            Ptr Word8
outPtr
            Ptr CSize
outLen

-- | SRP-6 Client side step 1:  Generate a new SRP-6 verifier  
srp6GenerateVerifier
    :: Identifier       -- ^ __identifier__: a username or other client identifier
    -> Password         -- ^ __password__: the secret used to authenticate user
    -> Salt             -- ^ __salt[]__: a randomly chosen value, at least 128 bits long
    -> DLGroupName      -- ^ __group_id__: specifies the shared SRP group
    -> HashName         -- ^ __hash_id__: specifies a secure hash function
    -> IO SRP6Verifier  -- ^ __verifier[]__: out buffer to store the SRP-6 verifier value
srp6GenerateVerifier :: SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> IO SRP6Verifier
srp6GenerateVerifier SRP6Verifier
identifier SRP6Verifier
password SRP6Verifier
salt SRP6Verifier
groupId SRP6Verifier
hashId = SRP6Verifier -> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
identifier ((Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
identifierPtr -> do
    SRP6Verifier -> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
password ((Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
passwordPtr -> do
        SRP6Verifier
-> (Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier
forall byte a. SRP6Verifier -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen SRP6Verifier
salt ((Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr Word8 -> CSize -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
saltPtr CSize
saltLen -> do
            SRP6Verifier -> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
groupId ((Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
groupIdPtr -> do
                SRP6Verifier -> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
hashId ((Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier)
-> (Ptr CChar -> IO SRP6Verifier) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
hashIdPtr -> do
                    (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
forall byte. (Ptr byte -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
allocBytesQuerying ((Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier)
-> (Ptr Word8 -> Ptr CSize -> IO CInt) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
outPtr Ptr CSize
outLen -> ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr Word8
-> CSize
-> ConstPtr CChar
-> ConstPtr CChar
-> Ptr Word8
-> Ptr CSize
-> IO CInt
botan_srp6_generate_verifier
                        (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
identifierPtr)
                        (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
passwordPtr)
                        (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
saltPtr)
                        CSize
saltLen
                        (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
groupIdPtr)
                        (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
hashIdPtr)
                        Ptr Word8
outPtr
                        Ptr CSize
outLen

-- NOTE: ORDER IS DIFFERENT FROM SERVER GENERATE VERIFIER
-- | SRP6a Client side step 2:  Generate a client A-value and the client shared key
srp6ClientAgree
    :: Identifier   -- ^ __username__: the username we are attempting login for
    -> Password     -- ^ __password__: the password we are attempting to use
    -> DLGroupName  -- ^ __group_id__: specifies the shared SRP group
    -> HashName     -- ^ __hash_id__: specifies a secure hash function
    -> Salt         -- ^ __salt[]__: is the salt value sent by the server
    -> SRP6BValue   -- ^ __uint8_t__: B[] is the server's public value
    -> RNG          -- ^ __rng_obj__: is a random number generator object
    -> IO (SRP6AValue, SRP6SharedSecret)    -- @(A,K)@
srp6ClientAgree :: SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> SRP6Verifier
-> RNG
-> IO (SRP6Verifier, SRP6Verifier)
srp6ClientAgree SRP6Verifier
identifier SRP6Verifier
password SRP6Verifier
groupId SRP6Verifier
hashId SRP6Verifier
salt SRP6Verifier
b RNG
rng = do
    SRP6Verifier
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
identifier ((Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
identifierPtr -> do
        SRP6Verifier
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
password ((Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
passwordPtr -> do
            SRP6Verifier
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
groupId ((Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
groupIdPtr -> do
                SRP6Verifier
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
hashId ((Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr CChar -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
hashIdPtr -> do
                    SRP6Verifier
-> (Ptr Word8 -> CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall byte a. SRP6Verifier -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen SRP6Verifier
salt ((Ptr Word8 -> CSize -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr Word8 -> CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
saltPtr CSize
saltLen -> do
                        SRP6Verifier
-> (Ptr Word8 -> CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall byte a. SRP6Verifier -> (Ptr byte -> CSize -> IO a) -> IO a
asBytesLen SRP6Verifier
b ((Ptr Word8 -> CSize -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr Word8 -> CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
bPtr CSize
bLen -> do
                            RNG
-> (BotanRNG -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a. RNG -> (BotanRNG -> IO a) -> IO a
withRNG RNG
rng ((BotanRNG -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (BotanRNG -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ BotanRNG
botanRNG -> do
                                (Ptr CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
aSzPtr -> do 
                                    (Ptr CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (SRP6Verifier, SRP6Verifier))
 -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr CSize -> IO (SRP6Verifier, SRP6Verifier))
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
kSzPtr -> do
                                        -- Query sizes
                                        -- TODO: Actually ensure expected error (insufficient buffer space)
                                        --  and propagate unexpected errors
                                        CInt
_ <- ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr Word8
-> CSize
-> ConstPtr Word8
-> CSize
-> BotanRNG
-> Ptr Word8
-> Ptr CSize
-> Ptr Word8
-> Ptr CSize
-> IO CInt
botan_srp6_client_agree
                                            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
identifierPtr)
                                            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
passwordPtr)
                                            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
groupIdPtr)
                                            (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
hashIdPtr)
                                            (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
saltPtr)
                                            CSize
saltLen
                                            (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
bPtr)
                                            CSize
bLen
                                            BotanRNG
botanRNG
                                            Ptr Word8
forall a. Ptr a
nullPtr
                                            Ptr CSize
aSzPtr
                                            Ptr Word8
forall a. Ptr a
nullPtr
                                            Ptr CSize
kSzPtr
                                        Int
kSz <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
kSzPtr
                                        Int
aSz <- CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
aSzPtr
                                        Int
-> (Ptr Word8 -> IO SRP6Verifier)
-> IO (SRP6Verifier, SRP6Verifier)
forall byte a. Int -> (Ptr byte -> IO a) -> IO (a, SRP6Verifier)
allocBytesWith Int
kSz ((Ptr Word8 -> IO SRP6Verifier) -> IO (SRP6Verifier, SRP6Verifier))
-> (Ptr Word8 -> IO SRP6Verifier)
-> IO (SRP6Verifier, SRP6Verifier)
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
kPtr -> do
                                            Int -> (Ptr Word8 -> IO ()) -> IO SRP6Verifier
forall byte. Int -> (Ptr byte -> IO ()) -> IO SRP6Verifier
allocBytes Int
aSz ((Ptr Word8 -> IO ()) -> IO SRP6Verifier)
-> (Ptr Word8 -> IO ()) -> IO SRP6Verifier
forall a b. (a -> b) -> a -> b
$ \ Ptr Word8
aPtr -> do
                                                HasCallStack => IO CInt -> IO ()
IO CInt -> IO ()
throwBotanIfNegative_ (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr CChar
-> ConstPtr Word8
-> CSize
-> ConstPtr Word8
-> CSize
-> BotanRNG
-> Ptr Word8
-> Ptr CSize
-> Ptr Word8
-> Ptr CSize
-> IO CInt
botan_srp6_client_agree
                                                    (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
identifierPtr)
                                                    (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
passwordPtr)
                                                    (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
groupIdPtr)
                                                    (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
hashIdPtr)
                                                    (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
saltPtr)
                                                    CSize
saltLen
                                                    (Ptr Word8 -> ConstPtr Word8
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr Word8
bPtr)
                                                    CSize
bLen
                                                    BotanRNG
botanRNG
                                                    Ptr Word8
aPtr
                                                    Ptr CSize
aSzPtr
                                                    Ptr Word8
kPtr
                                                    Ptr CSize
kSzPtr

-- NOTE: Missing FFI function: srp6_group_identifierz

-- | Return the size, in bytes, of the prime associated with group_id
srp6GroupSize
    :: DLGroupName  -- ^ __group_id__
    -> IO Int       -- ^ __group_p_bytes__
srp6GroupSize :: SRP6Verifier -> IO Int
srp6GroupSize SRP6Verifier
groupId = SRP6Verifier -> (Ptr CChar -> IO Int) -> IO Int
forall a. SRP6Verifier -> (Ptr CChar -> IO a) -> IO a
asCString SRP6Verifier
groupId ((Ptr CChar -> IO Int) -> IO Int)
-> (Ptr CChar -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \ Ptr CChar
groupIdPtr -> do
    (Ptr CSize -> IO Int) -> IO Int
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO Int) -> IO Int)
-> (Ptr CSize -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \ Ptr CSize
szPtr -> do
        HasCallStack => IO CInt -> IO ()
IO CInt -> IO ()
throwBotanIfNegative_ (IO CInt -> IO ()) -> IO CInt -> IO ()
forall a b. (a -> b) -> a -> b
$ ConstPtr CChar -> Ptr CSize -> IO CInt
botan_srp6_group_size (Ptr CChar -> ConstPtr CChar
forall a. Ptr a -> ConstPtr a
ConstPtr Ptr CChar
groupIdPtr) Ptr CSize
szPtr
        CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> Int) -> IO CSize -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
szPtr