@@ -52,38 +52,84 @@ import Botan.Low.PubKey
5252import Botan.Low.Remake
5353import Botan.Low.RNG
5454
55- {- $introduction
56-
57- A SRP client provides what is called a SRP verifier to the server.
58- This verifier is based on a password, but the password cannot be
59- easily derived from the verifier (however brute force attacks are
60- possible). Later, the client and server can perform an SRP exchange,
61- which results in a shared secret key. This key can be used for
62- mutual authentication and/or encryption.
63-
64- SRP works in a discrete logarithm group. Special parameter sets for
65- SRP6 are defined, denoted in the library as @modp\/srp\/<size>@, for
66- example @modp\/srp\/2048@.
67-
68- Warning
69-
70- While knowledge of the verifier does not easily allow an attacker to
71- get the raw password, they could still use the verifier to impersonate
72- the server to the client, so verifiers should be protected as carefully
73- as a plaintext password would be.
74-
75- SRP6 may be used as part of SSL/TLS: https://www.rfc-editor.org/rfc/rfc5054
76-
77- -}
78-
7955{- $usage
8056
81- On signup, the client generates a salt and verifier, and securely sends them to a server:
57+ On signup, the client generates a salt and verifier, and securely sends them to
58+ a server:
59+
60+ >>> :{
61+ {- # OPTIONS_GHC -threaded -Wall #-}
62+ import Botan.Low.Hash
63+ import Botan.Low.MAC
64+ import Botan.Low.PubKey
65+ import Botan.Low.RNG
66+ import Botan.Low.SRP6
67+ import Control.Concurrent
68+ import Control.Concurrent.Async
69+ import Control.Concurrent.MVar
70+ import Control.Exception
71+ import Control.Monad
72+ import Data.ByteString hiding (group)
73+ import Text.Printf
74+ :}
75+
76+ >>> :{
77+ type Identifier = ByteString
78+ data Msg =
79+ SendVerifier SRP6Verifier DLGroupName HashName
80+ | SendServerKey SRP6BValue
81+ | SendClientKey SRP6AValue
82+ | SendSharedSecret SRP6SharedSecret
83+ :}
84+
85+ >>> :{
86+ client :: MVar Msg -> IO ()
87+ client msgVar = do
88+ rng <- rngInit UserRNG
89+ let group = MODP_SRP_4096
90+ hash = SHA512
91+ identifier = "alice"
92+ password = "Fee fi fo fum!"
93+ salt <- rngGet rng 12
94+ verifier <- srp6GenerateVerifier identifier password salt group hash
95+ putMVar msgVar $ SendVerifier verifier group hash
96+ SendServerKey serverKey <- takeMVar msgVar
97+ (clientKey, clientSessionKey) <- srp6ClientAgree identifier password group hash salt serverKey rng
98+ putMVar msgVar $ SendClientKey clientKey
99+ SendSharedSecret serverSessionKey <- takeMVar msgVar
100+ let match = clientSessionKey == serverSessionKey
101+ if match then
102+ print @String "client secret == server secret"
103+ else
104+ error $
105+ printf "%s /= %s"
106+ (show clientSessionKey)
107+ (show serverSessionKey)
108+ :}
109+
110+ >>> :{
111+ server :: MVar Msg -> IO ()
112+ server msgVar = do
113+ rng <- rngInit UserRNG
114+ session <- srp6ServerSessionInit
115+ SendVerifier verifier group hash <- takeMVar msgVar
116+ serverKey <- srp6ServerSessionStep1 session verifier group hash rng
117+ putMVar msgVar $ SendServerKey serverKey
118+ SendClientKey clientKey <- takeMVar msgVar
119+ serverSessionKey <- srp6ServerSessionStep2 session clientKey
120+ putMVar msgVar $ SendSharedSecret serverSessionKey
121+ :}
122+
123+ >>> :{
124+ main :: IO ()
125+ main = do
126+ msgVar <- newEmptyMVar
127+ void $ concurrently (client msgVar) (server msgVar)
128+ :}
129+
130+ >>> main
131+ "client secret == server secret"
82132
83- > import Botan.Low.SRP6
84- > import Botan.Low.Hash
85- > import Botan.Low.RNG
86- > import Botan.Low.MAC
87133> rng <- rngInit UserRNG
88134> group = MODP_SRP_4096
89135> hash = SHA512
0 commit comments