Copyright | (c) Leo D 2023 |
---|---|
License | BSD-3-Clause |
Maintainer | leo@apotheca.io |
Stability | experimental |
Portability | POSIX |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
The library contains an implementation of the SRP6-a password authenticated key exchange protocol.
Synopsis
- newtype SRP6ServerSession = MkSRP6ServerSession {
- getSRP6ServerSessionForeignPtr :: ForeignPtr BotanSRP6ServerSessionStruct
- withSRP6ServerSession :: SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a
- srp6ServerSessionInit :: IO SRP6ServerSession
- srp6ServerSessionDestroy :: SRP6ServerSession -> IO ()
- srp6ServerSessionStep1 :: SRP6ServerSession -> SRP6Verifier -> DLGroupName -> HashName -> RNG -> IO SRP6BValue
- srp6ServerSessionStep2 :: SRP6ServerSession -> SRP6AValue -> IO SRP6SharedSecret
- srp6GenerateVerifier :: Identifier -> Password -> Salt -> DLGroupName -> HashName -> IO SRP6Verifier
- srp6ClientAgree :: Identifier -> Password -> DLGroupName -> HashName -> Salt -> SRP6BValue -> RNG -> IO (SRP6AValue, SRP6SharedSecret)
- srp6GroupSize :: DLGroupName -> IO Int
- type SRP6Verifier = ByteString
- type SRP6BValue = ByteString
- type SRP6AValue = ByteString
- type SRP6SharedSecret = ByteString
- pattern MODP_SRP_1024 :: DLGroupName
- pattern MODP_SRP_1536 :: DLGroupName
- pattern MODP_SRP_2048 :: DLGroupName
- pattern MODP_SRP_3072 :: DLGroupName
- pattern MODP_SRP_4096 :: DLGroupName
- pattern MODP_SRP_6144 :: DLGroupName
- pattern MODP_SRP_8192 :: DLGroupName
Secure Random Password 6a
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 SSLTLS: https:www.rfc-editor.orgrfc/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.
newtype SRP6ServerSession Source #
MkSRP6ServerSession | |
|
withSRP6ServerSession :: SRP6ServerSession -> (BotanSRP6ServerSession -> IO a) -> IO a Source #
srp6ServerSessionInit Source #
:: IO SRP6ServerSession | srp6: SRP-6 server session object |
Initialize an SRP-6 server session object
srp6ServerSessionDestroy :: SRP6ServerSession -> IO () Source #
Destroy a SRP6 server session object immediately
srp6ServerSessionStep1 Source #
:: 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 |
SRP-6 Server side step 1: Generate a server B-value
srp6ServerSessionStep2 Source #
:: SRP6ServerSession | srp6: SRP-6 server session object |
-> SRP6AValue | A[]: the client's value |
-> IO SRP6SharedSecret | key[]: out buffer to store the symmetric key value |
SRP-6 Server side step 2: Generate the server shared key
:: 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 |
SRP-6 Client side step 1: Generate a new SRP-6 verifier
:: 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) |
SRP6a Client side step 2: Generate a client A-value and the client shared key
:: DLGroupName | group_id |
-> IO Int | group_p_bytes |
Return the size, in bytes, of the prime associated with group_id
SRP6 Types
type SRP6Verifier = ByteString Source #
type SRP6BValue = ByteString Source #
type SRP6AValue = ByteString Source #
type SRP6SharedSecret = ByteString Source #
SRP discrete logarithm groups
pattern MODP_SRP_1024 :: DLGroupName Source #
pattern MODP_SRP_1536 :: DLGroupName Source #
pattern MODP_SRP_2048 :: DLGroupName Source #
pattern MODP_SRP_3072 :: DLGroupName Source #
pattern MODP_SRP_4096 :: DLGroupName Source #
pattern MODP_SRP_6144 :: DLGroupName Source #
pattern MODP_SRP_8192 :: DLGroupName Source #