1
1
import BigNum
2
2
import Crypto
3
+ import Foundation
3
4
4
5
/// Manages the client side of Secure Remote Password
5
6
///
@@ -27,14 +28,14 @@ public struct SRPClient<H: HashFunction> {
27
28
/// Initiate the authentication process
28
29
/// - Returns: An authentication state. The A value from this state should be sent to the server
29
30
public func generateKeys( ) -> SRPKeyPair {
30
- var a = BigNum ( )
31
- var A = BigNum ( )
31
+ var a : BigNum
32
+ var A : BigNum
32
33
repeat {
33
34
a = BigNum ( bytes: SymmetricKey ( size: . bits256) )
34
35
A = configuration. g. power ( a, modulus: configuration. N)
35
36
} while A % configuration. N == BigNum ( 0 )
36
37
37
- return SRPKeyPair ( public: SRPKey ( A) , private: SRPKey ( a) )
38
+ return SRPKeyPair ( public: SRPKey ( A, padding : self . configuration . sizeN ) , private: SRPKey ( a) )
38
39
}
39
40
40
41
/// return shared secret given the username, password, B value and salt from the server
@@ -46,51 +47,63 @@ public struct SRPClient<H: HashFunction> {
46
47
/// - serverPublicKey: server public key
47
48
/// - Throws: `nullServerKey`
48
49
/// - 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 {
50
57
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)
53
59
}
54
60
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
57
62
/// - Parameters:
58
- /// - clientPublicKey: client public key
63
+ /// - password: password
64
+ /// - salt: salt
65
+ /// - clientKeys: client public/private keys
59
66
/// - 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)
65
77
}
66
78
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
-
80
79
/// calculate proof of shared secret to send to server
81
80
/// - Parameters:
82
- /// - username: username
81
+ /// - username: Username
83
82
/// - salt: The salt value associated with the user returned by the server
84
- /// - clientPublicKey: client public key
83
+ /// - clientPublicKey: Client public key
85
84
/// - serverPublicKey: server public key
86
85
/// - sharedSecret: shared secret
87
86
/// - 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)
90
97
let hashSharedSecret = [ UInt8] ( H . hash ( data: sharedSecret. bytes) )
91
-
92
98
// 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
+ )
94
107
}
95
108
96
109
/// 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> {
101
114
/// - clientPublicKey: Client public key
102
115
/// - clientProof: Client proof
103
116
/// - 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)
105
124
let hashSharedSecret = [ UInt8] ( H . hash ( data: sharedSecret. bytes) )
106
125
// 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
+ )
108
131
}
109
132
110
133
/// If the server returns that the client verification code was valid it will also return a server
111
134
/// verification code that the client can use to verify the server is correct
112
135
///
113
136
/// - Parameters:
114
- /// - clientProof : Server proof
137
+ /// - serverProof : Server proof
115
138
/// - clientProof: Client proof
116
- /// - clientKeys : Client keys
139
+ /// - clientPublicKey : Client public key
117
140
/// - sharedSecret: Shared secret
118
141
/// - 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 {
120
148
// 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)
122
150
// is it the same
123
151
guard serverProof == HAMK else { throw SRPClientError . invalidServerCode }
124
152
}
@@ -134,17 +162,29 @@ public struct SRPClient<H: HashFunction> {
134
162
public func generateSaltAndVerifier( username: String , password: String ) -> ( salt: [ UInt8 ] , verifier: SRPKey ) {
135
163
let salt = [ UInt8 ] . random ( count: 16 )
136
164
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)
138
173
}
139
174
}
140
175
141
176
extension 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 {
144
184
guard serverPublicKey. number % configuration. N != BigNum ( 0 ) else { throw SRPClientError . nullServerKey }
145
185
146
186
// 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)
148
188
149
189
guard u != 0 else { throw SRPClientError . nullServerKey }
150
190
@@ -153,7 +193,7 @@ extension SRPClient {
153
193
// calculate S = (B - k*g^x)^(a+u*x)
154
194
let S = ( serverPublicKey. number - configuration. k * configuration. g. power ( x, modulus: configuration. N) ) . power ( clientKeys. private. number + u * x, modulus: configuration. N)
155
195
156
- return S
196
+ return . init ( S , padding : self . configuration . sizeN )
157
197
}
158
198
159
199
/// generate password verifier
0 commit comments