Skip to content

Commit c4341f0

Browse files
committed
Update README, formatting
1 parent bd76e88 commit c4341f0

File tree

12 files changed

+270
-268
lines changed

12 files changed

+270
-268
lines changed

Package.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ let package = Package(
1515
.library(name: "SRP", targets: ["SRP"]),
1616
],
1717
dependencies: [
18-
.package(url: "https://github.com/apple/swift-crypto", "1.0.0"..<"5.0.0"),
18+
.package(url: "https://github.com/apple/swift-crypto", "1.0.0" ..< "5.0.0"),
1919
.package(url: "https://github.com/adam-fowler/big-num", from: "2.0.0"),
2020
],
2121
targets: [
2222
.target(name: "SRP", dependencies: ["BigNum", "Crypto"]),
2323
.testTarget(
24-
name: "SRPTests", dependencies: ["SRP"]),
24+
name: "SRPTests", dependencies: ["SRP"]
25+
),
2526
]
2627
)

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ let clientSharedSecret = try client.calculateSharedSecret(
4747
let clientProof = client.calculateClientProof(
4848
username: username,
4949
salt: salt,
50-
clientPublicKey: clientKeys.public,
50+
clientPublicKey: clientPublicKey,
5151
serverPublicKey: serverPublicKey,
5252
sharedSecret: clientSharedSecret
5353
)
@@ -64,7 +64,7 @@ let serverProof = try server.verifyClientProof(
6464
username: username,
6565
salt: salt,
6666
clientPublicKey: clientPublicKey,
67-
serverPublicKey: serverKeys.public,
67+
serverPublicKey: serverPublicKey,
6868
sharedSecret: serverSharedSecret
6969
)
7070
```
@@ -73,7 +73,7 @@ And finally the client can verify the server proof is valid
7373
try client.verifyServerProof(
7474
serverProof: serverProof,
7575
clientProof: clientProof,
76-
clientKeys: clientKeys,
76+
clientPublicKey: clientPublicKey,
7777
sharedSecret: clientSharedSecret
7878
)
7979
```
@@ -90,5 +90,3 @@ The library is compliant with RFC5054 and should work with any server implementi
9090
## Proof of secret
9191

9292
For generating the proof above I use the method detailed in [RFC2945](https://tools.ietf.org/html/rfc2945#section-3) but not all servers use this method. For this reason I have kept the sharedSecret generation separate from the proof generation, so you can insert your own version.
93-
94-
I have also supplied a simple proof functions `server.verifySimpleClientProof` and `client.verifySimpleServerProof` which use the proof detailed in the Wikipedia [page](https://en.wikipedia.org/wiki/Secure_Remote_Password_protocol) on Secure Remote Password if you would prefer to use these.

Sources/SRP/Array.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,27 @@ extension Array where Element: FixedWidthInteger {
33
/// create array of random bytes
44
static func random(count: Int) -> [Element] {
55
var array = self.init()
6-
for _ in 0..<count {
7-
array.append(.random(in: Element.min..<Element.max))
6+
for _ in 0 ..< count {
7+
array.append(.random(in: Element.min ..< Element.max))
88
}
99
return array
1010
}
1111

1212
/// generate a hexdigest of the array of bytes
1313
func hexdigest() -> String {
14-
return self.map({
14+
return map {
1515
let characters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]
16-
return "\(characters[Int($0 >> 4)])\(characters[Int($0 & 0xf)])"
17-
}).joined()
16+
return "\(characters[Int($0 >> 4)])\(characters[Int($0 & 0xF)])"
17+
}.joined()
1818
}
1919
}
2020

2121
extension Array where Element == UInt8 {
2222
func pad(to size: Int) -> [UInt8] {
23-
let padSize = size - self.count
23+
let padSize = size - count
2424
guard padSize > 0 else { return self }
2525
// create prefix and return prefix + data
26-
let prefix: [UInt8] = (1...padSize).reduce([]) { result,_ in return result + [0] }
26+
let prefix: [UInt8] = (1 ... padSize).reduce([]) { result, _ in result + [0] }
2727
return prefix + self
2828
}
2929
}
@@ -32,7 +32,7 @@ extension Array where Element == UInt8 {
3232
func ^ (lhs: [UInt8], rhs: [UInt8]) -> [UInt8] {
3333
precondition(lhs.count == rhs.count, "Arrays are required to be the same size")
3434
var result = lhs
35-
for i in 0..<lhs.count {
35+
for i in 0 ..< lhs.count {
3636
result[i] = result[i] ^ rhs[i]
3737
}
3838
return result

Sources/SRP/client.swift

Lines changed: 63 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ import Foundation
1818
public 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

Comments
 (0)