@@ -15,9 +15,10 @@ public class Client {
1515 public func srpLogin( accountName: String , password: String ) -> AnyPublisher < AuthenticationState , Swift . Error > {
1616 var serviceKey : String !
1717
18- let client = SRPClient < SHA256 > ( username: accountName, password: password)
19- let a = client. startAuthentication ( )
20-
18+ let client = SRPClient ( configuration: SRPConfiguration < SHA256 > ( . N2048) )
19+ let clientKeys = client. generateKeys ( )
20+ let a = clientKeys. public
21+
2122 return Current . network. dataTask ( with: URLRequest . itcServiceKey)
2223 . map ( \. data)
2324 . decode ( type: ServiceKeyResponse . self, decoder: JSONDecoder ( ) )
@@ -33,15 +34,13 @@ public class Client {
3334 }
3435 . flatMap { ( serviceKey, hashcash) -> AnyPublisher < ( String , String , ServerSRPInitResponse ) , Swift . Error > in
3536
36- return Current . network. dataTask ( with: URLRequest . SRPInit ( serviceKey: serviceKey, a: a . base64EncodedString ( ) , accountName: accountName) )
37+ return Current . network. dataTask ( with: URLRequest . SRPInit ( serviceKey: serviceKey, a: Data ( a . bytes ) . base64EncodedString ( ) , accountName: accountName) )
3738 . map ( \. data)
3839 . decode ( type: ServerSRPInitResponse . self, decoder: JSONDecoder ( ) )
3940 . map { return ( serviceKey, hashcash, $0) }
4041 . eraseToAnyPublisher ( )
4142 }
4243 . flatMap { ( serviceKey, hashcash, srpInit) -> AnyPublisher < URLSession . DataTaskPublisher . Output , Swift . Error > in
43- print ( " SRP INIT REsponse: \( srpInit) " )
44-
4544 guard let decodedB = Data ( base64Encoded: srpInit. b) else {
4645 return Fail ( error: AuthenticationError . srpInvalidPublicKey)
4746 . eraseToAnyPublisher ( )
@@ -55,29 +54,20 @@ public class Client {
5554 let iterations = srpInit. iteration
5655
5756 do {
58-
5957 guard let encryptedPassword = self . pbkdf2 ( password: password, saltData: decodedSalt, keyByteCount: 32 , prf: CCPseudoRandomAlgorithm ( kCCPRFHmacAlgSHA256) , rounds: iterations) else {
6058 return Fail ( error: AuthenticationError . srpInvalidPublicKey)
6159 . eraseToAnyPublisher ( )
6260 }
6361
64- // let m1 = try client.processChallenge(salt: decodedSalt, publicKey: decodedB, isEncryptedPassword: true, encryptedPassword: encryptedPassword.hexEncodedString())
65- let encryptedPasswordString = String ( data: encryptedPassword, encoding: . utf8)
66- let m1 = try client. processChallenge ( salt: decodedSalt, publicKey: decodedB, isEncryptedPassword: true , encryptedPassword: encryptedPasswordString)
67-
68- guard let m2 = client. HAMK else {
69- return Fail ( error: AuthenticationError . srpInvalidPublicKey)
70- . eraseToAnyPublisher ( )
71- }
62+ let sharedSecret = try client. calculateSharedSecret ( password: encryptedPassword, salt: [ UInt8] ( decodedSalt) , clientKeys: clientKeys, serverPublicKey: . init( [ UInt8] ( decodedB) ) )
7263
73- print ( " m1: \( m1 . base64EncodedString ( ) ) " )
74- print ( " m2: \( m2 . base64EncodedString ( ) ) " )
75-
76- return Current . network. dataTask ( with: URLRequest . SRPComplete ( serviceKey: serviceKey, hashcash: hashcash, accountName: accountName, c: srpInit. c, m1: m1 . base64EncodedString ( ) , m2: m2 . base64EncodedString ( ) ) )
64+ let m1 = client . calculateClientProof ( username : accountName , salt : [ UInt8 ] ( decodedSalt ) , clientPublicKey : a , serverPublicKey : . init ( [ UInt8 ] ( decodedB ) ) , sharedSecret : . init ( sharedSecret . bytes ) )
65+ let m2 = client . calculateServerProof ( clientPublicKey : a , clientProof : m1 , sharedSecret : . init ( [ UInt8 ] ( sharedSecret . bytes ) ) )
66+
67+ return Current . network. dataTask ( with: URLRequest . SRPComplete ( serviceKey: serviceKey, hashcash: hashcash, accountName: accountName, c: srpInit. c, m1: Data ( m1 ) . base64EncodedString ( ) , m2: Data ( m2 ) . base64EncodedString ( ) ) )
7768 . mapError { $0 as Swift . Error }
7869 . eraseToAnyPublisher ( )
7970 } catch {
80- print ( " Error: calculateSharedSecret \( error) " )
8171 return Fail ( error: AuthenticationError . srpInvalidPublicKey)
8272 . eraseToAnyPublisher ( )
8373 }
@@ -115,79 +105,6 @@ public class Client {
115105 }
116106 . eraseToAnyPublisher ( )
117107 }
118- // .map(\.data)
119- // .decode(type: ServerSRPInitResponse.self, decoder: JSONDecoder())
120- //
121- //
122- //
123- // .flatMap { result -> AnyPublisher<AuthenticationState, Swift.Error> in
124- // return ("")
125- // }
126- // .flatMap { serverResponse -> AnyPublisher<AuthenticationState, Error> in
127- // print(serverResponse)
128- // return Fail(error: AuthenticationError.accountUsesTwoStepAuthentication)
129- // .eraseToAnyPublisher()
130- // }
131- . mapError { $0 as Swift . Error }
132- . eraseToAnyPublisher ( )
133- }
134-
135-
136- public func login( accountName: String , password: String ) -> AnyPublisher < AuthenticationState , Swift . Error > {
137- var serviceKey : String !
138-
139- return Current . network. dataTask ( with: URLRequest . itcServiceKey)
140- . map ( \. data)
141- . decode ( type: ServiceKeyResponse . self, decoder: JSONDecoder ( ) )
142- . flatMap { serviceKeyResponse -> AnyPublisher < ( String , String ) , Swift . Error > in
143- serviceKey = serviceKeyResponse. authServiceKey
144-
145- // Fixes issue https://github.com/RobotsAndPencils/XcodesApp/issues/360
146- // On 2023-02-23, Apple added a custom implementation of hashcash to their auth flow
147- // Without this addition, Apple ID's would get set to locked
148- return self . loadHashcash ( accountName: accountName, serviceKey: serviceKey)
149- . map { return ( serviceKey, $0) }
150- . eraseToAnyPublisher ( )
151- }
152- . flatMap { ( serviceKey, hashcash) -> AnyPublisher < URLSession . DataTaskPublisher . Output , Swift . Error > in
153-
154- return Current . network. dataTask ( with: URLRequest . signIn ( serviceKey: serviceKey, accountName: accountName, password: password, hashcash: hashcash) )
155- . mapError { $0 as Swift . Error }
156- . eraseToAnyPublisher ( )
157- }
158- . flatMap { result -> AnyPublisher < AuthenticationState , Swift . Error > in
159- let ( data, response) = result
160- return Just ( data)
161- . decode ( type: SignInResponse . self, decoder: JSONDecoder ( ) )
162- . flatMap { responseBody -> AnyPublisher < AuthenticationState , Swift . Error > in
163- let httpResponse = response as! HTTPURLResponse
164-
165- switch httpResponse. statusCode {
166- case 200 :
167- return Current . network. dataTask ( with: URLRequest . olympusSession)
168- . map { _ in AuthenticationState . authenticated }
169- . mapError { $0 as Swift . Error }
170- . eraseToAnyPublisher ( )
171- case 401 :
172- return Fail ( error: AuthenticationError . invalidUsernameOrPassword ( username: accountName) )
173- . eraseToAnyPublisher ( )
174- case 403 :
175- let errorMessage = responseBody. serviceErrors? . first? . description. replacingOccurrences ( of: " -20209: " , with: " " ) ?? " "
176- return Fail ( error: AuthenticationError . accountLocked ( errorMessage) )
177- . eraseToAnyPublisher ( )
178- case 409 :
179- return self . handleTwoStepOrFactor ( data: data, response: response, serviceKey: serviceKey)
180- case 412 where Client . authTypes. contains ( responseBody. authType ?? " " ) :
181- return Fail ( error: AuthenticationError . appleIDAndPrivacyAcknowledgementRequired)
182- . eraseToAnyPublisher ( )
183- default :
184- return Fail ( error: AuthenticationError . unexpectedSignInResponse ( statusCode: httpResponse. statusCode,
185- message: responseBody. serviceErrors? . map { $0. description } . joined ( separator: " , " ) ) )
186- . eraseToAnyPublisher ( )
187- }
188- }
189- . eraseToAnyPublisher ( )
190- }
191108 . mapError { $0 as Swift . Error }
192109 . eraseToAnyPublisher ( )
193110 }
@@ -382,27 +299,39 @@ public class Client {
382299 . mapError { $0 as Error }
383300 . eraseToAnyPublisher ( )
384301 }
385-
302+
303+ func sha256( data : Data ) -> Data {
304+ var hash = [ UInt8] ( repeating: 0 , count: Int ( CC_SHA256_DIGEST_LENGTH) )
305+ data. withUnsafeBytes {
306+ _ = CC_SHA256 ( $0. baseAddress, CC_LONG ( data. count) , & hash)
307+ }
308+ return Data ( hash)
309+ }
310+
386311 private func pbkdf2( password: String , saltData: Data , keyByteCount: Int , prf: CCPseudoRandomAlgorithm , rounds: Int ) -> Data ? {
387312 guard let passwordData = password. data ( using: . utf8) else { return nil }
388-
313+ let hashedPasswordData = sha256 ( data: passwordData)
314+
389315 var derivedKeyData = Data ( repeating: 0 , count: keyByteCount)
390316 let derivedCount = derivedKeyData. count
391317 let derivationStatus : Int32 = derivedKeyData. withUnsafeMutableBytes { derivedKeyBytes in
392318 let keyBuffer : UnsafeMutablePointer < UInt8 > =
393319 derivedKeyBytes. baseAddress!. assumingMemoryBound ( to: UInt8 . self)
394320 return saltData. withUnsafeBytes { saltBytes -> Int32 in
395321 let saltBuffer : UnsafePointer < UInt8 > = saltBytes. baseAddress!. assumingMemoryBound ( to: UInt8 . self)
396- return CCKeyDerivationPBKDF (
397- CCPBKDFAlgorithm ( kCCPBKDF2) ,
398- password,
399- passwordData. count,
400- saltBuffer,
401- saltData. count,
402- prf,
403- UInt32 ( rounds) ,
404- keyBuffer,
405- derivedCount)
322+ return hashedPasswordData. withUnsafeBytes { hashedPasswordBytes -> Int32 in
323+ let passwordBuffer : UnsafePointer < UInt8 > = hashedPasswordBytes. baseAddress!. assumingMemoryBound ( to: UInt8 . self)
324+ return CCKeyDerivationPBKDF (
325+ CCPBKDFAlgorithm ( kCCPBKDF2) ,
326+ passwordBuffer,
327+ hashedPasswordData. count,
328+ saltBuffer,
329+ saltData. count,
330+ prf,
331+ UInt32 ( rounds) ,
332+ keyBuffer,
333+ derivedCount)
334+ }
406335 }
407336 }
408337 return derivationStatus == kCCSuccess ? derivedKeyData : nil
0 commit comments