diff --git a/Sources/SRP/client.swift b/Sources/SRP/client.swift index 62a2561..8e27a5e 100644 --- a/Sources/SRP/client.swift +++ b/Sources/SRP/client.swift @@ -1,5 +1,6 @@ import BigNum import Crypto +import Foundation /// Manages the client side of Secure Remote Password /// @@ -27,14 +28,14 @@ public struct SRPClient { /// Initiate the authentication process /// - Returns: An authentication state. The A value from this state should be sent to the server public func generateKeys() -> SRPKeyPair { - var a = BigNum() - var A = BigNum() + var a: BigNum + var A: BigNum repeat { a = BigNum(bytes: SymmetricKey(size: .bits256)) - A = configuration.g.power(a, modulus: configuration.N) + A = configuration.g.number.power(a, modulus: configuration.N) } while A % configuration.N == BigNum(0) - return SRPKeyPair(public: SRPKey(A), private: SRPKey(a)) + return SRPKeyPair(public: SRPKey(A, padding: self.configuration.sizeN), private: SRPKey(a)) } /// return shared secret given the username, password, B value and salt from the server @@ -46,10 +47,15 @@ public struct SRPClient { /// - serverPublicKey: server public key /// - Throws: `nullServerKey` /// - Returns: shared secret - public func calculateSharedSecret(username: String, password: String, salt: [UInt8], clientKeys: SRPKeyPair, serverPublicKey: SRPKey) throws -> SRPKey { + public func calculateSharedSecret( + username: String, + password: String, + salt: [UInt8], + clientKeys: SRPKeyPair, + serverPublicKey: SRPKey + ) throws -> SRPKey { let message = [UInt8]("\(username):\(password)".utf8) - let sharedSecret = try calculateSharedSecret(message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey) - return SRPKey(sharedSecret) + return try calculateSharedSecret(message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey) } /// return shared secret given a binary password, B value and salt from the server @@ -60,50 +66,44 @@ public struct SRPClient { /// - serverPublicKey: server public key /// - Throws: `nullServerKey` /// - Returns: shared secret - public func calculateSharedSecret(password: [UInt8], salt: [UInt8], clientKeys: SRPKeyPair, serverPublicKey: SRPKey) throws -> SRPKey { + public func calculateSharedSecret( + password: [UInt8], + salt: [UInt8], + clientKeys: SRPKeyPair, + serverPublicKey: SRPKey + ) throws -> SRPKey { let message = [0x3a] + password - let sharedSecret = try calculateSharedSecret(message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey) - return SRPKey(sharedSecret) + return try calculateSharedSecret(message: message, salt: salt, clientKeys: clientKeys, serverPublicKey: serverPublicKey) } /// calculate proof of shared secret to send to server /// - Parameters: - /// - clientPublicKey: client public key - /// - serverPublicKey: server public key - /// - sharedSecret: shared secret - /// - Returns: The client verification code which should be passed to the server - public func calculateSimpleClientProof(clientPublicKey: SRPKey, serverPublicKey: SRPKey, sharedSecret: SRPKey) -> [UInt8] { - // get verification code - return SRP.calculateSimpleClientProof(clientPublicKey: clientPublicKey, serverPublicKey: serverPublicKey, sharedSecret: sharedSecret, padding: configuration.sizeN) - } - - /// 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 - /// - /// - Parameters: - /// - code: Verification code returned by server - /// - state: Authentication state - /// - Throws: `requiresVerificationKey`, `invalidServerCode` - public func verifySimpleServerProof(serverProof: [UInt8], clientProof: [UInt8], clientKeys: SRPKeyPair, sharedSecret: SRPKey) throws { - // get out version of server proof - let HAMS = SRP.calculateSimpleServerVerification(clientPublicKey: clientKeys.public, clientProof: clientProof, sharedSecret: sharedSecret, padding: configuration.sizeN) - // is it the same - guard serverProof == HAMS else { throw SRPClientError.invalidServerCode } - } - - /// calculate proof of shared secret to send to server - /// - Parameters: - /// - username: username + /// - username: Username /// - salt: The salt value associated with the user returned by the server - /// - clientPublicKey: client public key + /// - clientPublicKey: Client public key /// - serverPublicKey: server public key /// - sharedSecret: shared secret /// - Returns: The client verification code which should be passed to the server - public func calculateClientProof(username: String, salt: [UInt8], clientPublicKey: SRPKey, serverPublicKey: SRPKey, sharedSecret: SRPKey) -> [UInt8] { - - let hashSharedSecret = [UInt8](H.hash(data: sharedSecret.bytes(padding: configuration.sizeN))) - + public func calculateClientProof( + username: String, + salt: [UInt8], + clientPublicKey: SRPKey, + serverPublicKey: SRPKey, + sharedSecret: SRPKey + ) -> [UInt8] { + let clientPublicKey = clientPublicKey.with(padding: self.configuration.sizeN) + let serverPublicKey = serverPublicKey.with(padding: self.configuration.sizeN) + let sharedSecret = sharedSecret.with(padding: self.configuration.sizeN) + let hashSharedSecret = [UInt8](H.hash(data: sharedSecret.bytes)) // get verification code - return SRP.calculateClientProof(configuration: configuration, username: username, salt: salt, clientPublicKey: clientPublicKey, serverPublicKey: serverPublicKey, hashSharedSecret: hashSharedSecret, padding: configuration.sizeN) + return SRP.calculateClientProof( + configuration: configuration, + username: username, + salt: salt, + clientPublicKey: clientPublicKey, + serverPublicKey: serverPublicKey, + hashSharedSecret: hashSharedSecret + ) } /// If the server returns that the client verification code was valid it will also return a server @@ -114,24 +114,39 @@ public struct SRPClient { /// - clientPublicKey: Client public key /// - clientProof: Client proof /// - sharedSecret: Shared secret - public func calculateServerProof(clientPublicKey: SRPKey, clientProof: [UInt8], sharedSecret: SRPKey) -> [UInt8] { - let hashSharedSecret = [UInt8](H.hash(data: sharedSecret.bytes(padding: configuration.sizeN))) + public func calculateServerProof( + clientPublicKey: SRPKey, + clientProof: [UInt8], + sharedSecret: SRPKey + ) -> [UInt8] { + let clientPublicKey = clientPublicKey.with(padding: self.configuration.sizeN) + let sharedSecret = sharedSecret.with(padding: self.configuration.sizeN) + let hashSharedSecret = [UInt8](H.hash(data: sharedSecret.bytes)) // get out version of server proof - return SRP.calculateServerVerification(clientPublicKey: clientPublicKey, clientProof: clientProof, hashSharedSecret: hashSharedSecret, padding: configuration.sizeN) + return SRP.calculateServerVerification( + clientPublicKey: clientPublicKey, + clientProof: clientProof, + hashSharedSecret: hashSharedSecret + ) } /// If the server returns that the client verification code was valid it will also return a server /// verification code that the client can use to verify the server is correct /// /// - Parameters: - /// - clientProof: Server proof + /// - serverProof: Server proof /// - clientProof: Client proof - /// - clientKeys: Client keys + /// - clientPublicKey: Client public key /// - sharedSecret: Shared secret /// - Throws: `requiresVerificationKey`, `invalidServerCode` - public func verifyServerProof(serverProof: [UInt8], clientProof: [UInt8], clientKeys: SRPKeyPair, sharedSecret: SRPKey) throws { + public func verifyServerProof( + serverProof: [UInt8], + clientProof: [UInt8], + clientPublicKey: SRPKey, + sharedSecret: SRPKey + ) throws { // get our version of server proof - let HAMK = calculateServerProof(clientPublicKey: clientKeys.public, clientProof: clientProof, sharedSecret: sharedSecret) + let HAMK = calculateServerProof(clientPublicKey: clientPublicKey, clientProof: clientProof, sharedSecret: sharedSecret) // is it the same guard serverProof == HAMK else { throw SRPClientError.invalidServerCode } } @@ -147,26 +162,38 @@ public struct SRPClient { public func generateSaltAndVerifier(username: String, password: String) -> (salt: [UInt8], verifier: SRPKey) { let salt = [UInt8].random(count: 16) let verifier = generatePasswordVerifier(username: username, password: password, salt: salt) - return (salt: salt, verifier: SRPKey(verifier)) + return (salt: salt, verifier: SRPKey(verifier, padding: configuration.sizeN)) + } + + /// Hash data using same hash function that SRP uses + /// - Parameter data: Data to be hashed + /// - Returns: Hashed data + @inlinable public func hash(data: D) -> H.Digest where D : DataProtocol { + H.hash(data: data) } } extension SRPClient { /// return shared secret given the message (username:password), salt from server, client keys, and B value - func calculateSharedSecret(message: [UInt8], salt: [UInt8], clientKeys: SRPKeyPair, serverPublicKey: SRPKey) throws -> BigNum { + func calculateSharedSecret( + message: [UInt8], + salt: [UInt8], + clientKeys: SRPKeyPair, + serverPublicKey: SRPKey + ) throws -> SRPKey { guard serverPublicKey.number % configuration.N != BigNum(0) else { throw SRPClientError.nullServerKey } // calculate u = H(clientPublicKey | serverPublicKey) - let u = SRP.calculateU(clientPublicKey: clientKeys.public.bytes(padding: configuration.sizeN), serverPublicKey: serverPublicKey.bytes(padding: configuration.sizeN)) + let u = SRP.calculateU(clientPublicKey: clientKeys.public.bytes, serverPublicKey: serverPublicKey.bytes) guard u != 0 else { throw SRPClientError.nullServerKey } let x = BigNum(bytes: [UInt8](H.hash(data: salt + H.hash(data: message)))) // calculate S = (B - k*g^x)^(a+u*x) - let S = (serverPublicKey.number - configuration.k * configuration.g.power(x, modulus: configuration.N)).power(clientKeys.private.number + u * x, modulus: configuration.N) + let S = (serverPublicKey.number - configuration.k * configuration.g.number.power(x, modulus: configuration.N)).power(clientKeys.private.number + u * x, modulus: configuration.N) - return S + return .init(S, padding: self.configuration.sizeN) } /// generate password verifier @@ -178,7 +205,7 @@ extension SRPClient { /// generate password verifier public func generatePasswordVerifier(message: [UInt8], salt: [UInt8]) -> BigNum { let x = BigNum(bytes: [UInt8](H.hash(data: salt + H.hash(data: message)))) - let verifier = configuration.g.power(x, modulus: configuration.N) + let verifier = configuration.g.number.power(x, modulus: configuration.N) return verifier } } diff --git a/Sources/SRP/configuration.swift b/Sources/SRP/configuration.swift index 0d51b84..7905b44 100644 --- a/Sources/SRP/configuration.swift +++ b/Sources/SRP/configuration.swift @@ -6,7 +6,7 @@ public struct SRPConfiguration { /// large safe prime public let N: BigNum /// multiplicative group generator - public let g: BigNum + public let g: SRPKey /// derived value from N and g. k = H( N | g ) public let k: BigNum /// size in bytes of N @@ -17,8 +17,8 @@ public struct SRPConfiguration { public init(_ prime: Prime) { self.N = prime.group self.sizeN = Int(self.N.numBits() + 7) / 8 - self.g = prime.generator - self.k = BigNum(bytes: [UInt8](H.hash(data: self.N.bytes + self.g.bytes.pad(to: sizeN)))) + self.g = SRPKey(prime.generator, padding: self.sizeN) + self.k = BigNum(bytes: [UInt8](H.hash(data: self.N.bytes + self.g.bytes))) } /// Initialise SRPConfiguration with your own prime and multiplicative group generator @@ -28,7 +28,7 @@ public struct SRPConfiguration { public init(N: BigNum, g: BigNum) { self.N = N self.sizeN = Int(self.N.numBits() + 7) / 8 - self.g = g + self.g = SRPKey(g, padding: self.sizeN) self.k = BigNum(bytes: [UInt8](H.hash(data: self.N.bytes + self.g.bytes.pad(to: sizeN)))) } diff --git a/Sources/SRP/keys.swift b/Sources/SRP/keys.swift index 6089c1d..e1bbe67 100644 --- a/Sources/SRP/keys.swift +++ b/Sources/SRP/keys.swift @@ -1,32 +1,46 @@ import BigNum +import Crypto +import Foundation /// Wrapper for keys used by SRP public struct SRPKey { /// SRPKey internal storage public let number: BigNum + /// padding + public let padding: Int /// Representation as a byte array - public var bytes: [UInt8] { number.bytes } + public var bytes: [UInt8] { number.bytes.pad(to: self.padding) } /// Representation as a hex string - public var hex: String { number.hex } - /// Representation as a byte array with padding - public func bytes(padding: Int) -> [UInt8] { number.bytes.pad(to: padding) } - /// Representation as a hex string with padding - public func hex(padding: Int) -> String { number.bytes.pad(to: padding).hexdigest() } + public var hex: String { number.bytes.pad(to: self.padding).hexdigest() } /// Initialize with an array of bytes - public init(_ bytes: [UInt8]) { + @inlinable public init(_ bytes: C, padding: Int? = nil) { self.number = BigNum(bytes: bytes) + self.padding = padding ?? bytes.count } - /// Initialize with a BigNum - public init(_ number: BigNum) { - self.number = number + /// Initialize with a crypto digest + @inlinable public init(_ digest: D, padding: Int? = nil) { + self.number = BigNum(bytes: digest) + self.padding = padding ?? D.byteCount } /// Initialize with a hex string - public init?(hex: String) { + @inlinable public init?(hex: String, padding: Int = 0) { guard let number = BigNum(hex: hex) else { return nil } self.number = number + self.padding = padding + } + + /// Initialize with a BigNum + @usableFromInline init(_ number: BigNum, padding: Int = 0) { + self.number = number + self.padding = padding + } + + /// Return SRPKey with padding + func with(padding: Int) -> SRPKey { + .init(self.number, padding: padding) } } @@ -37,12 +51,11 @@ public struct SRPKeyPair { public let `public`: SRPKey public let `private`: SRPKey - /// Initialise a SRPKeyPair object /// - Parameters: /// - public: The public key of the key pair /// - private: The private key of the key pair - public init(`public`: SRPKey, `private`: SRPKey) { + init(`public`: SRPKey, `private`: SRPKey) { self.private = `private` self.public = `public` } diff --git a/Sources/SRP/server.swift b/Sources/SRP/server.swift index 3b1528b..a803460 100644 --- a/Sources/SRP/server.swift +++ b/Sources/SRP/server.swift @@ -1,5 +1,6 @@ import BigNum import Crypto +import Foundation /// Manages the server side of Secure Remote Password. /// @@ -15,13 +16,6 @@ import Crypto /// - https://tools.ietf.org/html/rfc5054 /// public struct SRPServer { - /// Authentication state. Stores A,B and shared secret - public struct AuthenticationState { - let clientPublicKey: SRPKey - let serverPublicKey: SRPKey - var serverPrivateKey: SRPKey - } - /// configuration has to be the same as the client configuration public let configuration: SRPConfiguration @@ -39,63 +33,58 @@ public struct SRPServer { var B: BigNum repeat { b = BigNum(bytes: SymmetricKey(size: .bits256)) - B = (configuration.k * verifier.number + configuration.g.power(b, modulus: configuration.N)) % configuration.N + B = (configuration.k * verifier.number + configuration.g.number.power(b, modulus: configuration.N)) % configuration.N } while B % configuration.N == BigNum(0) - return SRPKeyPair(public: SRPKey(B), private: SRPKey(b)) + return SRPKeyPair(public: SRPKey(B, padding: self.configuration.sizeN), private: SRPKey(b)) } /// calculate the shared secret /// - Parameters: - /// - clientPublicKey: public key received from client - /// - serverKeys: server key pair - /// - verifier: password verifier + /// - clientPublicKey: Public key received from client + /// - serverKeys: Server key pair + /// - verifier: Password verifier /// - Returns: shared secret - public func calculateSharedSecret(clientPublicKey: SRPKey, serverKeys: SRPKeyPair, verifier: SRPKey) throws -> SRPKey { + public func calculateSharedSecret( + clientPublicKey: SRPKey, + serverKeys: SRPKeyPair, + verifier: SRPKey + ) throws -> SRPKey { + let clientPublicKey = clientPublicKey.with(padding: self.configuration.sizeN) guard clientPublicKey.number % configuration.N != BigNum(0) else { throw SRPServerError.nullClientKey } // calculate u = H(clientPublicKey | serverPublicKey) - let u = SRP.calculateU(clientPublicKey: clientPublicKey.bytes(padding: configuration.sizeN), serverPublicKey: serverKeys.public.bytes(padding: configuration.sizeN)) + let u = SRP.calculateU(clientPublicKey: clientPublicKey.bytes, serverPublicKey: serverKeys.public.bytes) // calculate S let S = ((clientPublicKey.number * verifier.number.power(u, modulus: configuration.N)).power(serverKeys.private.number, modulus: configuration.N)) - return SRPKey(S) - } - - /// verify proof that client has shared secret and return a server verification proof. If verification fails a `invalidClientCode` error is thrown - /// - /// - Parameters: - /// - proof: Client proof - /// - clientPublicKey: Client public key - /// - serverPublicKey: Server public key - /// - sharedSecret: Shared secret - /// - Throws: invalidClientCode - /// - Returns: The server verification code - public func verifySimpleClientProof(proof: [UInt8], clientPublicKey: SRPKey, serverPublicKey: SRPKey, sharedSecret: SRPKey) throws -> [UInt8] { - let clientProof = SRP.calculateSimpleClientProof( - clientPublicKey: clientPublicKey, - serverPublicKey: serverPublicKey, - sharedSecret: sharedSecret, - padding: configuration.sizeN - ) - guard clientProof == proof else { throw SRPServerError.invalidClientProof } - return SRP.calculateSimpleServerVerification(clientPublicKey: clientPublicKey, clientProof: clientProof, sharedSecret: sharedSecret, padding: configuration.sizeN) + return SRPKey(S, padding: self.configuration.sizeN) } /// verify proof that client has shared secret and return a server verification proof. If verification fails a `invalidClientCode` error is thrown /// /// - Parameters: /// - code: verification code sent by user - /// - username: username - /// - salt: salt stored with user + /// - username: Username + /// - salt: Salt stored with user /// - clientPublicKey: Client public key /// - serverPublicKey: Server public key /// - sharedSecret: Shared secret /// - Throws: invalidClientCode /// - Returns: The server verification code - public func verifyClientProof(proof: [UInt8], username: String, salt: [UInt8], clientPublicKey: SRPKey, serverPublicKey: SRPKey, sharedSecret: SRPKey) throws -> [UInt8] { - let hashSharedSecret = [UInt8](H.hash(data: sharedSecret.bytes(padding: configuration.sizeN))) + public func verifyClientProof( + proof: [UInt8], + username: String, + salt: [UInt8], + clientPublicKey: SRPKey, + serverPublicKey: SRPKey, + sharedSecret: SRPKey + ) throws -> [UInt8] { + let clientPublicKey = clientPublicKey.with(padding: self.configuration.sizeN) + let serverPublicKey = serverPublicKey.with(padding: self.configuration.sizeN) + let sharedSecret = sharedSecret.with(padding: self.configuration.sizeN) + let hashSharedSecret = [UInt8](H.hash(data: sharedSecret.bytes)) let clientProof = SRP.calculateClientProof( configuration: configuration, @@ -103,10 +92,16 @@ public struct SRPServer { salt: salt, clientPublicKey: clientPublicKey, serverPublicKey: serverPublicKey, - hashSharedSecret: hashSharedSecret, - padding: configuration.sizeN + hashSharedSecret: hashSharedSecret ) guard clientProof == proof else { throw SRPServerError.invalidClientProof } - return SRP.calculateServerVerification(clientPublicKey: clientPublicKey, clientProof: clientProof, hashSharedSecret: hashSharedSecret, padding: configuration.sizeN) + return SRP.calculateServerVerification(clientPublicKey: clientPublicKey, clientProof: clientProof, hashSharedSecret: hashSharedSecret) + } + + /// Hash data using same hash function that SRP uses + /// - Parameter data: Data to be hashed + /// - Returns: Hashed data + @inlinable public func hash(data: D) -> H.Digest where D : DataProtocol { + H.hash(data: data) } } diff --git a/Sources/SRP/srp.swift b/Sources/SRP/srp.swift index 87ee302..104eb64 100644 --- a/Sources/SRP/srp.swift +++ b/Sources/SRP/srp.swift @@ -9,28 +9,6 @@ public struct SRP { BigNum(bytes: [UInt8].init(H.hash(data: clientPublicKey + serverPublicKey))) } - /// Calculate a simpler client verification code H(A | B | S) - static func calculateSimpleClientProof( - clientPublicKey: SRPKey, - serverPublicKey: SRPKey, - sharedSecret: SRPKey, - padding: Int - ) -> [UInt8] { - let HABK = H.hash(data: clientPublicKey.bytes(padding: padding) + serverPublicKey.bytes(padding: padding) + sharedSecret.bytes(padding: padding)) - return [UInt8](HABK) - } - - /// Calculate a simpler client verification code H(A | M1 | S) - static func calculateSimpleServerVerification( - clientPublicKey: SRPKey, - clientProof: [UInt8], - sharedSecret: SRPKey, - padding: Int - ) -> [UInt8] { - let HABK = H.hash(data: clientPublicKey.bytes(padding: padding) + clientProof.pad(to: padding) + sharedSecret.bytes(padding: padding)) - return [UInt8](HABK) - } - /// Calculate client verification code H(H(N)^ H(g)) | H(username) | salt | A | B | H(S)) static func calculateClientProof( configuration: SRPConfiguration, @@ -38,21 +16,20 @@ public struct SRP { salt: [UInt8], clientPublicKey: SRPKey, serverPublicKey: SRPKey, - hashSharedSecret: [UInt8], - padding: Int + hashSharedSecret: [UInt8] ) -> [UInt8] { // M = H(H(N)^ H(g)) | H(username) | salt | client key | server key | H(shared secret)) - let N_xor_g = [UInt8](H.hash(data: configuration.N.bytes.pad(to: padding))) ^ [UInt8](H.hash(data: configuration.g.bytes.pad(to: padding))) + let N_xor_g = [UInt8](H.hash(data: configuration.N.bytes)) ^ [UInt8](H.hash(data: configuration.g.bytes)) let hashUser = H.hash(data: [UInt8](username.utf8)) let M1 = [UInt8](N_xor_g) + hashUser + salt - let M2 = clientPublicKey.bytes(padding: padding) + serverPublicKey.bytes(padding: padding) + hashSharedSecret + let M2 = clientPublicKey.bytes + serverPublicKey.bytes + hashSharedSecret let M = H.hash(data: M1 + M2) return [UInt8](M) } /// Calculate server verification code H(A | M1 | K) - static func calculateServerVerification(clientPublicKey: SRPKey, clientProof: [UInt8], hashSharedSecret: [UInt8], padding: Int) -> [UInt8] { - let HAMK = H.hash(data: clientPublicKey.bytes(padding: padding) + clientProof + hashSharedSecret) + static func calculateServerVerification(clientPublicKey: SRPKey, clientProof: [UInt8], hashSharedSecret: [UInt8]) -> [UInt8] { + let HAMK = H.hash(data: clientPublicKey.bytes + clientProof + hashSharedSecret) return [UInt8](HAMK) } } diff --git a/Tests/SRPTests/SRPTests.swift b/Tests/SRPTests/SRPTests.swift index 3029b44..a3be282 100644 --- a/Tests/SRPTests/SRPTests.swift +++ b/Tests/SRPTests/SRPTests.swift @@ -59,7 +59,7 @@ final class SRPTests: XCTestCase { let serverSharedSecret = try server.calculateSharedSecret(clientPublicKey: clientKeys.public, serverKeys: serverKeys, verifier: verifier) let serverProof = try server.verifyClientProof(proof: clientProof, username: username, salt: salt, clientPublicKey: clientKeys.public, serverPublicKey: serverKeys.public, sharedSecret: serverSharedSecret) // client verifies server validation key - try client.verifyServerProof(serverProof: serverProof, clientProof: clientProof, clientKeys: clientKeys, sharedSecret: clientSharedSecret) + try client.verifyServerProof(serverProof: serverProof, clientProof: clientProof, clientPublicKey: clientKeys.public, sharedSecret: clientSharedSecret) } catch { XCTFail("\(error)") } @@ -87,7 +87,14 @@ final class SRPTests: XCTestCase { let A = BigNum(hex: "b525e8fe2eac8f5da6b3220e66a0ab6f833a59d5f079fe9ddcdf111a22eaec95850374d9d7597f45497eb429bcde5057a450948de7d48edc034264916a01e6c0690e14b0a527f107d3207fd2214653c9162f5745e7cbeb19a550a072d4600ce8f4ef778f6d6899ba718adf0a462e7d981ed689de93ea1bda773333f23ebb4a9b")! let B = BigNum(hex: "2bfc8559a022497f1254af3c76786b95cb0dfb449af15501aa51eefe78947d7ef06df4fcc07a899bcaae0e552ca72c7a1f3016f3ec357a86a1428dad9f98cb8a69d405404e57e9aaf01e51a46a73b3fc7bc1d212569e4a882ae6d878599e098c89033838ec069fe368a49461f531e5b4662700d56d8c252d0aea9da6abe9b014")! let secret = "b6288955afd690a13686d65886b5f82018515df3".bytes(using: .hexadecimal)! - let clientProof = SRP.calculateClientProof(configuration: configuration, username: username, salt: salt, clientPublicKey: SRPKey(A), serverPublicKey: SRPKey(B), hashSharedSecret: secret, padding: configuration.sizeN) + let clientProof = SRP.calculateClientProof( + configuration: configuration, + username: username, + salt: salt, + clientPublicKey: SRPKey(A, padding: configuration.sizeN), + serverPublicKey: SRPKey(B, padding: configuration.sizeN), + hashSharedSecret: secret + ) XCTAssertEqual(clientProof.hexdigest(), "2dbc18fd8bbb6574fd318e96fbc92c4c8dc8a5e8") } @@ -98,7 +105,11 @@ final class SRPTests: XCTestCase { let secret = "d89740e18a9fb597aef8f2ecc0e66f4b31c2ae08".bytes(using: .hexadecimal)! let clientProof = "e1a8629a723039a61be91a173ab6260fc582192f".bytes(using: .hexadecimal)! - let serverProof = SRP.calculateServerVerification(clientPublicKey: SRPKey(A), clientProof: clientProof, hashSharedSecret: secret, padding: 0) + let serverProof = SRP.calculateServerVerification( + clientPublicKey: SRPKey(A), + clientProof: clientProof, + hashSharedSecret: secret + ) XCTAssertEqual(serverProof.hexdigest(), "8342bd06bdf4d263de2df9a56da8e581fb38c769") } @@ -119,13 +130,13 @@ final class SRPTests: XCTestCase { let a = BigNum(hex: "60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393")! // copied from client.swift - let A = configuration.g.power(a, modulus: configuration.N) + let A = configuration.g.number.power(a, modulus: configuration.N) XCTAssertEqual(A.hex, "61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC44352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEAB349EF5D76988A3672FAC47B0769447B".lowercased()) let b = BigNum(hex: "E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20")! // copied from server.swift - let B = (configuration.k * verifier + configuration.g.power(b, modulus: configuration.N)) % configuration.N + let B = (configuration.k * verifier + configuration.g.number.power(b, modulus: configuration.N)) % configuration.N XCTAssertEqual(B.hex, "BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58".lowercased()) @@ -133,7 +144,13 @@ final class SRPTests: XCTestCase { XCTAssertEqual(u.hex, "CE38B9593487DA98554ED47D70A7AE5F462EF019".lowercased()) - let sharedSecret = try client.calculateSharedSecret(username: username, password: password, salt: salt, clientKeys: SRPKeyPair(public: SRPKey(A), private: SRPKey(a)), serverPublicKey: SRPKey(B)) + let sharedSecret = try client.calculateSharedSecret( + username: username, + password: password, + salt: salt, + clientKeys: SRPKeyPair(public: SRPKey(A, padding: configuration.sizeN), private: SRPKey(a)), + serverPublicKey: SRPKey(B, padding: configuration.sizeN) + ) XCTAssertEqual(sharedSecret.number.hex, "B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212DC346D7E474B29EDE8A469FFECA686E5A".lowercased()) } @@ -155,27 +172,32 @@ final class SRPTests: XCTestCase { let b = BigNum(hex: "00f3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f")! // copied from server.swift - let B = (configuration.k * verifier + configuration.g.power(b, modulus: configuration.N)) % configuration.N + let B = (configuration.k * verifier + configuration.g.number.power(b, modulus: configuration.N)) % configuration.N - XCTAssertEqual(SRPKey(B).hex(padding: configuration.sizeN), "0022ce5a7b9d81277172caa20b0f1efb4643b3becc53566473959b07b790d3c3f08650d5531c19ad30ebb67bdb481d1d9cf61bf272f8439848fdda58a4e6abc5abb2ac496da5098d5cbf90e29b4b110e4e2c033c70af73925fa37457ee13ea3e8fde4ab516dff1c2ae8e57a6b264fb9db637eeeae9b5e43dfaba9b329d3b8770ce89888709e026270e474eef822436e6397562f284778673a1a7bc12b6883d1c21fbc27ffb3dbeb85efda279a69a19414969113f10451603065f0a012666645651dde44a52f4d8de113e2131321df1bf4369d2585364f9e536c39a4dce33221be57d50ddccb4384e3612bbfd03a268a36e4f7e01de651401e108cc247db50392") + XCTAssertEqual(SRPKey(B, padding: configuration.sizeN).hex, "0022ce5a7b9d81277172caa20b0f1efb4643b3becc53566473959b07b790d3c3f08650d5531c19ad30ebb67bdb481d1d9cf61bf272f8439848fdda58a4e6abc5abb2ac496da5098d5cbf90e29b4b110e4e2c033c70af73925fa37457ee13ea3e8fde4ab516dff1c2ae8e57a6b264fb9db637eeeae9b5e43dfaba9b329d3b8770ce89888709e026270e474eef822436e6397562f284778673a1a7bc12b6883d1c21fbc27ffb3dbeb85efda279a69a19414969113f10451603065f0a012666645651dde44a52f4d8de113e2131321df1bf4369d2585364f9e536c39a4dce33221be57d50ddccb4384e3612bbfd03a268a36e4f7e01de651401e108cc247db50392") let a = BigNum(hex: "00f2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3d7")! // copied from client.swift - let A = configuration.g.power(a, modulus: configuration.N) + let A = configuration.g.number.power(a, modulus: configuration.N) - XCTAssertEqual(SRPKey(A).hex(padding: configuration.sizeN), "007da76cb7e77af5ab61f334dbd5a958513afcdf0f47ab99271fc5f7860fe2132e5802ca79d2e5c064bb80a38ee08771c98a937696698d878d78571568c98a1c40cc6e7cb101988a2f9ba3d65679027d4d9068cb8aad6ebff0101bab6d52b5fdfa81d2ed48bba119d4ecdb7f3f478bd236d5749f2275e9484f2d0a9259d05e49d78a23dd26c60bfba04fd346e5146469a8c3f010a627be81c58ded1caaef2363635a45f97ca0d895cc92ace1d09a99d6beb6b0dc0829535c857a419e834db12864cd6ee8a843563b0240520ff0195735cd9d316842d5d3f8ef7209a0bb4b54ad7374d73e79be2c3975632de562c596470bb27bad79c3e2fcddf194e1666cb9fc") + XCTAssertEqual(SRPKey(A, padding: configuration.sizeN).hex, "007da76cb7e77af5ab61f334dbd5a958513afcdf0f47ab99271fc5f7860fe2132e5802ca79d2e5c064bb80a38ee08771c98a937696698d878d78571568c98a1c40cc6e7cb101988a2f9ba3d65679027d4d9068cb8aad6ebff0101bab6d52b5fdfa81d2ed48bba119d4ecdb7f3f478bd236d5749f2275e9484f2d0a9259d05e49d78a23dd26c60bfba04fd346e5146469a8c3f010a627be81c58ded1caaef2363635a45f97ca0d895cc92ace1d09a99d6beb6b0dc0829535c857a419e834db12864cd6ee8a843563b0240520ff0195735cd9d316842d5d3f8ef7209a0bb4b54ad7374d73e79be2c3975632de562c596470bb27bad79c3e2fcddf194e1666cb9fc") let u = SRP.calculateU(clientPublicKey: A.bytes.pad(to: configuration.sizeN), serverPublicKey: B.bytes.pad(to: configuration.sizeN)) XCTAssertEqual(u.hex, "b284aa1064e8775150da6b5e2147b47ca7df505bed94a6f4bb2ad873332ad732") - let sharedSecret = try client.calculateSharedSecret(message: message, salt: salt, clientKeys: SRPKeyPair(public: SRPKey(A), private: SRPKey(a)), serverPublicKey: SRPKey(B)) + let sharedSecret = try client.calculateSharedSecret( + message: message, + salt: salt, + clientKeys: SRPKeyPair(public: SRPKey(A, padding: configuration.sizeN), private: SRPKey(a)), + serverPublicKey: SRPKey(B, padding: configuration.sizeN) + ) - XCTAssertEqual(sharedSecret.hex, "92aaf0f527906aa5e8601f5d707907a03137e1b601e04b5a1deb02a981f4be037b39829a27dba50f1b27545ff2e28729c2b79dcbdd32c9d6b20d340affab91a626a8075806c26fe39df91d0ad979f9b2ee8aad1bc783e7097407b63bfe58d9118b9b0b2a7c5c4cdebaf8e9a460f4bf6247b0da34b760a59fac891757ddedcaf08eed823b090586c63009b2d740cc9f5397be89a2c32cdcfe6d6251ce11e44e6ecbdd9b6d93f30e90896d2527564c7eb9ff70aa91acc0bac1740a11cd184ffb989554ab58117c2196b353d70c356160100ef5f4c28d19f6e59ea2508e8e8aac6001497c27f362edbafb25e0f045bfdf9fb02db9c908f10340a639fe84c31b27") + XCTAssertEqual(sharedSecret.hex, "0092aaf0f527906aa5e8601f5d707907a03137e1b601e04b5a1deb02a981f4be037b39829a27dba50f1b27545ff2e28729c2b79dcbdd32c9d6b20d340affab91a626a8075806c26fe39df91d0ad979f9b2ee8aad1bc783e7097407b63bfe58d9118b9b0b2a7c5c4cdebaf8e9a460f4bf6247b0da34b760a59fac891757ddedcaf08eed823b090586c63009b2d740cc9f5397be89a2c32cdcfe6d6251ce11e44e6ecbdd9b6d93f30e90896d2527564c7eb9ff70aa91acc0bac1740a11cd184ffb989554ab58117c2196b353d70c356160100ef5f4c28d19f6e59ea2508e8e8aac6001497c27f362edbafb25e0f045bfdf9fb02db9c908f10340a639fe84c31b27") - let clientProof = client.calculateSimpleClientProof(clientPublicKey: SRPKey(A), serverPublicKey: SRPKey(B), sharedSecret: SRPKey(sharedSecret)) + let clientProof = SHA256.hash(data: SRPKey(A, padding: configuration.sizeN).bytes + SRPKey(B, padding: configuration.sizeN).bytes + sharedSecret.bytes) - XCTAssertEqual(clientProof.hexdigest(), "27949ec1e0f1625633436865edb037e23eb6bf5cb91873f2a2729373c2039008") + XCTAssertEqual([UInt8](clientProof).hexdigest(), "27949ec1e0f1625633436865edb037e23eb6bf5cb91873f2a2729373c2039008") } static var allTests = [