@@ -18,13 +18,13 @@ import Foundation
1818public struct SRPClient < H: HashFunction > {
1919 /// configuration. This needs to be the same as the server configuration
2020 public let configuration : SRPConfiguration < H >
21-
21+
2222 /// Initialise a SRPClient object
2323 /// - Parameter configuration: configuration to use
2424 public init ( configuration: SRPConfiguration < H > ) {
2525 self . configuration = configuration
2626 }
27-
27+
2828 /// Initiate the authentication process
2929 /// - Returns: An authentication state. The A value from this state should be sent to the server
3030 public func generateKeys( ) -> SRPKeyPair {
@@ -35,9 +35,9 @@ public struct SRPClient<H: HashFunction> {
3535 A = configuration. g. power ( a, modulus: configuration. N)
3636 } while A % configuration. N == BigNum ( 0 )
3737
38- return SRPKeyPair ( public: SRPKey ( A, padding: self . configuration. sizeN) , private: SRPKey ( a) )
38+ return SRPKeyPair ( public: SRPKey ( A, padding: configuration. sizeN) , private: SRPKey ( a) )
3939 }
40-
40+
4141 /// return shared secret given the username, password, B value and salt from the server
4242 /// - Parameters:
4343 /// - username: user identifier
@@ -48,16 +48,16 @@ public struct SRPClient<H: HashFunction> {
4848 /// - Throws: `nullServerKey`
4949 /// - Returns: shared secret
5050 public func calculateSharedSecret(
51- username: String ,
52- password: String ,
53- salt: [ UInt8 ] ,
54- clientKeys: SRPKeyPair ,
51+ username: String ,
52+ password: String ,
53+ salt: [ UInt8 ] ,
54+ clientKeys: SRPKeyPair ,
5555 serverPublicKey: SRPKey
5656 ) throws -> SRPKey {
5757 let message = [ UInt8] ( " \( username) : \( password) " . utf8)
5858 return try calculateSharedSecret ( message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey)
5959 }
60-
60+
6161 /// return shared secret given a binary password, B value and salt from the server
6262 /// - Parameters:
6363 /// - password: password
@@ -67,16 +67,19 @@ public struct SRPClient<H: HashFunction> {
6767 /// - Throws: `nullServerKey`
6868 /// - Returns: shared secret
6969 public func calculateSharedSecret(
70- password: [ UInt8 ] ,
71- salt: [ UInt8 ] ,
72- clientKeys: SRPKeyPair ,
70+ password: [ UInt8 ] ,
71+ salt: [ UInt8 ] ,
72+ clientKeys: SRPKeyPair ,
7373 serverPublicKey: SRPKey
7474 ) throws -> SRPKey {
75- let message = [ 0x3a ] + password
75+ let message = [ 0x3A ] + password
7676 return try calculateSharedSecret ( message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey)
7777 }
78-
79- /// calculate proof of shared secret to send to server
78+
79+ /// Calculate proof of shared secret to send to server.
80+ ///
81+ /// This uses the method detailed in https://tools.ietf.org/html/rfc2945#section-3
82+ ///
8083 /// - Parameters:
8184 /// - username: Username
8285 /// - salt: The salt value associated with the user returned by the server
@@ -85,74 +88,76 @@ public struct SRPClient<H: HashFunction> {
8588 /// - sharedSecret: shared secret
8689 /// - Returns: The client verification code which should be passed to the server
8790 public func calculateClientProof(
88- username: String ,
89- salt: [ UInt8 ] ,
90- clientPublicKey: SRPKey ,
91- serverPublicKey: SRPKey ,
91+ username: String ,
92+ salt: [ UInt8 ] ,
93+ clientPublicKey: SRPKey ,
94+ serverPublicKey: SRPKey ,
9295 sharedSecret: SRPKey
9396 ) -> [ UInt8 ] {
94- let clientPublicKey = clientPublicKey. with ( padding: self . configuration. sizeN)
95- let serverPublicKey = serverPublicKey. with ( padding: self . configuration. sizeN)
96- let sharedSecret = sharedSecret. with ( padding: self . configuration. sizeN)
97+ let clientPublicKey = clientPublicKey. with ( padding: configuration. sizeN)
98+ let serverPublicKey = serverPublicKey. with ( padding: configuration. sizeN)
99+ let sharedSecret = sharedSecret. with ( padding: configuration. sizeN)
97100 let hashSharedSecret = [ UInt8] ( H . hash ( data: sharedSecret. bytes) )
98101 // get verification code
99102 return SRP< H> . calculateClientProof(
100- configuration: configuration,
101- username: username,
102- salt: salt,
103- clientPublicKey: clientPublicKey,
104- serverPublicKey: serverPublicKey,
103+ configuration: configuration,
104+ username: username,
105+ salt: salt,
106+ clientPublicKey: clientPublicKey,
107+ serverPublicKey: serverPublicKey,
105108 hashSharedSecret: hashSharedSecret
106109 )
107110 }
108-
109- /// If the server returns that the client verification code was valid it will also return a server
110- /// verification code that the client can use to verify the server is correct. This is the calculation
111+
112+ /// If the server returns that the client verification code was valid it will also return a server
113+ /// verification code that the client can use to verify the server is correct. This is the calculation
111114 /// to verify it is correct
112115 ///
113116 /// - Parameters:
114117 /// - clientPublicKey: Client public key
115118 /// - clientProof: Client proof
116119 /// - sharedSecret: Shared secret
117120 public func calculateServerProof(
118- clientPublicKey: SRPKey ,
119- clientProof: [ UInt8 ] ,
121+ clientPublicKey: SRPKey ,
122+ clientProof: [ UInt8 ] ,
120123 sharedSecret: SRPKey
121124 ) -> [ UInt8 ] {
122- let clientPublicKey = clientPublicKey. with ( padding: self . configuration. sizeN)
123- let sharedSecret = sharedSecret. with ( padding: self . configuration. sizeN)
125+ let clientPublicKey = clientPublicKey. with ( padding: configuration. sizeN)
126+ let sharedSecret = sharedSecret. with ( padding: configuration. sizeN)
124127 let hashSharedSecret = [ UInt8] ( H . hash ( data: sharedSecret. bytes) )
125128 // get out version of server proof
126129 return SRP< H> . calculateServerVerification(
127- clientPublicKey: clientPublicKey,
128- clientProof: clientProof,
130+ clientPublicKey: clientPublicKey,
131+ clientProof: clientProof,
129132 hashSharedSecret: hashSharedSecret
130133 )
131134 }
132-
133- /// If the server returns that the client verification code was valid it will also return a server
135+
136+ /// If the server returns that the client verification code was valid it will also return a server
134137 /// verification code that the client can use to verify the server is correct
135138 ///
139+ /// This uses the method detailed in https://tools.ietf.org/html/rfc2945#section-3
140+ ///
136141 /// - Parameters:
137142 /// - serverProof: Server proof
138143 /// - clientProof: Client proof
139144 /// - clientPublicKey: Client public key
140145 /// - sharedSecret: Shared secret
141146 /// - Throws: `requiresVerificationKey`, `invalidServerCode`
142147 public func verifyServerProof(
143- serverProof: [ UInt8 ] ,
144- clientProof: [ UInt8 ] ,
145- clientPublicKey: SRPKey ,
148+ serverProof: [ UInt8 ] ,
149+ clientProof: [ UInt8 ] ,
150+ clientPublicKey: SRPKey ,
146151 sharedSecret: SRPKey
147152 ) throws {
148153 // get our version of server proof
149154 let HAMK = calculateServerProof ( clientPublicKey: clientPublicKey, clientProof: clientProof, sharedSecret: sharedSecret)
150155 // is it the same
151156 guard serverProof == HAMK else { throw SRPClientError . invalidServerCode }
152157 }
153-
154- /// Generate salt and password verifier from username and password. When creating your user instead of
155- /// passing your password to the server, you pass the salt and password verifier values. In this way the
158+
159+ /// Generate salt and password verifier from username and password. When creating your user instead of
160+ /// passing your password to the server, you pass the salt and password verifier values. In this way the
156161 /// server never knows your password so can never leak it.
157162 ///
158163 /// - Parameters:
@@ -168,17 +173,17 @@ public struct SRPClient<H: HashFunction> {
168173 /// Hash data using same hash function that SRP uses
169174 /// - Parameter data: Data to be hashed
170175 /// - Returns: Hashed data
171- @inlinable public func hash< D> ( data: D ) -> H . Digest where D : DataProtocol {
176+ @inlinable public func hash< D> ( data: D ) -> H . Digest where D: DataProtocol {
172177 H . hash ( data: data)
173178 }
174179}
175180
176- extension SRPClient {
181+ public extension SRPClient {
177182 /// return shared secret given the message (username:password), salt from server, client keys, and B value
178- func calculateSharedSecret(
179- message: [ UInt8 ] ,
180- salt: [ UInt8 ] ,
181- clientKeys: SRPKeyPair ,
183+ internal func calculateSharedSecret(
184+ message: [ UInt8 ] ,
185+ salt: [ UInt8 ] ,
186+ clientKeys: SRPKeyPair ,
182187 serverPublicKey: SRPKey
183188 ) throws -> SRPKey {
184189 guard serverPublicKey. number % configuration. N != BigNum ( 0 ) else { throw SRPClientError . nullServerKey }
@@ -187,23 +192,23 @@ extension SRPClient {
187192 let u = SRP< H> . calculateU( clientPublicKey: clientKeys. public. bytes, serverPublicKey: serverPublicKey. bytes)
188193
189194 guard u != 0 else { throw SRPClientError . nullServerKey }
190-
195+
191196 let x = BigNum ( bytes: [ UInt8] ( H . hash ( data: salt + H. hash ( data: message) ) ) )
192-
197+
193198 // calculate S = (B - k*g^x)^(a+u*x)
194199 let S = ( serverPublicKey. number - configuration. k * configuration. g. power ( x, modulus: configuration. N) ) . power ( clientKeys. private. number + u * x, modulus: configuration. N)
195-
196- return . init( S, padding: self . configuration. sizeN)
200+
201+ return . init( S, padding: configuration. sizeN)
197202 }
198-
203+
199204 /// generate password verifier
200- public func generatePasswordVerifier( username: String , password: String , salt: [ UInt8 ] ) -> BigNum {
205+ func generatePasswordVerifier( username: String , password: String , salt: [ UInt8 ] ) -> BigNum {
201206 let message = " \( username) : \( password) "
202207 return generatePasswordVerifier ( message: [ UInt8] ( message. utf8) , salt: salt)
203208 }
204-
209+
205210 /// generate password verifier
206- public func generatePasswordVerifier( message: [ UInt8 ] , salt: [ UInt8 ] ) -> BigNum {
211+ func generatePasswordVerifier( message: [ UInt8 ] , salt: [ UInt8 ] ) -> BigNum {
207212 let x = BigNum ( bytes: [ UInt8] ( H . hash ( data: salt + H. hash ( data: message) ) ) )
208213 let verifier = configuration. g. power ( x, modulus: configuration. N)
209214 return verifier
0 commit comments