11import BigNum
22import Crypto
3+ import Foundation
34
45/// Manages the client side of Secure Remote Password
56///
@@ -27,14 +28,14 @@ public struct SRPClient<H: HashFunction> {
2728 /// Initiate the authentication process
2829 /// - Returns: An authentication state. The A value from this state should be sent to the server
2930 public func generateKeys( ) -> SRPKeyPair {
30- var a = BigNum ( )
31- var A = BigNum ( )
31+ var a : BigNum
32+ var A : BigNum
3233 repeat {
3334 a = BigNum ( bytes: SymmetricKey ( size: . bits256) )
3435 A = configuration. g. power ( a, modulus: configuration. N)
3536 } while A % configuration. N == BigNum ( 0 )
3637
37- return SRPKeyPair ( public: SRPKey ( A) , private: SRPKey ( a) )
38+ return SRPKeyPair ( public: SRPKey ( A, padding : self . configuration . sizeN ) , private: SRPKey ( a) )
3839 }
3940
4041 /// return shared secret given the username, password, B value and salt from the server
@@ -46,51 +47,63 @@ public struct SRPClient<H: HashFunction> {
4647 /// - serverPublicKey: server public key
4748 /// - Throws: `nullServerKey`
4849 /// - Returns: shared secret
49- public func calculateSharedSecret( username: String , password: String , salt: [ UInt8 ] , clientKeys: SRPKeyPair , serverPublicKey: SRPKey ) throws -> SRPKey {
50+ public func calculateSharedSecret(
51+ username: String ,
52+ password: String ,
53+ salt: [ UInt8 ] ,
54+ clientKeys: SRPKeyPair ,
55+ serverPublicKey: SRPKey
56+ ) throws -> SRPKey {
5057 let message = [ UInt8] ( " \( username) : \( password) " . utf8)
51- let sharedSecret = try calculateSharedSecret ( message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey)
52- return SRPKey ( sharedSecret)
58+ return try calculateSharedSecret ( message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey)
5359 }
5460
55-
56- /// calculate proof of shared secret to send to server
61+ /// return shared secret given a binary password, B value and salt from the server
5762 /// - Parameters:
58- /// - clientPublicKey: client public key
63+ /// - password: password
64+ /// - salt: salt
65+ /// - clientKeys: client public/private keys
5966 /// - serverPublicKey: server public key
60- /// - sharedSecret: shared secret
61- /// - Returns: The client verification code which should be passed to the server
62- public func calculateSimpleClientProof( clientPublicKey: SRPKey , serverPublicKey: SRPKey , sharedSecret: SRPKey ) -> [ UInt8 ] {
63- // get verification code
64- return SRP< H> . calculateSimpleClientProof( clientPublicKey: clientPublicKey, serverPublicKey: serverPublicKey, sharedSecret: sharedSecret)
67+ /// - Throws: `nullServerKey`
68+ /// - Returns: shared secret
69+ public func calculateSharedSecret(
70+ password: [ UInt8 ] ,
71+ salt: [ UInt8 ] ,
72+ clientKeys: SRPKeyPair ,
73+ serverPublicKey: SRPKey
74+ ) throws -> SRPKey {
75+ let message = [ 0x3a ] + password
76+ return try calculateSharedSecret ( message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey)
6577 }
6678
67- /// If the server returns that the client verification code was valiid it will also return a server verification code that the client can use to verify the server is correct
68- ///
69- /// - Parameters:
70- /// - code: Verification code returned by server
71- /// - state: Authentication state
72- /// - Throws: `requiresVerificationKey`, `invalidServerCode`
73- public func verifySimpleServerProof( serverProof: [ UInt8 ] , clientProof: [ UInt8 ] , clientKeys: SRPKeyPair , sharedSecret: SRPKey ) throws {
74- // get out version of server proof
75- let HAMS = SRP< H> . calculateSimpleServerVerification( clientPublicKey: clientKeys. public, clientProof: clientProof, sharedSecret: sharedSecret)
76- // is it the same
77- guard serverProof == HAMS else { throw SRPClientError . invalidServerCode }
78- }
79-
8079 /// calculate proof of shared secret to send to server
8180 /// - Parameters:
82- /// - username: username
81+ /// - username: Username
8382 /// - salt: The salt value associated with the user returned by the server
84- /// - clientPublicKey: client public key
83+ /// - clientPublicKey: Client public key
8584 /// - serverPublicKey: server public key
8685 /// - sharedSecret: shared secret
8786 /// - Returns: The client verification code which should be passed to the server
88- public func calculateClientProof( username: String , salt: [ UInt8 ] , clientPublicKey: SRPKey , serverPublicKey: SRPKey , sharedSecret: SRPKey ) -> [ UInt8 ] {
89-
87+ public func calculateClientProof(
88+ username: String ,
89+ salt: [ UInt8 ] ,
90+ clientPublicKey: SRPKey ,
91+ serverPublicKey: SRPKey ,
92+ sharedSecret: SRPKey
93+ ) -> [ 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)
9097 let hashSharedSecret = [ UInt8] ( H . hash ( data: sharedSecret. bytes) )
91-
9298 // get verification code
93- return SRP< H> . calculateClientProof( configuration: configuration, username: username, salt: salt, clientPublicKey: clientPublicKey, serverPublicKey: serverPublicKey, hashSharedSecret: hashSharedSecret)
99+ return SRP< H> . calculateClientProof(
100+ configuration: configuration,
101+ username: username,
102+ salt: salt,
103+ clientPublicKey: clientPublicKey,
104+ serverPublicKey: serverPublicKey,
105+ hashSharedSecret: hashSharedSecret
106+ )
94107 }
95108
96109 /// If the server returns that the client verification code was valid it will also return a server
@@ -101,24 +114,39 @@ public struct SRPClient<H: HashFunction> {
101114 /// - clientPublicKey: Client public key
102115 /// - clientProof: Client proof
103116 /// - sharedSecret: Shared secret
104- public func calculateServerProof( clientPublicKey: SRPKey , clientProof: [ UInt8 ] , sharedSecret: SRPKey ) -> [ UInt8 ] {
117+ public func calculateServerProof(
118+ clientPublicKey: SRPKey ,
119+ clientProof: [ UInt8 ] ,
120+ sharedSecret: SRPKey
121+ ) -> [ UInt8 ] {
122+ let clientPublicKey = clientPublicKey. with ( padding: self . configuration. sizeN)
123+ let sharedSecret = sharedSecret. with ( padding: self . configuration. sizeN)
105124 let hashSharedSecret = [ UInt8] ( H . hash ( data: sharedSecret. bytes) )
106125 // get out version of server proof
107- return SRP< H> . calculateServerVerification( clientPublicKey: clientPublicKey, clientProof: clientProof, sharedSecret: hashSharedSecret)
126+ return SRP< H> . calculateServerVerification(
127+ clientPublicKey: clientPublicKey,
128+ clientProof: clientProof,
129+ hashSharedSecret: hashSharedSecret
130+ )
108131 }
109132
110133 /// If the server returns that the client verification code was valid it will also return a server
111134 /// verification code that the client can use to verify the server is correct
112135 ///
113136 /// - Parameters:
114- /// - clientProof : Server proof
137+ /// - serverProof : Server proof
115138 /// - clientProof: Client proof
116- /// - clientKeys : Client keys
139+ /// - clientPublicKey : Client public key
117140 /// - sharedSecret: Shared secret
118141 /// - Throws: `requiresVerificationKey`, `invalidServerCode`
119- public func verifyServerProof( serverProof: [ UInt8 ] , clientProof: [ UInt8 ] , clientKeys: SRPKeyPair , sharedSecret: SRPKey ) throws {
142+ public func verifyServerProof(
143+ serverProof: [ UInt8 ] ,
144+ clientProof: [ UInt8 ] ,
145+ clientPublicKey: SRPKey ,
146+ sharedSecret: SRPKey
147+ ) throws {
120148 // get our version of server proof
121- let HAMK = calculateServerProof ( clientPublicKey: clientKeys . public , clientProof: clientProof, sharedSecret: sharedSecret)
149+ let HAMK = calculateServerProof ( clientPublicKey: clientPublicKey , clientProof: clientProof, sharedSecret: sharedSecret)
122150 // is it the same
123151 guard serverProof == HAMK else { throw SRPClientError . invalidServerCode }
124152 }
@@ -134,17 +162,29 @@ public struct SRPClient<H: HashFunction> {
134162 public func generateSaltAndVerifier( username: String , password: String ) -> ( salt: [ UInt8 ] , verifier: SRPKey ) {
135163 let salt = [ UInt8 ] . random ( count: 16 )
136164 let verifier = generatePasswordVerifier ( username: username, password: password, salt: salt)
137- return ( salt: salt, verifier: SRPKey ( verifier) )
165+ return ( salt: salt, verifier: SRPKey ( verifier, padding: configuration. sizeN) )
166+ }
167+
168+ /// Hash data using same hash function that SRP uses
169+ /// - Parameter data: Data to be hashed
170+ /// - Returns: Hashed data
171+ @inlinable public func hash< D> ( data: D ) -> H . Digest where D : DataProtocol {
172+ H . hash ( data: data)
138173 }
139174}
140175
141176extension SRPClient {
142- /// return shared secret given the username, password, B value and salt from the server
143- func calculateSharedSecret( message: [ UInt8 ] , salt: [ UInt8 ] , clientKeys: SRPKeyPair , serverPublicKey: SRPKey ) throws -> BigNum {
177+ /// 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 ,
182+ serverPublicKey: SRPKey
183+ ) throws -> SRPKey {
144184 guard serverPublicKey. number % configuration. N != BigNum ( 0 ) else { throw SRPClientError . nullServerKey }
145185
146186 // calculate u = H(clientPublicKey | serverPublicKey)
147- let u = SRP< H> . calculateU( clientPublicKey: clientKeys. public. bytes, serverPublicKey: serverPublicKey. bytes, pad : configuration . sizeN )
187+ let u = SRP< H> . calculateU( clientPublicKey: clientKeys. public. bytes, serverPublicKey: serverPublicKey. bytes)
148188
149189 guard u != 0 else { throw SRPClientError . nullServerKey }
150190
@@ -153,7 +193,7 @@ extension SRPClient {
153193 // calculate S = (B - k*g^x)^(a+u*x)
154194 let S = ( serverPublicKey. number - configuration. k * configuration. g. power ( x, modulus: configuration. N) ) . power ( clientKeys. private. number + u * x, modulus: configuration. N)
155195
156- return S
196+ return . init ( S , padding : self . configuration . sizeN )
157197 }
158198
159199 /// generate password verifier
0 commit comments